Title: Linked Lists
1Linked Lists
2Linked List Basics
- Linked lists and arrays are similar since they
both store collections of data. - The array's features all follow from its strategy
of allocating the memory for all its elements in
one block of memory. - Linked lists use an entirely different strategy
linked lists allocate memory for each element
separately and only when necessary.
3Disadvantages of Arrays
- The size of the array is fixed.
- In case of dynamically resizing the array from
size S to 2S, we need 3S units of available
memory. - Programmers allocate arrays which seem "large
enough This strategy has two disadvantages (a)
most of the time there are just 20 or 30
elements in the array and 70 of the space in the
array really is wasted. (b) If the program ever
needs to process more than the declared size, the
code breaks. - Inserting (and deleting) elements into the middle
of the array is potentially expensive because
existing elements need to be shifted over to make
room
4Linked lists
- Linked lists are appropriate when the number of
data elements to be represented in the data
structure at once is unpredictable. - Linked lists are dynamic, so the length of a list
can increase or decrease as necessary. - Each node does not necessarily follow the
previous one physically in the memory. - Linked lists can be maintained in sorted order by
inserting or deleting an element at the proper
point in the list.
5Singly Linked Lists
head
next
next
next
Last node
First node
6Empty List
- Empty Linked list is a single pointer having the
value of NULL. - head NULL
head
7Basic Ideas
- Lets assume that the node is given by the
following type declaration - struct Node
- Object element
- Node next
8Basic Linked List Operations
- Insert a node
- Delete a node
- Searching a node
- List Traversal
9Insertion in a linked list
a
b
current
x
tmp
tmp new Node tmp-gtelement x tmp-gtnext
current-gtnext current-gtnext tmp Or simply
(if Node has a constructor initializing its
members) current-gtnext new Node(x,current-gtnext
)
10Deletion from a linked list
a
x
b
current
- Node deletedNode current-gtnext
- current-gtnext current-gtnext-gtnext
- delete deletedNode
11Special Cases (1)
- Inserting before the first node (or to an empty
list) - tmp new Node
- tmp-gtelement x
- if (current NULL)
- tmp-gtnext head
- head tmp
-
- else // Adding in middle or at end
- tmp-gtnext curent-gtnext
- current-gtnext tmp
-
-
12Special Cases (2)
- if (current NULL)
- // Deleting first node
- head head -gtnext
- else
- // Deleting other nodes
- Node deletedNode current-gtnext
- current-gtnext deletedNode -gtnext
-
13Searching a node in a linked list
- pCur pHead
-
- // Search until target is found or we reach
- // the end of list
- while (pCur ! NULL
- pCur-gtelement ! target)
-
- pCur pCur-gtnext
-
- //Determine if target is found
- if (pCur) found 1
- else found 0
14Traversing a linked list
- Node pWalker
- int count 0
-
- cout ltltList contains\n
-
- for (pWalkerpHead pWalker!NULL
- pWalker pWalker-gtnext)
-
- count
- cout ltlt pWalker-gtelement ltlt endl
15Reversing a linked list
- Node reverse(Node x)
-
- Node t, y x, r NULL
- while (y!NULL)
- t y-gtnext
- y-gtnext r
- r y
- y t
-
- return r
16Header Nodes
- One problem with the basic description it
assumes that whenever an item x is removed (or
inserted) some previous item is always present. - Consequently removal of the first item and
inserting an item as a new first node become
special cases to consider. - In order to avoid dealing with special cases
introduce a header node (dummy node). - A header node is an extra node in the list that
holds no data but serves to satisfy the
requirement that every node has a previous node.
17List with a header node
header
a
b
d
c
18List insertion sort
- // Maintain two lists, an input (unsorted) list
and - // an output (sorted) list. The code is
simplified by - // the use of head nodes for each list.
- // Assume the following node definition
- struct Node
- int element
- Node next
- Node (int x Node t)
- element x next t
-
- // First generate N random numbers and build a
list - Node heada(0, NULL)
- Node aheada t a
- for (int i0 iltN i)
- t (t-gtnext new node (rand() 1000,
NULL))
19- // Sort the linked list
- Node headb(0,NULL)
- Node t, u, x, b headb
- for (t a-gtnext t!NULL t u)
- u t-gtnext
- x b
- while( x-gtnext ! NULL
- x-gtnext-gtelement lt t-gtelement)
- x x-gtnext
- t-gtnext x-gtnext
- x-gtnext t
-
20Linked list implementation of Stacks
- In implementing Stack as a linked list the top of
the stack is represented by the first item in the
linked list. - To implement push create a new node and attach
it as the new first node. - To implement pop advance the top of stack to the
second item in the list (if there is one). - Each operation is performed in constant time.
21Implementing a Stack with a Singly Linked List
- struct Node // a node in the stack
- Object element // element
- Node next // next pointer
- Node(const Object e Object(), Node n NULL)
- element(e), next(n) // constructor
-
- typedef Node NodePtr // pointer type to node
22Class LinkedStack
- template ltclass Objectgt
- class LinkedStack
- protected // local node structure
- // ... (insert Node here)
- private // member data
- NodePtr tp // pointer to stack top
- int sz // number of items in stack
- public
- LinkedStack() // default constructor
- tp NULL
- sz 0
-
- int size() const return sz // number of
elements - bool isEmpty() const return sz 0 // is
the stack empty?
23Class LinkedStack (cont.)
- Object top() throw(StackEmptyException)
- if (isEmpty())
- throw StackEmptyException("Top of empty
stack") - return tp-gtelement
-
- void push(const Object e) // push element
onto stack - NodePtr v new Node(e, tp)
- tp v // v is now the top
- sz
-
- Object pop() throw(StackEmptyException) // pop
top element - if (isEmpty())
- throw StackEmptyException("Pop of empty
stack") - NodePtr old tp // node to remove
- tp tp-gtnext
- sz--
- Object result old-gtelement // element to
return - delete old
- return result
24Class LinkedStack (cont.)
- template ltclass Objectgt // copy from stack ls
- void LinkedStackltObjectgtcopyFrom(const
LinkedStack ls) -
- tp NULL
- NodePtr p ls.tp // p is current node in ls
- NodePtr prev NULL
- while (p ! NULL)
- NodePtr v new Node(p-gtelement, NULL) //
create copy of p - if (tp NULL) tp v // if first node
- else prev-gtnext v // else link after prev
- prev v
- p p-gtnext
-
- sz ls.sz
-
25Linked list implementation of Queues
- A linked list in which we maintain a pointer to
the first and last nodes can be used to implement
the queue in constant time per operation. - The dequeue routine is logically identical to a
stack pop. - The enqueue has two cases
- Queue is empty create one element, have both
front and back point to it. - Otherwise, attach the new node to the end of list
and reset the end of list to this new node.
26Implementing a Queue with a Singly Linked List
- // ... (part of class LinkedQueue)
- void enqueue(const Object e) // enqueue
element - NodePtr v new Node(e, NULL)
- if (sz 0) head v //if empty, this is new
head - else tail-gtnext v // else link after tail
- tail v // v is now the tail
- sz
-
- Object dequeue() throw(QueueEmptyException) //
dequeue - if (isEmpty())
- throw QueueEmptyException("Dequeue of empty
queue") - NodePtr old head // node to remove
- head head-gtnext
- if ((--sz) 0)
- tail NULL // deletion causes empty queue
- Object result old-gtelement
- delete old
- return result
- // ...
27Doubly Linked Lists
pHead
a
b
c
- Advantages
- Convenient to traverse the list backwards.
- Simplifies insertion and deletion because you no
longer have to refer to the previous node. - Disadvantage
- Increase in space requirements.
28Deletion
current
head
- oldNode current
- oldNode-gtprev-gtnext oldNode-gtnext
- oldNode-gtnext-gtprev oldNode-gtprev
- delete oldNode
- current head
29Insertion
head
current
- newNode new Node(x)
- newNode-gtprev current
- newNode-gtnext current-gtnext
- newNode-gtprev-gtnext newNode
- newNode-gtnext-gtprev newNode
- current newNode
newNode