linked List

Singularly Linked List

Dynamic data structure consisting of a sequence of nodes arranged in a linear order

  • The order in a linked list is determined by a pointer in each object

Each node(element) of a linked list has an key and a pointer next

  • Given a node x in the list, x.next points to its successor in the linked list
  • if x.next = NIL, that element is the last element and is called the tail of the list.
  • L.head points to the first element of the list , if L.head = NIL then the list is empty.
  • L.tail points to the last element of the list
  • if L.head && L.tail = NIL, then the list is empty

Insertion

Insertion at the head, that:

  • Allocate a new node
  • update two pointers

Time complexity :

INSERT(L,x):
	x.next = L.head
	L.head = x

Deletion

Deletion at the head, that:

  • Update L.head
  • Deallocate memeory of node being deleted(done by garbage collection normally)

Time Complexity :

DELETE-HEAD(L):
	if( L.head != NIL ):
		L.head = L.head.next

Find the first element with key in list using simple linear search.

  • if found, return a pointer to this element.
  • if not, return NIL. Iterator pattern

Time Complexity :

SEARCH(L,k):
	x = L.head
	while( x != NIL and x.key != k ):
		x = x.next
	return x

Recursion

The structure of linked lists is inherently recursive

  • Iterators can be implemented by recursive algorithms
REC-SEARCH(x,k):
	if( x = NIL ):
		return x
	else if( x.key = k ):
		return x
	else:
		return REC-SEARCH(x.next,k)

Doubly Linked List

Extension of singly linked list in which each node has a pointer attribute prev

  • a node x in the list, x.prev points to the previous node in the linked list
  • if x.prev = NIL, x has no predecessor and is therefore the head of the list

Pro: some operations are simplified and become more efficient# Con: memory overhead

Circular Linked List

Boundary conditions complicate the specification of the operations on doubly linked lists

  • We can introduce sentinels to simplify the code A Sentinal is a dummy node L.nil between the head and tail
  • L.nil.next points to the head
  • L.nil.prev points to the tail
  • The next attribute of the tail and the prev attribute of the head point to L.nil
  • Attribute L.head is no longer needed (use L.nil.next instead)