<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE document PUBLIC "-//CNX//DTD CNXML 0.5 plus MathML//EN" "http://cnx.rice.edu/cnxml/0.5/DTD/cnxml_mathml.dtd">
<document xmlns="http://cnx.rice.edu/cnxml" xmlns:md="http://cnx.rice.edu/mdml/0.4" xmlns:m="http://www.w3.org/1998/Math/MathML" xmlns:bib="http://bibtexml.sf.net/" id="id3716468">
  <name>Linked lists</name>
  <metadata>
  <md:version>1.2</md:version>
  <md:created>2007/10/19 08:06:47 GMT-5</md:created>
  <md:revised>2007/11/12 10:18:41.612 US/Central</md:revised>
  <md:authorlist>
      <md:author id="hanv">
      <md:firstname/>
      
      <md:surname/>
      
    </md:author>
  </md:authorlist>

  <md:maintainerlist>
    <md:maintainer id="hanv">
      <md:firstname/>
      
      <md:surname/>
      
    </md:maintainer>
  </md:maintainerlist>
  
  

  <md:abstract/>
</metadata>
  <content>
    <section id="id-0181081391395">
      <name>2. Linked lists</name>
      <para id="id5225114">(From Wikipedia, the free encyclopedia)</para>
      <para id="id5225124">In computer science, a linked list is one of the fundamental data structures. It consists of a sequence of nodes, each containing arbitrary data fields and one or two references ("links") pointing to the next and/or previous nodes. The principal benefit of a linked list over a conventional array is that the order of the linked items may be different from the order that the data items are stored in memory or on disk, allowing the list of items to be traversed in a different order. A linked list is a self-referential datatype because it contains a pointer or link to another datum of the same type. Linked lists permit insertion and removal of nodes at any point in the list in constant time, but do not allow random access. Several different types of linked list exist: singly-linked lists, doubly-linked lists, and circularly-linked lists.</para>
      <para id="id3686433">Linked lists can be implemented in most languages. Languages such as Lisp and Scheme have the data structure built in, along with operations to access the linked list. Procedural or object-oriented languages such as C, C++, and Java typically rely on mutable references to create linked lists.</para>
      <section id="id-361921650463">
        <name>2.1. Types of linked lists</name>
        <section id="id-406759630594">
          <name>2.1.1. Linearly-linked lists</name>
          <para id="id5132036">(From Wikipedia, the free encyclopedia)</para>
          <para id="id5132046">Singly-linked list</para>
          <para id="id5132050">The simplest kind of linked list is a singly-linked list (or slist for short), which has one link per node. This link points to the next node in the list, or to a null value or empty list if it is the final node.</para>
          <para id="id5132077"><figure id="id5132089"><media type="image/png" src="Singly-linked-list.png"><param name="height" value="33"/><param name="width" value="331"/></media>
