CSC 231: Introduction to Data Structures Queues, Deques, Lists Linked Lists
Linear Data Structures Chapter 3 What are the 4 Linear Structures? Stacks Queues Deques Lists
Summary of 4 Linear Structures Stack Add to top, remove from top - last in first out Queue Add to rear, remove from front – first in first out Deque Add to either end, remove from either end List Add anywhere, remove from anywhere visualgo.net/list
QUEUES
Queues: Basic Operators What should we visualize? Enqueue, dequeue
Applications of Queues Queues show up all over the place “in real life” Waiting in line Jobs sent to a printer Processes running on a cpu Queues are useful for simulating these real world events
How would we implement a queue in Python? We need to support Create an empty queue Enqueue to the “rear” Dequeue from the “front” Let’s suppose we use the list data structure to implement a queue. What is the front of a list? What is the rear?
Well, let’s decide the “front” of the queue is the rear of the list Dequeue is pop() Therfore, Enqueue is insert(0, item)
class Queue: def __init__(self): self class Queue: def __init__(self): self.items = [] def isEmpty(self): return self.items == [] def enqueue(self, item): self.items.insert(0,item) def dequeue(self): return self.items.pop() def size(self): return len(self.items)
What is the big O of each? Initializing (creating)? Enqueue? Dequeue?
Couldn’t we have chosen the front of the list is the first element Of course! Enqueue would be append(item) Dequeue would be pop(0, item)
class Queue: def __init__(self): self class Queue: def __init__(self): self.items = [] def isEmpty(self): return self.items == [] def enqueue(self, item): self.items.append(item) def dequeue(self): return self.items.pop(0) def size(self): return len(self.items)
What’s the big O? enqueue? dequeue? Which was the better implementation? Treat the last element as the “front”? Treat the first element as the “front”?
Deques Deque is pronounced “deck”. Add to either end, remove from either end
The Book’s Implementation class Deque: def __init__(self): self.items = [] def isEmpty(self): return self.items == [] def addFront(self, item): self.items.append(item) def addRear(self, item): self.items.insert(0,item) def removeFront(self): return self.items.pop() def removeRear(self): return self.items.pop(0) def size(self): return len(self.items) What is the big O of each method?
The book’s example of using a deque Checking a palindrome
Lists The book gives an unordered list And an ordered list What’s the difference? The methods we want to support: add, remove, search, isEmpty, length, append, index, insert, pop, pop(position)
The Linked List data type Items in the list are not constrained by their physical placement Items that are “next to” each other only figuratively, not literally Items are not stored contiguously in memory
The Visualization of a Linked List
Linked Lists consist of a sequence of Nodes A Node contains Data A link to the next node.
The Node class class Node: def __init__(self,initdata): self.data = initdata self.next = None def getData(self): return self.data def getNext(self): return self.next def setData(self,newdata): self.data = newdata def setNext(self,newnext): self.next = newnext
The UnOrdered List class UnorderedList: def __init__(self): self.head = None def isEmpty(self): return self.head == None def add(self,item): temp = Node(item) temp.setNext(self.head) self.head = temp
How do you find the length? def length(self): current = self.head count = 0 while current != None: count = count + 1 current = current.getNext() return count
How do you search? def search(self,item): current = self.head found = False while current != None and not found: if current.getData() == item: found = True else: current = current.getNext() return found
How do you remove? current = self.head previous = None found = False def remove(self,item): current = self.head previous = None found = False while not found: if current.getData() == item: found = True else: previous = current current = current.getNext() if previous == None: self.head = current.getNext() previous.setNext(current.getNext())
Unordered Linked List (Stack) Would the linked list class be a good data structure to implement a stack? Why or why not? Implement push and pop. What is the big-O of each?
Doubly-Linked Lists A node keeps track of What is next AND What is previous
What does a node look like? class DoublyLinkedNode: #constructor def __init__(self, value): self.data = value self.prev = None self.next = None
What does a doubly-linked list look like? class DoublyLinkedList: #constructor def __init__(self): self.head = None self.tail = None self.size = 0
How do you add to the list? To the front … or to the end def addFront(self, value): newNode = DoublyLinkedNode(value) if (self.size == 0): self.head = newNode self.tail = newNode self.size = 1 else: newNode.next = self.head self.head.prev = newNode self.size += 1 #what is the big O of this method?
Add to the end newNode = DoublyLinkedNode(value) if (self.size == 0): def addRear(self, value): newNode = DoublyLinkedNode(value) if (self.size == 0): self.head = newNode self.tail = newNode self.size = 1 else: newNode.prev = self.tail self.tail.next = newNode self.size += 1 #what is the big O of this method?
Remove from the front Remove from the rear def removeFront(self): value = self.head.data self.head = self.head.next if self.head != None: self.head.prev = None self.size -= 1 return value def removeRear(self): value = self.tail.data self.tail = self.tail.prev if self.tail != None: self.tail.next = None
Print (forward) def printItOut(self): temp = self.head while temp != None: print(temp.data,end=" ") temp = temp.next print()
Print (backward) def printInReverse(self): temp = self.tail while temp != None: print(temp.data, end=" ") temp = temp.prev print()
Retrieving a value at a particular index ''' Retrieve the item at index. def atIndex(self, index): count = 0 temp = self.head while count < index: count += 1 temp = temp.next return temp.data
Summary of 4 Linear Structures Questions: Can we implement these using a Doubly-Linked List? Stack Add to top, remove from top Queue Add to rear, remove from front Deque Add to either end, remove from either end List Add anywhere, remove from anywhere
Stack w/ Doubly Linked List class Stack: def __init__(self): self.stack = DoublyLinkedList() def push(self, item): self.stack.addFront(item) def pop(self): return self.stack.removeFront() def size(self): return self.stack.size
(Reminder) Queue w/ List (Big-O??) class Queue: def __init__(self): self.items = [] def isEmpty(self): return self.items == [] def enqueue(self, item): self.items.insert(0,item) def dequeue(self): return self.items.pop() def size(self): return len(self.items)
Queue w/ Doubly Linked List (Big O?) from DoublyLinkedList import * class Queue: def __init__(self): self.queue = DoublyLinkedList() def isEmpty(self): return self.queue.size == 0 def enqueue(self, item): self.queue.addRear(item) def dequeue(self): return self.queue.removeFront() def size(self): return self.queue.size
Reminder: Deque w/ List (Big O?) class Deque: def __init__(self): self.items = [] def isEmpty(self): return self.items == [] def addFront(self, item): self.items.append(item) def addRear(self, item): self.items.insert(0,item) def removeFront(self): return self.items.pop() def removeRear(self): return self.items.pop(0) def size(self): return len(self.items)
Deque w/ Doubly Linked List class Deque: def __init__(self): self.deque = DoublyLinkedList() def isEmpty(self): return self.deque.size == 0 def addFront(self, item): self.deque.addFront(item) def addRear(self, item): self.deque.addRear(item) def removeFront(self): return self.deque.removeFront() def removeRear(self): return self.deque.removeRear() def size(self): return self.deque.size
How about a list where you can insert or remove from any index? What is the big O of finding an element at a particular index with a doubly-linked list? Once you have found it, what is the big-O of deleting?
Using a Singly-Linked List Using a Doubly-Linked List Summary Using a Python List Using a Singly-Linked List Using a Doubly-Linked List Stack Push O(1) Pop Queue Enqueue O(n) O(1)* Dequeue Deque AddFront AddRear RemoveFront RemoveRear List Add/Remove End O(1)/O(n) Add/Remove Front Add/Remove index k Get at index k