1 | #include <stdio.h> // for NULL definition |
---|
2 | #include "llistd.h" // function prototypes |
---|
3 | |
---|
4 | /***************************************************************************** |
---|
5 | * AUTHOR: Scott Scriven, SSN: 523-21-9640, CLASS: CS151.003, DATE: 96-11-21 |
---|
6 | ****************************************************************************** |
---|
7 | * Doubly Linked Lists! (some of my really old code, commented for this class) |
---|
8 | * This code will handle "generic" Doubly-Linked Lists. These lists can be |
---|
9 | * any type as long as they satisfy a few requirements: |
---|
10 | * Your structure must start with two integer pointers: |
---|
11 | * struct mystruct { |
---|
12 | * int *next, *prev; |
---|
13 | * ... |
---|
14 | * }; |
---|
15 | * That's all, pretty much. |
---|
16 | * |
---|
17 | * Most of the functions take integer pointers. This means you will have to |
---|
18 | * call them in one of the following ways: |
---|
19 | * function((int *)&mystruct); |
---|
20 | * function((int *)mystruct); |
---|
21 | * function(&mystruct.next); |
---|
22 | * |
---|
23 | ****************************************************************************** |
---|
24 | * If I'm not mistaken, this code should work regardless of your machine's |
---|
25 | * integer size (16/32/64/etc... bit) |
---|
26 | ****************************************************************************** |
---|
27 | * Note that we have to do NULL checking to make sure we don't try to write |
---|
28 | * to protected areas of memory if we reach the beginning/end of a list. |
---|
29 | * |
---|
30 | * We also do some circular-link checking to avoid infinite loops. |
---|
31 | * These loops will work fine: |
---|
32 | * a <-> b <-> c <-> a <-> b... |
---|
33 | * a <-> b <-> c -> c -> c... |
---|
34 | * This loop might make this code puke: |
---|
35 | * a <-> b <-> c <-> d -> c d <- e <-> f <-> g |
---|
36 | *****************************************************************************/ |
---|
37 | |
---|
38 | |
---|
39 | /***************************************************************************** |
---|
40 | * Function: LLMakeFirstNode() |
---|
41 | ****************************************************************************** |
---|
42 | * Description: |
---|
43 | * Makes a node stand alone; creates the first node of a list. You must do |
---|
44 | * the memory/node allocation manually. It returns the parameter you send it. |
---|
45 | ****************************************************************************** |
---|
46 | * Function Calls: |
---|
47 | * None. |
---|
48 | *****************************************************************************/ |
---|
49 | int * LLMakeFirstNode(int * first) // Make a standalone node... |
---|
50 | { |
---|
51 | (int *)first[0] = NULL; |
---|
52 | (int *)first[1] = NULL; |
---|
53 | return first; |
---|
54 | } |
---|
55 | |
---|
56 | |
---|
57 | /***************************************************************************** |
---|
58 | * Function: LLFindFirst() |
---|
59 | ****************************************************************************** |
---|
60 | * Description: |
---|
61 | * Given a node of a list, it returns the first node of the list (assuming |
---|
62 | * that the first node either points to NULL or itself). If list is circular, |
---|
63 | * it returns *next* node in the list. |
---|
64 | ****************************************************************************** |
---|
65 | * Function Calls: |
---|
66 | * LLFindPrev See below... |
---|
67 | *****************************************************************************/ |
---|
68 | int * LLFindFirst(int * current) // returns address of First node |
---|
69 | { |
---|
70 | int *prev=current; |
---|
71 | |
---|
72 | // If prev[1] (pointer to previous node) is NULL, we hit the beginning. |
---|
73 | // If prev[1] is the same as current, we've got a circular linked list... |
---|
74 | while((int *)prev[1] != NULL && (int *)prev[1] != current) |
---|
75 | { |
---|
76 | prev = LLFindPrev(prev); |
---|
77 | } |
---|
78 | |
---|
79 | return prev; |
---|
80 | } |
---|
81 | |
---|
82 | /***************************************************************************** |
---|
83 | * Function: LLFindNext() |
---|
84 | ****************************************************************************** |
---|
85 | * Description: |
---|
86 | * Returns the address of the next node in the list, or NULL if we're at the |
---|
87 | * end of the list. |
---|
88 | ****************************************************************************** |
---|
89 | * Function Calls: |
---|
90 | * None. |
---|
91 | *****************************************************************************/ |
---|
92 | int * LLFindNext(int * current) // returns address of next node |
---|
93 | { |
---|
94 | // Return the address of the next node |
---|
95 | if((int *)current[0] != current) |
---|
96 | return (int *)current[0]; |
---|
97 | else |
---|
98 | return NULL; |
---|
99 | } |
---|
100 | |
---|
101 | /***************************************************************************** |
---|
102 | * Function: LLFindPrev() |
---|
103 | ****************************************************************************** |
---|
104 | * Description: |
---|
105 | * Returns the address of the previous node in the list, or NULL if we're |
---|
106 | * at the beginning of the list. |
---|
107 | ****************************************************************************** |
---|
108 | * Function Calls: |
---|
109 | * None. |
---|
110 | *****************************************************************************/ |
---|
111 | int * LLFindPrev(int * current) // returns address of prev node |
---|
112 | { |
---|
113 | // Return the address of the previous node |
---|
114 | if((int *)current[1] != current) |
---|
115 | return (int *)current[1]; |
---|
116 | else |
---|
117 | return NULL; |
---|
118 | } |
---|
119 | |
---|
120 | /***************************************************************************** |
---|
121 | * Function: LLFindLast() |
---|
122 | ****************************************************************************** |
---|
123 | * Description: |
---|
124 | * Given any node, returns the address of the last node of that list. This |
---|
125 | * works just like LLFindFirst(), but in reverse. |
---|
126 | ****************************************************************************** |
---|
127 | * Function Calls: |
---|
128 | * LLFindNext See above... |
---|
129 | *****************************************************************************/ |
---|
130 | int * LLFindLast(int * current) // returns address of last node |
---|
131 | { |
---|
132 | int *next = current; |
---|
133 | |
---|
134 | // If next[0] (pointer to next node) is NULL, we hit the end. |
---|
135 | // If next[0] is the same as current, we've got a circular linked list... |
---|
136 | while((int *)next[0] != NULL && (int *)next[0] != current) |
---|
137 | { |
---|
138 | next = LLFindNext(next); |
---|
139 | } |
---|
140 | |
---|
141 | return next; |
---|
142 | } |
---|
143 | |
---|
144 | |
---|
145 | /***************************************************************************** |
---|
146 | * Function: LLAddNode() |
---|
147 | ****************************************************************************** |
---|
148 | * Description: |
---|
149 | * Inserts a node in the list *after* the "current" node. It updates the |
---|
150 | * list neighbors accordingly. |
---|
151 | ****************************************************************************** |
---|
152 | * Function Calls: |
---|
153 | * LLFindNext See above... |
---|
154 | *****************************************************************************/ |
---|
155 | int * LLAddNode(int * current, int * add) // Adds node AFTER current one |
---|
156 | { |
---|
157 | int *next; |
---|
158 | |
---|
159 | if(current == add) return current; // We can't add a node to itself... |
---|
160 | |
---|
161 | next = LLFindNext(current); // Get the next node address |
---|
162 | |
---|
163 | (int *)current[0] = add; // Point the current node to the new node |
---|
164 | (int *)add[0] = next; // Point the new node to next node |
---|
165 | (int *)add[1] = current; // Make new node point back to the current node |
---|
166 | |
---|
167 | if(next != NULL) |
---|
168 | (int *)next[1] = add; // Point next node back to the new node |
---|
169 | |
---|
170 | return add; // Return the address of the new node |
---|
171 | } |
---|
172 | |
---|
173 | /***************************************************************************** |
---|
174 | * Function: LLInsertNode() |
---|
175 | ****************************************************************************** |
---|
176 | * Description: |
---|
177 | * Inserts a node in the list *before* the "current" node. It updates the |
---|
178 | * list neighbors accordingly. |
---|
179 | ****************************************************************************** |
---|
180 | * Function Calls: |
---|
181 | * LLFindPrev See above... |
---|
182 | *****************************************************************************/ |
---|
183 | int * LLInsertNode(int * current, int * add) // Adds node BEFORE current one |
---|
184 | { |
---|
185 | int *prev; |
---|
186 | |
---|
187 | if(current == add) return current; // We can't add a node to itself... |
---|
188 | |
---|
189 | prev = LLFindPrev(current); // Get the previous node's address |
---|
190 | |
---|
191 | if(prev != NULL) |
---|
192 | (int *)prev[0] = add; // Previous node points to new node |
---|
193 | (int *)add[0] = current; // New node points to current node |
---|
194 | (int *)add[1] = prev; // New node points back to previous node |
---|
195 | (int *)current[1] = add; // Current node points back to new node |
---|
196 | |
---|
197 | return add; // Return the address of the new node |
---|
198 | } |
---|
199 | |
---|
200 | /***************************************************************************** |
---|
201 | * Function: LLCutNode() |
---|
202 | ****************************************************************************** |
---|
203 | * Description: |
---|
204 | * Removes a node from the list, and joins its neighbors. Returns the |
---|
205 | * address of the cut node. You must deallocate the node manually, if |
---|
206 | * you want to free its memory. |
---|
207 | ****************************************************************************** |
---|
208 | * Function Calls: |
---|
209 | * LLFindPrev See Above... |
---|
210 | * LLFindNext See Above... |
---|
211 | *****************************************************************************/ |
---|
212 | int * LLCutNode(int * cut) // Removes a node from the link |
---|
213 | { |
---|
214 | int * prev, * next; |
---|
215 | |
---|
216 | prev = LLFindPrev(cut); // Find surrounding nodes... |
---|
217 | next = LLFindNext(cut); |
---|
218 | |
---|
219 | (int *)cut[0] = NULL; // Make the removed node point nowhere |
---|
220 | (int *)cut[1] = NULL; |
---|
221 | |
---|
222 | if(prev != NULL) // Join the surrounding nodes... |
---|
223 | (int *)prev[0] = next; |
---|
224 | if(next != NULL) |
---|
225 | (int *)next[1] = prev; |
---|
226 | |
---|
227 | return cut; // Return the address of the node that has been cut... |
---|
228 | } |
---|
229 | |
---|
230 | |
---|
231 | /***************************************************************************** |
---|
232 | * Function: LLPush() |
---|
233 | ****************************************************************************** |
---|
234 | * Description: |
---|
235 | * Inserts a node at the end of the whole list. "Current" can be any node |
---|
236 | * in the list, and "add" is the node you want to add. |
---|
237 | ****************************************************************************** |
---|
238 | * Function Calls: |
---|
239 | * LLFindLast() See above... |
---|
240 | * LLAddNode() See above... |
---|
241 | *****************************************************************************/ |
---|
242 | int * LLPush(int * current, int * add) // Add node to end of list |
---|
243 | { |
---|
244 | int *last; |
---|
245 | |
---|
246 | last = LLFindLast(current); |
---|
247 | |
---|
248 | return LLAddNode(last, add); |
---|
249 | } |
---|
250 | |
---|
251 | /***************************************************************************** |
---|
252 | * Function: LLPop() |
---|
253 | ****************************************************************************** |
---|
254 | * Description: |
---|
255 | * Pops (removes) a node off the end of the list. Returns the address of |
---|
256 | * the node we chopped off. "current" can be any node in the list. |
---|
257 | ****************************************************************************** |
---|
258 | * Function Calls: |
---|
259 | * LLFindLast See above... |
---|
260 | * LLCutNode See above... |
---|
261 | *****************************************************************************/ |
---|
262 | int * LLPop(int * current) // Remove node from end of list |
---|
263 | { |
---|
264 | int *last; |
---|
265 | |
---|
266 | last = LLFindLast(current); |
---|
267 | |
---|
268 | return LLCutNode(last); |
---|
269 | } |
---|
270 | |
---|
271 | /***************************************************************************** |
---|
272 | * Function: LLShift() |
---|
273 | ****************************************************************************** |
---|
274 | * Description: |
---|
275 | * Pops (removes) a node from the beginning of the list. Returns the address |
---|
276 | * of the node we cut off. |
---|
277 | ****************************************************************************** |
---|
278 | * Function Calls: |
---|
279 | * LLFindFirst See above... |
---|
280 | * LLCutNode See above... |
---|
281 | *****************************************************************************/ |
---|
282 | int * LLShift(int * current) // Remove node from start of list |
---|
283 | { |
---|
284 | int *begin; |
---|
285 | |
---|
286 | begin = LLFindFirst(current); |
---|
287 | |
---|
288 | return LLCutNode(begin); |
---|
289 | } |
---|
290 | |
---|
291 | /***************************************************************************** |
---|
292 | * Function: LLUnshift() |
---|
293 | ****************************************************************************** |
---|
294 | * Description: |
---|
295 | * Inserts a node at the beginning of the list. |
---|
296 | ****************************************************************************** |
---|
297 | * Function Calls: |
---|
298 | * LLFindFirst See above... |
---|
299 | * LLInsertNode See above... |
---|
300 | *****************************************************************************/ |
---|
301 | int * LLUnshift(int * current, int * add) // Add node to beginning of list |
---|
302 | { |
---|
303 | int *begin; |
---|
304 | |
---|
305 | begin = LLFindFirst(current); |
---|
306 | |
---|
307 | return LLInsertNode(begin, add); |
---|
308 | } |
---|
309 | |
---|
310 | /***************************************************************************** |
---|
311 | * Function: LLSwapNodes() |
---|
312 | ****************************************************************************** |
---|
313 | * Description: |
---|
314 | * Switches two nodes' positions in the linked list. It can handle cases |
---|
315 | * when the nodes are complete seperate, cases when the nodes are each |
---|
316 | * other's neighbors, and cases when the two nodes are the same one. |
---|
317 | * No return value. |
---|
318 | ****************************************************************************** |
---|
319 | * Function Calls: |
---|
320 | * LLFindNext See Above... |
---|
321 | * LLFindPrev See above... |
---|
322 | *****************************************************************************/ |
---|
323 | void LLSwapNodes(int * one, int * two) // Switch two nodes' positions... |
---|
324 | { |
---|
325 | int *firstprev, *firstnext; |
---|
326 | int *secondprev, *secondnext; |
---|
327 | |
---|
328 | if(one == two) return; // if they're the same, do nothing |
---|
329 | |
---|
330 | firstprev = LLFindPrev(one); // Store the addresses of their neighbors... |
---|
331 | firstnext = LLFindNext(one); |
---|
332 | secondprev = LLFindPrev(two); |
---|
333 | secondnext = LLFindNext(two); |
---|
334 | |
---|
335 | if(firstprev != NULL) (int *)firstprev[0] = two; // Swap their |
---|
336 | if(firstnext != NULL) (int *)firstnext[1] = two; // Neighbors' pointers |
---|
337 | if(secondprev != NULL) (int *)secondprev[0] = one; |
---|
338 | if(secondnext != NULL) (int *)secondnext[1] = one; |
---|
339 | |
---|
340 | (int *)one[0] = secondnext; // Swap the two nodes' pointers |
---|
341 | (int *)one[1] = secondprev; |
---|
342 | (int *)two[0] = firstnext; |
---|
343 | (int *)two[1] = firstprev; |
---|
344 | |
---|
345 | if(firstnext == two) (int *)one[1] = two; // Fix things if they were |
---|
346 | if(firstprev == two) (int *)one[0] = two; // next to each other... |
---|
347 | if(secondprev == one) (int *)two[0] = one; |
---|
348 | if(secondnext == one) (int *)two[1] = one; |
---|
349 | } |
---|
350 | |
---|
351 | /***************************************************************************** |
---|
352 | * Function: LLCountNodes() |
---|
353 | ****************************************************************************** |
---|
354 | * Description: |
---|
355 | * Traverses the entire list and returns the number of nodes it finds. |
---|
356 | ****************************************************************************** |
---|
357 | * Function Calls: |
---|
358 | * LLFindFirst See above... |
---|
359 | * LLFindNext See above... |
---|
360 | *****************************************************************************/ |
---|
361 | int LLCountNodes(int * current) // Returns # of nodes in entire list |
---|
362 | { |
---|
363 | int numnodes=1; |
---|
364 | int *first, *next; |
---|
365 | |
---|
366 | first = LLFindFirst(current); // Get the first node... |
---|
367 | next = first; |
---|
368 | |
---|
369 | |
---|
370 | // If next[0] (pointer to next node) is NULL, we hit the end. |
---|
371 | // If next[0] is the same as current, we've got a circular linked list... |
---|
372 | while((int *)next[0] != NULL && (int *)next[0] != first) |
---|
373 | { |
---|
374 | numnodes++; |
---|
375 | next = LLFindNext(next); |
---|
376 | } |
---|
377 | |
---|
378 | return numnodes; |
---|
379 | } |
---|
380 | |
---|
381 | |
---|
382 | /***************************************************************************** |
---|
383 | * Function: LLSelectSort() |
---|
384 | ****************************************************************************** |
---|
385 | * Description: |
---|
386 | * Given any node in a list, sorts the whole list using a selection sort |
---|
387 | * algorithm. You must supply a function to compare two nodes. The |
---|
388 | * return value is the address of the new first node in the list. |
---|
389 | ****************************************************************************** |
---|
390 | * Function Calls: |
---|
391 | * LLCountNodes See above... |
---|
392 | * LLFindLast See above... |
---|
393 | * LLFindFirst See above... |
---|
394 | * LLFindNext See above... |
---|
395 | * LLFindPrev See above... |
---|
396 | * LLSwapNodes See above... |
---|
397 | * compare The user-defined function which compares two nodes. |
---|
398 | * If you've ever used qsort, this should be familiar. |
---|
399 | *****************************************************************************/ |
---|
400 | // Sorts the list and returns a pointer to the first node |
---|
401 | int * LLSelectSort(int * current, int compare(void *, void *)) |
---|
402 | { |
---|
403 | int i,j; // Junk / loop variables |
---|
404 | int numnodes; // number of nodes in list |
---|
405 | int *best, *last; // best match and last node in the list |
---|
406 | |
---|
407 | numnodes = LLCountNodes(current); // get the number of nodes... |
---|
408 | last = LLFindLast(current); // Find the last node. |
---|
409 | |
---|
410 | for(i=numnodes-1; i>1; i--) |
---|
411 | { |
---|
412 | current = LLFindFirst(current); // get the first node again |
---|
413 | best = last; // reset our "best" node |
---|
414 | |
---|
415 | for(j=0; j<i; j++) |
---|
416 | { |
---|
417 | if(compare(current, best) > 0) // If we found a better match... |
---|
418 | { |
---|
419 | best = current; // keep track of the "best" match |
---|
420 | } |
---|
421 | current = LLFindNext(current); // Go to the next node. |
---|
422 | } |
---|
423 | |
---|
424 | LLSwapNodes(last, best); // Switch two nodes... |
---|
425 | last = LLFindPrev(best); // And go backwards by one node. |
---|
426 | } |
---|
427 | |
---|
428 | return LLFindFirst(current); // return pointer to the first node. |
---|
429 | } |
---|