home *** CD-ROM | disk | FTP | other *** search
/ Point Programming 1 / PPROG1.ISO / c / snippets / llist.nts < prev    next >
Encoding:
Text File  |  1995-03-13  |  9.1 KB  |  176 lines

  1. === Some notes on Linked Lists ===========================================
  2.  
  3. Introduction
  4.  
  5. Linked lists consist of any number of 'nodes' which contain data and one
  6. pointer for singly linked lists or two pointers for doubly linked lists.
  7. The first or only pointer serves to connect one node to a next node; in a
  8. doubly linked list the second pointer serves to connect the node to a
  9. previous node.
  10. A 'first node pointer' serves as anchor to the entire list. A 'last node
  11. pointer' is optional; but it is common in doubly linked lists.
  12. One or more 'current node pointers' -- sometimes allocated on the fly --
  13. simplify access to specific nodes.
  14.  
  15. The three most common operations on linked lists are:
  16. - creating a new node AFTER the current node,
  17. - creating a new node BEFORE the current node,
  18. - deleting the current node.
  19.  
  20. Operations to create a node as first or last node, or deleting a first or
  21. last node are also common. And of course there are operations to change
  22. the current node -- i.e. changing the value of the current node pointer --
  23. and operations to access the data of the current node and optionally the
  24. data of the first or last nodes.
  25.  
  26.  
  27. Singly Linked Lists, simple design and complicated implementation
  28.  
  29. Generally speaking, creating a new node AFTER the current node is rather
  30. simple. It consists of:
  31. - allocating an appropriately sized piece of memory for a node,
  32. - filling in its data part (actually optional: it could be done later),
  33. - copying the value of the current node's next node pointer to the new
  34.   node's next pointer,
  35. - copying the address of the new node to the current node's next pointer,
  36. - optionally changing the current node pointer's value to the address of
  37.   the new node.
  38.  
  39. Creating a new node BEFORE the current node is also rather simple:
  40. - make the preceding node the current node,
  41. - then insert the new node after the current node.
  42.  
  43. And deleting the current node:
  44. - copy the value of the current node's next pointer to the preceding
  45.   node's next pointer,
  46. - de-allocate the current node's piece of memory,
  47. - change the current node pointer in a sensible way, e.g. change it to the
  48.   address of the next node.
  49.  
  50. There are, however, a number of problems:
  51. 1 The obvious first is the necessity to find the preceding node when you
  52.   want to delete the current node, and when you want to create a new node
  53.   before the current node.
  54. 2 What will be the value of the current node pointer after deletion of the
  55.   first node or the last node -- both in the sense of 'only' node and
  56.   'end-of-the-list' node?
  57. 3 What special things should be done when the list is empty?
  58. 4 What special handling is necessary when creating a new node _before_ the
  59.   current node when the current node is the _first_ node?
  60. 5 What special handling is necessary when creating a new node _after_ the
  61.   current node when the current node is the _last_ node?
  62.   (This 'problem' is included for symmetry reasons. The answer is: "None,
  63.   unless a 'last node pointer' and/or a dummy head node are used.")
  64. 6 What are the consequences of allowing the current node pointer to become
  65.   invalid? For example after deleting the last node (see 2), or after
  66.   changing the current node pointer to the 'next' node if it was pointing
  67.   to the last node. (See also 4 and 5.)
  68.  
  69. In a simple design these problems should be handled when the situations
  70. occur. Note that for some special purpose designs some of these problems
  71. can be ignored.
  72.  
  73. Singly Linked Lists, complicated design and simple implementation I
  74.  
  75. Problem 6 can be handled by taking care that it does not occur.
  76. After deletion of a node the current node pointer is commonly set to point
  77. to the node following the old current node. If after deletion of the last
  78. (end-of-list) node the new current node is set to be the node preceding
  79. the deleted node, the problem is avoided.
  80. This complicates the implementation for deletion of a node slightly, but
  81. it simplifies the implementation for creating a new node after the current
  82. node -- and optionally the implementation for creating a new node at the
  83. end of the list -- as the situation does not need to be detected and
  84. handled any more. In a good implementation it does not affect the code for
  85. changing the current node pointer to the next node. (One of my first
  86. implementations wasn't good in that respect ...)
  87. Note that this solution for Problem 6 also partially solves Problem 2. And
  88. essentially merges the remaining part of Problem 2 with Problem 3.
  89. Note also that the solution may have some unwanted side effects as the
  90. 'motion' of the current node pointer will be reversed at the end of the
  91. list.
  92.  
  93. Singly Linked Lists, complicated design and simple implementation II
  94.  
  95. Problem 2 can be handled by giving node pointers a NULL value as indica-
  96. tion of its pointing to an 'invalid' node. An alternative is using other
  97. 'invalid' pointer values. With invalid meaning that the data at that
  98. address is irrelevant. But the 'invalidity' must usually be detectable!
  99. Note however that whenever detection is required, a NULL value is the most
  100. efficient. But when detection is NOT required another value may be better.
  101.  
  102. Singly Linked Lists, complicated design and simple implementation III
  103.  
  104. Problem 3 can be handled with a dummy head node. I.e. a node which is the
  105. physical first node, but does NOT contain relevant data. For practical
  106. purposes the node following this node is the actual or logical first node.
  107. Now let the current node pointer have a similar extra level of indirection
  108. -- otherwise it wouldn't make any sense. Also the current node pointer
  109. itself does not have then to be updated in come cases. As there is now no
  110. more structural difference between the logical first node and any other
  111. node Problem 3 is completely solved. As is a part of problem 4.
  112. Note that implementation for creating a new node BEFORE the current node
  113. now 'physically' is a _simplified_ version of the implementation for
  114. creating a new node AFTER the current node without a dummy head node. And
  115. that the implementation for creating a new node AFTER the current node is
  116. merely a matter of changing the value of the current node pointer to the
  117. address of the next node -- IF POSSIBLE -- and creating it before the now
  118. current node.
  119. Note also that Problem 1 -- with exception of deletion of the last node --
  120. is completely solved. And that the remaining problem with deletion of the
  121. last node is actually the same as Problems 6 AND 5.
  122. When having a valid last node pointer is useful Problem 6 should be solved
  123. as indicated. In my opinion it should always be solved, as the performance
  124. penalty is quite low.
  125.  
  126. Singly Linked Lists, conclusion
  127.  
  128. For general purpose implementations of Singly Linked Lists, it is very
  129. sensible to use a dummy head node. As an extra level of indirection is
  130. added there is a slight performance penalty. On the other hand the code
  131. size is definitely reduced, and the performance advantage -- by not having
  132. to test for special conditions -- may be more than the penalty.
  133.  
  134. For special purpose Singly Linked Lists the choice of whether or not to
  135. use dummy head nodes is quite dependent on its purpose and on performance
  136. requirements.
  137.  
  138. In the literature (Sedgewick, _Algorithms in C_, ISBN 0-201-51425-7, p.20)
  139. it is suggested that having a dummy tail node as well is useful.
  140. This is however only the case when the environment has 'garbage collec-
  141. tion' capabilities. I.e. it is useful only when explicit de-allocation of
  142. memory is not necessary (or even possible). Without garbage collection, or
  143. without a way to reverse a de-allocation, it causes MORE problems than it
  144. solves!
  145. The same book also suggests having the last (the dummy if it is used) node
  146. pointing to itself. That only makes sense in some special implementations.
  147. It has the advantage of not requiring a test to prevent the current node
  148. pointer from 'leaving' the list. But as this test is required anyway in
  149. most implementations and environments, it normally does not make any
  150. sense.
  151.  
  152.  
  153. Doubly Linked Lists
  154.  
  155. The operations relevant to Doubly Linked Lists are essentialy the same as
  156. those for Singly Linked Lists. Only the 'previous node pointers' need to
  157. be handled in addition.
  158. The problems are generally also the same. Only Problem 1 isn't there any
  159. more. Doubly Linked Lists are a specific solution to that problem! The
  160. only new questions are whether there should be a last node pointer and
  161. whether there should be a dummy tail node as well. The answer to which is:
  162. neither or both.
  163.  
  164. Dummy head nodes are as useful in Doubly Linked Lists as they are in
  165. Singly Linked Lists and for the same reasons: no more special handling for
  166. first node pointers. Dummy tail nodes are also useful for the same reason:
  167. no more special handling for last node pointers.
  168. Having for the current node pointer an extra level of indirection -- by
  169. having it actually point to the preceeding node -- isn't a necessity any
  170. more. The preceeding node is now easily accessible. It still can have some
  171. advantages though: it does not have to be updated after creating a new
  172. node. But the extra level of indirection can be bothersome.
  173.  
  174.  
  175. === A.Reitsma, Delft, The Netherlands. 94-08-11 ====== Public Domain =====
  176.