Linked Lists, Stacks, Queues, Deques It s time for a chainge!
Learning Goals After this unit, you should be able to... Differentiate an abstraction from an implementation. Define and give examples of problems that can be solved using the abstract data types stacks, queues and deques. Compare and contrast the implementations of these abstract data types using linked lists and circular arrays in C++. Demonstrate how dynamic memory management is handled in C++ (e.g., allocation, deallocation, memory heap, run-time stack). Gain experience with pointers in C++ and their tradeoffs and risks (dangling pointers, memory leaks). Explain the difference between the complexity of a problem (sorting) and the complexity of a particular algorithm for solving that problem. Manipulate data in stacks, queues, and deques (irrespective of any implementation).
Linked Lists: an alternative to arrays Can you think of any limitations with the array data structure?
Another note on abstract Data Types (Public) interface specifications Language independent
Linked Lists: an alternative to arrays A Linked List is an abstract data type for representing lists as collections of linked items Instead of having an overall representation of the list, the ordering of the list is represented locally That is, the information about what element comes next in a list is stored as a pointer within the element object. No list object (element) knows about any other elements in the list, just the ones to which it is adjacent
Linked Lists: an abstraction This is a pictorial representation of a singly linked list Note that it is not necessarily represented contiguously in memory, nor in the order the elements occur in the list itself
Linked Lists: implementation Let s take a look at how this is represented in C++
struct hockey_player { int jersey_number; string name; hockey_player* next; };... hockey_player * head = NULL;... void insert(int num, string name) { hockey_player * temp; temp = new hockey_player; temp->jersey_number = num; temp->name = name; } temp->next = head; head = temp; }
Comparison of Worst Case Complexities (for n entries): Assume we have a head pointer (only) for the linked list below. (Later: would your answers change if we also had a tail pointer?) Operation Array Array Linked List Linked List (unordered) (ordered) (unordered) (ordered) Insert at start O(1) O(n) O(1) O(1) Insert at end O(1) O(1) O(1) O(1) Insert after current position O(1) O(n) O(1) O(1) Find (search for) a value O(n) O(n)/O(lgn) O(n) O(n) Delete at current position O(1) O(n) O(1) O(1)
Comparison of Worst Case Complexities (for n entries): Assume we have a head pointer (only) for the linked list below. (Later: would your answers change if we also had a tail pointer?) Operation Array Array Linked List Linked List (unordered) (ordered) (unordered) (ordered) Insert at start O(1) O(n) O(1) O(1) Insert at end O(1) O(1) O(1) O(1) Insert after current position O(1) O(n) O(1) O(1) Find (search for) a value O(n) O(n)/O(lgn) O(n) O(n) Delete at current position O(1) O(n) O(1) O(1)
Comparison of Worst Case Complexities (for n entries): Assume we have a head pointer (only) for the linked list below. (Later: would your answers change if we also had a tail pointer?) Operation Array Array Linked List Linked List (unordered) (ordered) (unordered) (ordered) Insert at start O(1) O(n) O(1) O(1) Insert at end O(1) O(1) O(1) O(1) Insert after current position O(1) O(n) O(1) O(1) Find (search for) a value O(n) O(n)/O(lgn) O(n) O(n) Delete at current position O(1) O(n) O(1) O(1)
Comparison of Worst Case Complexities (for n entries): Assume we have a head pointer (only) for the linked list below. (Later: would your answers change if we also had a tail pointer?) Operation Array Array Linked List Linked List (unordered) (ordered) (unordered) (ordered) Insert at start O(1) O(n) O(1) O(1) Insert at end O(1) O(1) O(1) O(1) Insert after current position O(1) O(n) O(1) O(1) Find (search for) a value O(n) O(n)/O(lgn) O(n) O(n) Delete at current position O(1) O(n) O(1) O(1)
Comparison of Worst Case Complexities (for n entries): Assume we have a head pointer (only) for the linked list below. (Later: would your answers change if we also had a tail pointer?) Operation Array Array Linked List Linked List (unordered) (ordered) (unordered) (ordered) Insert at start O(1) O(n) O(1) O(1) Insert at end O(1) O(1) O(1) O(1) Insert after current position O(1) O(n) O(1) O(1) Find (search for) a value O(n) O(n)/O(lgn) O(n) O(n) Delete at current position O(1) O(n) O(1) O(1)
Stacks A stack operates on the LIFO principle: Last In, First Out. Push and pop operations have real-life analogies: a stack of trays or plates in a cafeteria, Pez dispenser, etc. Software examples: supporting a Web browser s Back button, passing variables to functions, keeping track of function calls (e.g., recursion), storing local variables, etc. Some stack operations and their complexities: - push(item) (add to top) - pop() (take off top) - returntop() (without removing) - empty() (is stack empty?) - getsize() (how many in stack?)
A stack can be implemented using either an array or a linked list:
Queues A queue operates on the FIFO principle: First In, First Out Real-life analogies: line-up at a bank or supermarket Software examples: Web browser requests to a server Some queue operations and their complexities: - enqueue(item) - dequeue() - getfirst(item) (without removing) - empty() (is it empty?) - getsize() (how many?)
A queue can be implemented using either a circular array or a linked list:
Doubly-Linked Lists In what ways does a doubly-linked list differ from a singly-linked list, besides the presence of an extra pointer? What are the advantages and disadvantages?
Deques A deque (pronounced deck ) is a double-ended queue. It acts like a queue, but we can insert at either end, and remove from either end. Like a queue, a deque can be implemented using either an array or a linked list. It is really an abstraction of the queue and stack.
Learning Goals After this unit, you should be able to... Differentiate an abstraction from an implementation. Define and give examples of problems that can be solved using the abstract data types stacks, queues and deques. Compare and contrast the implementations of these abstract data types using linked lists and circular arrays in C++. Demonstrate how dynamic memory management is handled in C++ (e.g., allocation, deallocation, memory heap, run-time stack). Gain experience with pointers in C++ and their tradeoffs and risks (dangling pointers, memory leaks). Explain the difference between the complexity of a problem (sorting) and the complexity of a particular algorithm for solving that problem. Manipulate data in stacks, queues, and deques (irrespective of any implementation).