<caption>A singly-linked list containing three integer values</caption></figure></para>
          <para id="id5132122">Doubly-linked list</para>
          <para id="id5132132">A more sophisticated kind of linked list is a doubly-linked list or two-way linked list. Each node has two links: one points to the previous node, or points to a null value or empty list if it is the first node; and one points to the next, or points to a null value or empty list if it is the final node.</para>
          <para id="id5132161"><figure id="id5132277"><media type="image/png" src="Doubly-linked-list.png"><param name="height" value="29"/><param name="width" value="444"/></media><caption>A doubly-linked list containing three integer values</caption></figure></para>
          <para id="id5132310">In some very low level languages, Xor-linking offers a way to implement doubly-linked lists using a single word for both links, although the use of this technique is usually discouraged. A similar link storage preserving technique is the subtraction edge.</para>
        </section>
        <section id="id-415070024259">
          <name>2.1.2. Circularly-linked lists</name>
          <para id="id5132326">(From Wikipedia, the free encyclopedia)</para>
          <para id="id5132336">In a circularly-linked list, the first and final nodes are linked together. This can be done for both singly and doubly linked lists. To traverse a circular linked list, you begin at any node and follow the list in either direction until you return to the original node. Viewed another way, circularly-linked lists can be seen as having no beginning or end. This type of list is most useful for managing buffers for data ingest, and in cases where you have one object in a list and wish to see all other objects in the list.</para>
          <para id="id5132360">The pointer pointing to the whole list may be called the access pointer.</para>
          <para id="id5132365"><figure id="id5132378"><media type="image/png" src="Circularly-linked-list.png"><param name="height" value="48"/><param name="width" value="279"/></media><caption>A circularly-linked list containing three integer values</caption></figure></para>
          <para id="id5132412">Singly-circularly-linked list</para>
          <para id="id5132424">In a singly-circularly-linked list, each node has one link, similar to an ordinary singly-linked list, except that the next link of the last node points back to the first node. As in a singly-linked list, new nodes can only be efficiently inserted after a node we already have a reference to. For this reason, it's usual to retain a reference to only the last element in a singly-circularly-linked list, as this allows quick insertion at the beginning, and also allows access to the first node through the last node's next pointer.</para>
          <para id="id4248363">Doubly-circularly-linked list</para>
          <para id="id4248375">In a doubly-circularly-linked list, each node has two links, similar to a doubly-linked list, except that the previous link of the first node points to the last node and the next link of the last node points to the first node. As in doubly-linked lists, insertions and removals can be done at any point with access to any nearby node. Although structurally a doubly-circularly-linked list has no beginning or end, an external access pointer may formally establish the pointed node to be the head node or the tail node, and maintain order just as well as a doubly-linked list with sentinel nodes.</para>
        </section>
      </section>
      <section id="id-986741823282">
        <name>2.2. Linked lists operations</name>
        <para id="id4248410">When manipulating linked lists in-place, care must be taken to not use values that you have invalidated in previous assignments. This makes algorithms for inserting or deleting linked list nodes somewhat subtle. This section gives pseudocode for adding or removing nodes from singly, doubly, and circularly linked lists in-place. Throughout we will use null to refer to an end-of-list marker or sentinel, which may be implemented in a number of ways.</para>
        <section id="id-888998763874">
          <name>2.2.1. Linearly-linked lists</name>
          <para id="id4248441">(From Wikipedia, the free encyclopedia)</para>
          <para id="id4248450">Singly-linked lists</para>
          <para id="id4248454">Our node data structure will have two fields. We also keep a variable firstNode which always points to the first node in the list, or is null for an empty list.</para>
          <para id="id4248481">record Node {</para>
          <para id="id4248505">data // The data being stored in the node</para>
          <para id="id4248520">next // A reference to the next node, null for last node</para>
          <para id="id4248536">}</para>
          <para id="id4248541">record List {</para>
          <para id="id4248565">Node firstNode // points to first node of list; null for empty list</para>
          <para id="id4248591">}</para>
          <para id="id4248597">Traversal of a singly-linked list is simple, beginning at the first node and following each next link until we come to the end:</para>
          <para id="id4248615">node := list.firstNode</para>
          <para id="id4248620">while node not null {</para>
          <para id="id4248636">(do something with node.data)</para>
          <para id="id4248650">node := node.next</para>
          <para id="id4248657">}</para>
          <para id="id4248662">The following code inserts a node after an existing node in a singly linked list. The diagram shows how it works. Inserting a node before an existing one cannot be done; instead, you have to locate it while keeping track of the previous node.</para>
          <para id="id4248670">
            <figure id="id4248680"><media type="image/png" src="Singly_linked_list_insert_after.png">
                <param name="height" value="104"/>
                <param name="width" value="360"/>
              </media>
            <caption>Code inserting</caption></figure>
          </para>
          
          <para id="id4248709">function insertAfter(Node node, Node newNode) { // insert newNode after node</para>
          <para id="id4248747">newNode.next := node.next</para>
          <para id="id4248755">node.next := newNode</para>
          <para id="id4248766">}</para>
          <para id="id4248772">Inserting at the beginning of the list requires a separate function. This requires updating firstNode.</para>
          <para id="id4248789">function insertBeginning(List list, Node newNode) { // insert node before current first node</para>
          <para id="id3709391">newNode.next := list.firstNode</para>
          <para id="id3709402">list.firstNode := newNode</para>
          <para id="id3709410">}</para>
          <para id="id3709415">Similarly, we have functions for removing the node after a given node, and for removing a node from the beginning of the list. The diagram demonstrates the former. To find and remove a particular node, one must again keep track of the previous element.</para>
          <para id="id3709435">
            <figure id="id3709445"><media type="image/png" src="Singly_linked_list_delete_after.png">
                <param name="height" value="101"/>
                <param name="width" value="315"/>
              </media>
            <caption>Remove node past</caption></figure>
          </para>
          
          <para id="id3709474">function removeAfter(Node node) { // remove node past this one</para>
          <para id="id3709503">obsoleteNode := node.next</para>
          <para id="id3709511">node.next := node.next.next</para>
          <para id="id3709519">destroy obsoleteNode</para>
          <para id="id3709526">}</para>
          <para id="id3709532">function removeBeginning(List list) { // remove first node</para>
          <para id="id3709561">obsoleteNode := list.firstNode</para>
          <para id="id3709569">list.firstNode := list.firstNode.next // point past deleted node</para>
          <para id="id3709587">destroy obsoleteNode</para>
          <para id="id3709594">}</para>
          <para id="id3709600">Notice that removeBeginning() sets list.firstNode to null when removing the last node in the list.</para>
          <para id="id3709624">Since we can't iterate backwards, efficient "insertBefore" or "removeBefore" operations are not possible.</para>
          <para id="id3709630">Appending one linked list to another can be inefficient unless a reference to the tail is kept as part of the List structure, because we must traverse the entire first list in order to find the tail, and then append the second list to this. Thus, if two linearly-linked lists are each of length n, list appending has asymptotic time complexity of O(n). In the Lisp family of languages, list appending is provided by the append procedure.</para>
          <para id="id3709670">Many of the special cases of linked list operations can be eliminated by including a dummy element at the front of the list. This ensures that there are no special cases for the beginning of the list and renders both insertBeginning() and removeBeginning() unnecessary. In this case, the first useful data in the list will be found at list.firstNode.next.</para>
          <para id="id3709680">Doubly-linked lists</para>
          <para id="id3709690">With doubly-linked lists there are even more pointers to update, but also less information is needed, since we can use backwards pointers to observe preceding elements in the list. This enables new operations, and eliminates special-case functions. We will add a prev field to our nodes, pointing to the previous element, and a lastNode field to our list structure which always points to the last node in the list. Both list.firstNode and list.lastNode are null for an empty list.</para>
          <para id="id3709748">record Node {</para>
          <para id="id3709772">data // The data being stored in the node</para>
          <para id="id3709787">next // A reference to the next node; null for last node</para>
          <para id="id3709803">prev // A reference to the previous node; null for first node</para>
          <para id="id3709818">}</para>
          <para id="id5194750">record List {</para>
          <para id="id5194774">Node firstNode // points to first node of list; null for empty list</para>
          <para id="id5194801">Node lastNode // points to last node of list; null for empty list</para>
          <para id="id5194827">}</para>
          <para id="id5194832">Iterating through a doubly linked list can be done in either direction. In fact, direction can change many times, if desired.</para>
          <para id="id5194838">Forwards</para>
          <para id="id5194843">node := list.firstNode</para>
          <para id="id5194849">while node ≠ null</para>
          <para id="id5194869">&lt;do something with node.data&gt;</para>
          <para id="id5194878">node := node.next</para>
          <para id="id5194886">Backwards</para>
          <para id="id5194890">node := list.lastNode</para>
          <para id="id5194896">while node ≠ null</para>
          <para id="id5194916">&lt;do something with node.data&gt;</para>
          <para id="id5194925">node := node.prev</para>
          <para id="id5194932">These symmetric functions add a node either after or before a given node, with the diagram demonstrating after:</para>
          <para id="id5194941">
            <figure id="id5194951"><media type="image/png" src="Doubly_linked_list_insert_after.png">
                <param name="height" value="102"/>
                <param name="width" value="443"/>
              </media>
            <caption>Insert node after</caption></figure>
          </para>
          
          <para id="id5194981">function insertAfter(List list, Node node, Node newNode)</para>
          <para id="id5195020">newNode.prev := node</para>
          <para id="id5195027">newNode.next := node.next</para>
          <para id="id5195035">if node.next = null</para>
          <para id="id5195058">list.lastNode := newNode</para>
          <para id="id5195065">else</para>
          <para id="id5195079">node.next.prev := newNode</para>
          <para id="id5195087">node.next := newNode</para>
          <para id="id5195094">function insertBefore(List list, Node node, Node newNode)</para>
          <para id="id5195133">newNode.prev := node.prev</para>
          <para id="id5195141">newNode.next := node</para>
          <para id="id5195148">if node.prev is null</para>
          <para id="id5195166">list.firstNode := newNode</para>
          <para id="id5195174">else</para>
          <para id="id5195188">node.prev.next := newNode</para>
          <para id="id5195195">node.prev := newNode</para>
          <para id="id4521851">We also need a function to insert a node at the beginning of a possibly-empty list:</para>
          <para id="id4521857">function insertBeginning(List list, Node newNode)</para>
          <para id="id4521886">if list.firstNode = null</para>
          <para id="id4521909">list.firstNode := newNode</para>
          <para id="id4521916">list.lastNode := newNode</para>
          <para id="id4521926">newNode.prev := null</para>
          <para id="id4521934">newNode.next := null</para>
          <para id="id4521942">else</para>
          <para id="id4521956">insertBefore(list, list.firstNode, newNode)</para>
          <para id="id4521963">A symmetric function inserts at the end:</para>
          <para id="id4521968">function insertEnd(List list, Node newNode)</para>
          <para id="id4521997">if list.lastNode = null</para>
          <para id="id4522019">insertBeginning(list, newNode)</para>
          <para id="id4522027">else</para>
          <para id="id4522041">insertAfter(list, list.lastNode, newNode)</para>
          <para id="id4522049">Removing a node is easier, only requiring care with the firstNode and lastNode:</para>
          <para id="id4522074">function remove(List list, Node node)</para>
          <para id="id4522104">if node.prev = null</para>
          <para id="id4522126">list.firstNode := node.next</para>
          <para id="id4522134">else</para>
          <para id="id4522148">node.prev.next := node.next</para>
          <para id="id4522155">if node.next = null</para>
          <para id="id4522178">list.lastNode := node.prev</para>
          <para id="id4522185">else</para>
          <para id="id4522199">node.next.prev := node.prev</para>
          <para id="id4522207">destroy node</para>
          <para id="id4522214">One subtle consequence of this procedure is that deleting the last element of a list sets both firstNode and lastNode to null, and so it handles removing the last node from a one-element list correctly. Notice that we also don't need separate "removeBefore" or "removeAfter" methods, because in a doubly-linked list we can just use "remove(node.prev)" or "remove(node.next)" where these are valid.</para>
        </section>
        <section id="id-230939580875">
          <name>2.2.2. Circularly-linked lists</name>
          <para id="id4522262">(From Wikipedia, the free encyclopedia)</para>
          <para id="id4522272">Circularly-linked lists can be either singly or doubly linked. In a circularly linked list, all nodes are linked in a continuous circle, without using null. For lists with a front and a back (such as a queue), one stores a reference to the last node in the list. The next node after the last node is the first node. Elements can be added to the back of the list and removed from the front in constant time.</para>
          <para id="id4522304">Both types of circularly-linked lists benefit from the ability to traverse the full list beginning at any given node. This often allows us to avoid storing firstNode and lastNode, although if the list may be empty we need a special representation for the empty list, such as a lastNode variable which points to some node in the list or is null if it's empty; we use such a lastNode here. This representation significantly simplifies adding and removing nodes with a non-empty list, but empty lists are then a special case.</para>
          <para id="id4971440">Doubly-circularly-linked lists</para>
          <para id="id4971452">Assuming that someNode is some node in a non-empty list, this code iterates through that list starting with someNode (any node will do):</para>
          <para id="id4971479">Forwards</para>
          <para id="id4971483">node := someNode</para>
          <para id="id4971489">do</para>
          <para id="id4971500">do something with node.value</para>
          <para id="id4971508">node := node.next</para>
          <para id="id4971516">while node ≠ someNode</para>
          <para id="id4971532">Backwards</para>
          <para id="id4971537">node := someNode</para>
          <para id="id4971542">do</para>
          <para id="id4971554">do something with node.value</para>
          <para id="id4971561">node := node.prev</para>
          <para id="id4971572">while node ≠ someNode</para>
          <para id="id4971589">Notice the postponing of the test to the end of the loop. This is important for the case where the list contains only the single node someNode.</para>
          <para id="id4971607">This simple function inserts a node into a doubly-linked circularly-linked list after a given element:</para>
          <para id="id4971616">function insertAfter(Node node, Node newNode)</para>
          <para id="id4971650">newNode.next := node.next</para>
          <para id="id4971657">newNode.prev := node</para>
          <para id="id4971665">node.next.prev := newNode</para>
          <para id="id4971673">node.next := newNode</para>
          <para id="id4971685">To do an "insertBefore", we can simply "insertAfter(node.prev, newNode)". Inserting an element in a possibly empty list requires a special function:</para>
          <para id="id4971691">function insertEnd(List list, Node node)</para>
          <para id="id4971725">if list.lastNode = null</para>
          <para id="id4971747">node.prev := node</para>
          <para id="id4971755">node.next := node</para>
          <para id="id4971762">else</para>
          <para id="id4971776">insertAfter(list.lastNode, node)</para>
          <para id="id4971784">list.lastNode := node</para>
          <para id="id4971792">To insert at the beginning we simply "insertAfter(list.lastNode, node)". Finally, removing a node must deal with the case where the list empties:</para>
          <para id="id4971798">function remove(List list, Node node)</para>
          <para id="id4971832">if node.next = node</para>
          <para id="id5202216">list.lastNode := null</para>
          <para id="id5202232">else</para>
          <para id="id5202245">node.next.prev := node.prev</para>
          <para id="id5202253">node.prev.next := node.next</para>
          <para id="id5202261">if node = list.lastNode</para>
          <para id="id5202279">list.lastNode := node.prev;</para>
          <para id="id5202287">destroy node</para>
          <para id="id5202294">As in doubly-linked lists, "removeAfter" and "removeBefore" can be implemented with "remove(list, node.prev)" and "remove(list, node.next)".</para>
        </section>
      </section>
    </section>
  </content>
</document>
