Skip to content

Commit e59bc3b

Browse files
committed
feat: add sublist search algorithm
1 parent d54afc5 commit e59bc3b

File tree

1 file changed

+275
-0
lines changed

1 file changed

+275
-0
lines changed

search/sublist_search.cpp

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
/**
2+
* @file
3+
* @brief Implementation of the [Sublist Search Algorithm](https://www.geeksforgeeks.org/sublist-search-search-a-linked-list-in-another-list) algorithm.
4+
* @details
5+
* * Sublist search is used to detect a presence of one list in another list.
6+
* * Suppose we have a single-node list (let's say the first list), and we want to ensure that the list is present
7+
* in another list (let's say the second list), then we can perform the sublist search to find it.
8+
*
9+
* * For instance, the first list contains these elements: 23 -> 30 -> 41, and the second list contains these
10+
* elements: 10 -> 15 -> 23 -> 30 -> 41 -> 49. At a glance, we see that the first list presents in the second list.
11+
*
12+
* ### Working
13+
* * The sublist search algorithm works by comparing the first element of the first list with the
14+
* first element of the second list.
15+
* * If the two values don't match, it goes to the next element of the second list. It does this until the two values match.
16+
*
17+
* @author [Nitin Sharma](https://github.com/foo290)
18+
*/
19+
20+
#include <iostream> // for IO operations
21+
#include <vector> // For passing data as array
22+
#include <cassert> // For assert
23+
24+
/**
25+
* A Node structure representing single link Node in a linked list.
26+
*/
27+
struct Node {
28+
int data;
29+
Node *next;
30+
};
31+
32+
/**
33+
* @brief Main searching function
34+
* @param sublist A linked list which is supposed to be searched in mainList.
35+
* @param mainList A linked list in which sublist will be searched.
36+
* @returns bool If the sublist is found, returns true, else false.
37+
*/
38+
bool sublistSearch(Node *sublist, Node *mainList) {
39+
if (sublist == nullptr || mainList == nullptr) {
40+
return false;
41+
}
42+
43+
Node *target_ptr = sublist;
44+
45+
while (mainList != nullptr) {
46+
Node *main_ptr = mainList; // Initialize main pointer to the current node of main list.
47+
48+
while (target_ptr != nullptr) {
49+
if (main_ptr == nullptr) {
50+
return false;
51+
52+
} else if (main_ptr->data == target_ptr->data) {
53+
// If the data of target node and main node is equal then move to the next node of both lists.
54+
target_ptr = target_ptr->next;
55+
main_ptr = main_ptr->next;
56+
57+
} else {
58+
break;
59+
}
60+
}
61+
62+
if (target_ptr == nullptr) {
63+
// Is target pointer becomes null that means the target list is been traversed without returning false.
64+
// Which means the sublist has been found and return ture.
65+
return true;
66+
}
67+
68+
target_ptr = sublist; // set the target pointer again to stating point of target list.
69+
mainList = mainList->next; // set the main pointer to the next element of the main list and repeat the algo.
70+
}
71+
72+
// If the main list is exhausted, means sublist does not found, return false
73+
return false;
74+
}
75+
76+
/**
77+
* @brief A simple function to print the linked list.
78+
* @param start The head of the linked list
79+
* @returns void
80+
*/
81+
void printLinkedList(Node *start) {
82+
while (start != nullptr) {
83+
std::cout << "->" << start->data;
84+
start = start->next;
85+
}
86+
std::cout << std::endl;
87+
}
88+
89+
/**
90+
* @brief Makes a dummy linked list for testing.
91+
* @param data A vector of "int" containing the data that is supposed to be stored in nodes of linked list.
92+
* @returns Node* A head pointer to the linked list.
93+
*/
94+
Node *makeLinkedList(const std::vector<int> &data) {
95+
Node *head = nullptr;
96+
Node *tail = nullptr;
97+
for (int i : data) {
98+
Node *node = new Node;
99+
node->data = i;
100+
node->next = nullptr;
101+
if (head == nullptr) {
102+
head = node;
103+
tail = node;
104+
}
105+
else {
106+
tail->next = node;
107+
tail = tail->next;
108+
}
109+
}
110+
return head;
111+
}
112+
113+
/**
114+
* A class, encapsulating the necessary test cases.
115+
*/
116+
class TestCases {
117+
private:
118+
template<typename T>
119+
void log(T msg) {
120+
// It's just to avoid writing cout and endl
121+
std::cout << "[TESTS] : ---> " << msg << std::endl;
122+
}
123+
124+
public:
125+
void runTests() {
126+
log("Running Tests...");
127+
128+
testCase_1();
129+
testCase_2();
130+
testCase_3();
131+
132+
log("Test Cases over!");
133+
std::cout << std::endl;
134+
}
135+
136+
void testCase_1() {
137+
const bool expectedOutput = true;
138+
139+
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
140+
log("This is test case 1 for sublist search Algorithm : ");
141+
log("Description:");
142+
log(" EDGE CASE : Only contains one element");
143+
144+
std::vector<int> sublistData = {6};
145+
std::vector<int> mainlistData = {2, 5, 6, 7, 8};
146+
147+
Node *sublistLL = makeLinkedList(sublistData);
148+
Node *mainlistLL = makeLinkedList(mainlistData);
149+
150+
bool exists = sublistSearch(sublistLL, mainlistLL);
151+
152+
log("Checking assert expression...");
153+
assert(exists == expectedOutput);
154+
log("Assertion check passed!");
155+
156+
log("[PASS] : TEST CASE 1 PASS!");
157+
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
158+
159+
delete(sublistLL);
160+
delete(mainlistLL);
161+
162+
}
163+
164+
void testCase_2() {
165+
const bool expectedOutput = true;
166+
167+
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
168+
log("This is test case 2 for sublist search Algorithm : ");
169+
log("Description:");
170+
log(" contains main list of 100 elements and sublist of 20");
171+
172+
std::vector<int> sublistData(20);
173+
std::vector<int> mainlistData(100);
174+
175+
for (int i = 0; i < 100; i++) {
176+
// Inserts 100 elements in main list
177+
mainlistData[i] = i + 1;
178+
}
179+
180+
int temp = 0;
181+
for (int i = 45; i < 65; i++) {
182+
// Inserts 20 elements in sublist
183+
sublistData[temp] = i + 1;
184+
temp++;
185+
}
186+
187+
Node *sublistLL = makeLinkedList(sublistData);
188+
Node *mainlistLL = makeLinkedList(mainlistData);
189+
190+
bool exists = sublistSearch(sublistLL, mainlistLL);
191+
192+
log("Checking assert expression...");
193+
assert(exists == expectedOutput);
194+
log("Assertion check passed!");
195+
196+
log("[PASS] : TEST CASE 2 PASS!");
197+
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
198+
}
199+
200+
void testCase_3() {
201+
const bool expectedOutput = false;
202+
203+
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
204+
log("This is test case 3 for sublist search Algorithm : ");
205+
log("Description:");
206+
log(" contains main list of 50 elements and sublist of 20");
207+
208+
std::vector<int> sublistData(20);
209+
std::vector<int> mainlistData(50);
210+
211+
212+
for (int i = 0; i < 50; i++) {
213+
// Inserts 100 elements in main list
214+
mainlistData.push_back(i + 1);
215+
}
216+
217+
for (int i = 45; i < 65; i++) {
218+
// Inserts 20 elements in sublist
219+
sublistData.push_back(i + 1);
220+
}
221+
222+
Node *sublistLL = makeLinkedList(sublistData);
223+
Node *mainlistLL = makeLinkedList(mainlistData);
224+
225+
bool exists = sublistSearch(sublistLL, mainlistLL);
226+
227+
log("Checking assert expression...");
228+
assert(exists == expectedOutput);
229+
log("Assertion check passed!");
230+
231+
log("[PASS] : TEST CASE 3 PASS!");
232+
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
233+
}
234+
};
235+
236+
/**
237+
* @brief A test function that runs various checks
238+
* @returns void
239+
*/
240+
void test() {
241+
TestCases tc;
242+
tc.runTests();
243+
}
244+
245+
/**
246+
* @brief Main function
247+
* @param argc commandline argument count (ignored)
248+
* @param argv commandline array of arguments (ignored)
249+
* @returns 0 on exit
250+
*/
251+
int main(int argc, char *argv[]) {
252+
test(); // Executing various test cases first.
253+
254+
std::vector<int> mainlistData = {2, 5, 6, 7, 8};
255+
std::vector<int> sublistData = {6, 8};
256+
Node *mainlistLL = makeLinkedList(mainlistData);
257+
Node *sublistLL = makeLinkedList(sublistData);
258+
259+
bool exists = sublistSearch(sublistLL, mainlistLL);
260+
261+
std::cout << "Sublist :" << std::endl;
262+
printLinkedList(sublistLL);
263+
264+
std::cout << "Main list : " << std::endl;
265+
printLinkedList(mainlistLL);
266+
std::cout << std::endl;
267+
268+
if (exists){
269+
std::cout << "[TRUE] - sublist found in main list";
270+
}
271+
else{
272+
std::cout << "[FALSE] - sublist NOT found in main list";
273+
}
274+
return 0;
275+
}

0 commit comments

Comments
 (0)