Presentation is loading. Please wait.

# CS 367 – Introduction to Data Structures

## Presentation on theme: "CS 367 – Introduction to Data Structures"— Presentation transcript:

CS 367 – Introduction to Data Structures
Linked Lists – Part II CS 367 – Introduction to Data Structures

Adding a Tail Reference
Up to now, we have only considered our lists to have a head reference having a tail reference makes adding to the end of the list much more efficient constant time: O(1) however, a tail reference makes things more complex must make sure that head and tail refer to null when the list is empty must make sure head and tail point to the same node when only one node in the list

Add/Delete Tail public void addTail(Object data) {
Node tmp = new Node(data, null); // empty list? if(tail == null) { head = tail = tmp; } else { tail.next = tmp; tail = tmp; } } public Object deleteTail() { if(tail == null) { return null; } // empty list. // get the tail and a reference to the previous node Node cur, prev = null; for(Node cur = head; cur != tail; prev = cur, cur = cur.next); tail = prev; if(tail == null) { head = null; } // list is now empty else { tail.next = null; } return cur;

Problem Adding to tail: O(1) Deleteing from tail: O(n)
this is because the list can only be searched in one direction from head to tail have to search entire list to find the node prior to the tail so that its next reference can be adjusted

Doubly Linked List Solution is to include a previous and a next pointer in a node previous: refers to node immediately prior next: refers to node immediately after this is called a doubly linked list Now it is possible to search in both directions also makes removing the tail O(1)

Doubly Linked List Head Tail John Smith Jane Doe Pat Thomas 87.45
next next next previous previous previous

Doubly Linked List Node
A node now looks slightly different class Node { public Object data; public Node previous; public Node next; public Node(Object data, Node previous, Node next) { this.data = data; this.previous = previous; this.next = next; } The linked list we will consider will have a head and a tail pointer

Inserting at the tail Inserting at the tail is almost identical
it is slightly more complicated one more reference to deal with public void insertTail(Object data) { tail = new Node(data, tail, null); // is this the only node in the list? if(tail.previous == null) { head = tail; } else { tail.previous.next = tail; } }

Removing Tail of List Removing a node at the tail is now quick
public Object deleteTail() { if(tail == null) { return null; } // empty list Node tmp = tail; tail = tail.previous; if(tail != null) { tail.next = null; } else { head = null; } return tmp.data; } Notice that this operation is O(1) now

Adding a Node public void add(Object data) {
Node tmp = new Node(data, null, null); if(head == null) { head = tail = tmp; } // list was empty // find where the node goes else { Node cur; while((cur != null) && (((Comparable)cur.getData()).compareTo(data) <= 0)) cur = cur.next; tmp.setNext(cur); if(cur != null) { tmp.setPrev(cur.getPrev()); cur.setPrev(tmp); if(tmp.getPrev() != null) { tmp.getPrev().setNext(tmp); } else { head = tmp; } } else { tmp.setPrev(tail); tail.setNext(tmp); tail = tmp; }

Adding a Node Remember, must consider the following cases
empty list adding to head adding to tail adding to middle of the list Obviously, adding to the middle of a doubly linked list is more sophisticated

Appropriateness When should you use a doubly linked list?
depends on your application if you are routinely deleting from tail if you know where the desired node is may be faster to search from the rear Anything you can do with a singly linked list can be done with a doubly linked list reverse is not true

Circular Lists May want a list to form a ring (why?)
every node has a successor if it is a doubly linked circular list, every node has a successor and a predecessor no head or tail only need to keep track of current node if only one node in the list, its successor is itself current.next = current if the list is empty, current refers to null

Circular List Empty list. One node in list. Multiple nodes in list.
current Empty list. current data One node in list. next current Multiple nodes in list. data data data next next next

Inserting a Node While there is no head or tail, we do have a concept of the beginning and end of list beginning: what current is referencing end: node immediately prior to current When using a circular list, usually does not matter much about the ordering so usually insert immediately after or before the current node

Inserting a Node After Current
public void insert(Object data) { Node tmp = new Node(data, null); // check if this is the only node in the list if(current == null) { tmp.setNext(tmp); current = tmp; } else { tmp.setNext(current.getNext()); current.setNext(tmp);

Inserting Node Before Current
In a singly linked list, this is more difficult either need to keep track of the tail and do the insert or you need to search from current to the end of the list how do you know when a complete loop has been made around the list? what is the problem with this method?

Removing the Current Node
When doing a remove, usually removing the current node why? This can cause some problems if a singly linked list is used to implement circular list have to find and update tail of list requires a search all the way through the list O(n) problem easily solved by using a doubly linked list

Download ppt "CS 367 – Introduction to Data Structures"

Similar presentations

Ads by Google