0% found this document useful (0 votes)
19 views53 pages

C175 09 W21 LinkedLists

This document provides an overview of singly-linked lists and doubly-linked lists. It discusses the objectives of learning about linked list implementations and their nodes and elements. Diagrams are presented to illustrate external and internal representations of lists, including nodes that contain elements and links to other nodes. Code examples in Python demonstrate classes for list nodes and the overall linked list. Key methods for the interfaces of nodes and lists are also outlined.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
19 views53 pages

C175 09 W21 LinkedLists

This document provides an overview of singly-linked lists and doubly-linked lists. It discusses the objectives of learning about linked list implementations and their nodes and elements. Diagrams are presented to illustrate external and internal representations of lists, including nodes that contain elements and links to other nodes. Code examples in Python demonstrate classes for list nodes and the overall linked list. Key methods for the interfaces of nodes and lists are also outlined.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 53

CMPUT 175 (W21)

Singly-Linked Lists and


Doubly-Linked Lists

You should view the vignette:


Linked Lists

Post-test
Objectives
Learn about an implementation of Lists called
a Singly-Linked List
We will first draw lists and discuss them
We will then create a class for elements of
a list, and a class for the list itself

Repeat the process for a Doubly-Linked List

March 3, 2021 © Osmar R. Zaïane : University of Alberta In collaboration with Duane Szafron 2
External Container Diagrams
We can draw an external or
implementation-independent diagram of
a container by just showing its elements.

For example, here is the diagram for a


general container where the elements
are not even ordered:

"Fred"
"Wilma"
"Barney"

March 3, 2021 © Osmar R. Zaïane : University of Alberta 3


Indexed Container Diagram
We can modify the diagram when the
interface is more specific.
For example, here is a diagram for an
indexed container:
0 1 2

"Fred" "Wilma" "Barney"

Note that it still might be implemented in


different ways
March 3, 2021 © Osmar R. Zaïane : University of Alberta 4
External List Diagrams
Since the elements in a list are ordered,
they must be “connected” somehow to
maintain this order.
Since different implementation classes
“connect” the elements differently, we do
not show the connections in an external
diagram.
"Fred" "Wilma" "Barney"

March 3, 2021 © Osmar R. Zaïane : University of Alberta 5


Internal List Diagrams - Nodes
However, when we want to highlight a particular class
implementation of a List, we add internal structure.
Each element is put in a list node and the nodes connect to
each other with links.
The end of the list is denoted by a dot instead of a link to
another node.
“Fred” “Wilma” “Barney”
“Fred” “Wilma” “Barney”
Instead of a dot, it can be represented as a link going
nowhere, sometimes called Nil, Null, or None.

“Fred” “Wilma” “Barney”


March 3, 2021 © Osmar R. Zaïane : University of Alberta 6
Links and Nodes

Where are these nodes placed?

What are these links from one node to the


other?

What can the content of these nodes be?

“Fred” “Wilma” “Barney”

March 3, 2021 © Osmar R. Zaïane : University of Alberta 7


1 Byte = 8 bits = one character
1 Kilobyte KB = 1024 bytes about 1000 bytes
1 Megabyte MB = about 1000 Kilobyte
1 Gigabyte GB = 1000 MB = about a billion bytes
1 Terabyte TB = 1000 GB

Computer Memory
List RAM: Random Access Memory
[“Fred”, 175, True, 2.77]
Float
Integer 3.14
175 String
Object “Hello”
“Fred” Character
8/14/1976 ‘z’

March 3, 2021 © Osmar R. Zaïane : University of Alberta 8


00 01 02 03 04 05 06 07 08 09 0A 0B 0C0D0E 0F 10 11 12 13 14 15 16 17 18 19 1A1B 1C1D 1E 1F 20 21 22 23 24 25 26
01
02
03
04
05
06
07
08
09
0A
0B
0C
0D
0E 0F12
0F
10
11
12
13 1420
14
15
16
17
18
19
1A
1B
1C
1D
Character
c Long Integer
20170301
Integer
175

Array of 10 Integers
101 175 272 ? ? ? ? ? ? ?

272

272

101 175

175
101
175 P a u l

272

272 Al i
101 C l a ude

175
101
Complex List Node Diagrams
If the elements of a list are complex objects, it is
not always possible to draw the elements inside
the node.
In this case, an arrow is used in the node to
represent a reference to the element.
This diagram is actually more accurate since the
node always contains a reference to an object
instead of an object.

“Fred”
8/14/1976
March 3, 2021 © Osmar R. Zaïane : University of Alberta 12
Terminology: Elements & Nodes
In these notes we use the term element
to refer to the individual values or objects
that collectively make up the list.

We use the term node to refer to an


object that contains an element object
and links to adjacent list nodes.

node
element “Fred”
8/14/1976
March 3, 2021 © Osmar R. Zaïane : University of Alberta 13
Singly-Linked Lists
“Fred”
8/14/1976

In a singly-linked list, each list node contains an


element and a link to the “next” node in the list.
element

Since a node contains a link to the next node,


this is an example of self-referencing of objects.
It points to another instance of the same class.
We need to define two classes to implement a
singly-linked list: one for the nodes and one for
the list itself.

We will call the first one SLinkedListNode and


the second SLinkedList
March 3, 2021 © Osmar R. Zaïane : University of Alberta 14
SLinkedListNode Class
Each instance of SLinkedListNode represents a
single list node with two instance variables.
The instance variable, data, is a reference to an
element object.
The instance variable, next, is a reference to the
next node (another instance of SLinkedListNode)
or None if it is the last node (tail node).
SLinkedListNode None

data next
“Fred” “Wilma” “Barney”
8/14/1976 10/14/1979 3/10/1978
March 3, 2021 © Osmar R. Zaïane : University of Alberta 15
Interface for ADT: Node
setData(element) - set element as the new data
setNext(reference) - set reference as the new next
getData() - returns the data element
getNext() - returns the reference to the next node

getData() getNext()

data next

setData() setNext()

March 3, 2021 © Osmar R. Zaïane : University of Alberta 16


SLinkedListNode in Python
class SLinkedListNode:
def __init__(self, initData, initNext):
# constructs a new node and initializes it to contain
# the given object (initData) and link to the given next node.
self.data = initData
self.next = initNext

def getData(self): # returns the element


return self.data
def getNext(self): # returns the next node
return self.next
def setData(self, newData): # sets the newData as the element
self.data = newData
def setNext(self, newNext): # sets the newNext as the next node
self.next= newNext

March 3, 2021 © Osmar R. Zaïane : University of Alberta 17


Interface for ADT: List
add(item) - adds a new item to the list
remove(item) - removes the item from the list
search(item) - returns a boolean value if item in list
isEmpty() - tests to see whether the list is empty
length() - returns the number of elements in the list
append(item) - adds item to the end of list
index(item) - returns the position of item in the list
insert(pos,item) - adds an item at a given position in list
pop() - removes and returns the last item
pop(pos) - removes and returns the item at a position
March 3, 2021 © Osmar R. Zaïane : University of Alberta 18
SLinkedList Class
Each SLinkedList object has an instance
variable, head, that is a reference to the first
SLinkedListNode object of the list.
It also maintains an integer valued instance
variable, size, that is the size of the list.
SLinkedList
size head
3

“Fred” “Wilma” “Barney”


March 3, 2021 © Osmar R. Zaïane : University of Alberta 19
Why Cache the List Size?
The list size could be computed by traversing
the list and counting nodes.

However, the size is cached as an instance


variable so that the length() method can be
computed faster.

The disadvantage of caching the size as an


instance variable is that the instance variable
must be updated each time an element is
added or removed from the list.

March 3, 2021 © Osmar R. Zaïane : University of Alberta 20


List Traversal
Many list methods will involve traversal of the
list elements from the head to the tail, or from
the head to a particular element or location.
We use a cursor (called current) for traversal.
3 “Fred” “Wilma” “Barney”

current current = self.head


3 “Fred” “Wilma” “Barney”

current current = current.getNext()


3 “Fred” “Wilma” “Barney”
current = current.getNext() current
None
3 “Fred” “Wilma” “Barney”
current = current.getNext() current

March 3, 2021 © Osmar R. Zaïane : University of Alberta 21


SLinkedList in Python
class SLinkedList:
def __init__(self):
self.head=None
self.size=0

def isEmpty(self):
return self.head == None

def length(self):
return self.size
def length(self):
current = self.head
count = 0
while current != None:
If we do not cache the size count = count + 1
we could traverse the list current = current.getNext()
and count the elements
return count

March 3, 2021 © Osmar R. Zaïane : University of Alberta 22


Converting to a String
Before we see the implementations of the other
methods in the public interface, we can see how to
convert the list to allow it to be printed.
def __str__(self):
We simply s= '['
traverse the i=0
current=self.head
list and build while current != None:
a string that if i>0:
s = s + ','
contains the dataObject = current.getData()
elements and s = s + "%s" % dataObject
put them in i = i + 1
current = current.getNext()
between “[“ s = s + ']'
and “]” return s

March 3, 2021
SLinkedList – add(item)
def add(self, item):
# adds an item to list at the beginning We could
temp = SLinkedListNode(item,None)
also have
temp.setNext(self.head) done the
self.head = temp following:
self.size += 1
def add(self, item):

temp = SLinkedListNode(item,self.head)
self.head = temp
add(“Fred”) self.size += 1
size head
2 3 “Wilma” “Barney”
Step 1: construct a node with “Fred”
Step 2: link the next of this node to what head points to
“Fred” Step 3: head is now pointing to this new node
Step 4: update size
March 3, 2021 © Osmar R. Zaïane : University of Alberta 24
SLinkedList – search(item)
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

search(“Wilma”)
3 “Fred” “Wilma” “Barney”

current current = self.head


3 “Fred” “Wilma” “Barney”

current current = current.getNext()


current.getData == “Wilma”
March 3, 2021 © Osmar R. Zaïane : University of Alberta 25
SLinkedList – index(item)
def index(self, item):
# searches for the item and returns its order
# number(index). Returns -1 if item doesn’t exist
current = self.head
found = False
index = 0
while current != None and not found:
if current.getData() == item:
found = True
else:
current = current.getNext()
index = index + 1
if not found:
index = -1
return index
index(“Wilma”) current current = self.head index 0
3 “Fred” “Wilma” “Barney”

3 “Fred” “Wilma” “Barney”


current = current.getNext()
index = index + 1 current index 1
March 3, 2021 © Osmar R. Zaïane : University of Alberta 26
SLinkedList – remove(item)
def remove(self, item): remove(“Fred”)
# searches for the item and removes it 32
# the method assumes the item exists
current = self.head Fred Wilma Barney
previous=None
found = False current previous
while not found:
if current.getData() == item: remove(“Wilma”)
found = True 32
else:
previous = current Fred Wilma Barney
current = current.getNext()
if previous == None: previous current
self.head = current.getNext()
else: remove(“Barney”)
previous.setNext(current.getNext())
self.size -= 1 32
Fred Wilma Barney
initially
previous None current previous current

3 “Fred” “Wilma” “Barney” None

March 3, 2021 © Osmar R. Zaïane : University of Alberta 27


SLinkedList – append(item)
def append(self, item):
# adds the item to the end of the list
# must traverse the list to the end and add item
temp = SLinkedListNode(item, None)
if (self.head == None):
self.head=temp
else:
current = self.head;
while (current.getNext() != None):
current = current.getNext()
current.setNext(temp)
self.size +=1

append(“Pebbles”)
3
4 current temp “Pebbles”

“Fred” “Wilma” “Barney”


March 3, 2021 © Osmar R. Zaïane : University of Alberta 28
pop() = Removal from Tail
We cannot remove from the tail by just traversing to
the last node and removing it.

We need a reference to the second last node so we


can set its “next” reference to None.
3 “Fred” “Wilma” “Barney”

current

3 “Fred” “Wilma” “Barney”

previous.setNext(None); previous current


None

To find the second last node, we need to traverse the


list with a second cursor following the first.

March 3, 2021 © Osmar R. Zaïane : University of Alberta 29


SLinkedList – pop()
def pop(self):

current = self.head
previous = None
while (current.getNext() != None):
previous = current
current = current.getNext()

if (previous == None):
self.head = None
else:
previous.setNext(None)
self.size -= 1
return current.getData()

3
2 previous current
None

“Fred” “Wilma” “Barney”


March 3, 2021 © Osmar R. Zaïane : University of Alberta 30
SLinkedList - Remaining Methods

insert(pos,item) - adds an item at a given position in list


pop(pos) - removes and returns the item at a position

Left as an exercise
There could be other methods such as
peek(), clear(), etc.

March 3, 2021 © Osmar R. Zaïane : University of Alberta 31


Linked-List Implementation
Advice
When manipulating references, draw
pictures.

Every public method of an object should


leave the object in a consistent state.

Test the boundaries of your structures and


methods.

March 3, 2021 © Osmar R. Zaïane : University of Alberta 32


Linked List for MAZE
Recall the problem of MAZE traversal from one of the earlier
classes.
We will show here how neighboring positions can be stored
using a Linked List.
0 : {1}
S 1 : {0, 2, 6}
0 5 4
2 : {1, 3}
3 : {2, 4}
1 2 3 4 : {3, 5}
5 : {4}
6 : {1, 7, 10}
6 7 8
7 : {6, 8}
8 : {7, 9}
10 11 9 9 : {8}
F
10 : {6, 11}
11 : {10}

March 3, 2021 © Osmar R. Zaïane : University of Alberta 33


Creating an Adjacency List of Linked Lists
adj 0 NONE
First create an array of null pointers: 1 NONE
2 NONE
adj = [] 3 NONE

for i in range(12): #create 0..11 empty lists 4 NONE


5 NONE
adj.append(None) S0 5 4
6 NONE
7 NONE
1 2 3
adj 0 1 8 NONE
1 0 2 6 6 7 8 9 NONE
2 1 3 10 NONE
10 11 9
3 2 4 F 11 NONE
4 3 5
5 4
6 1 7 10

Next create linked


7 6 8
8 7 9
9 8
lists of legal positions
10 6 11 that are adjacent to
11 10
each position.
March 3, 2021 © Osmar R. Zaïane : University of Alberta 34
Creating an Adjacency List of Linked Lists

We also need an array “visited” to store whether a


state has been visited already

visited = []
for i in range(12): #initialize to False, True when visited
visited.append(False)

March 3, 2021 © Osmar R. Zaïane : University of Alberta 35


Solving MAZE Problem with
Adjacency List & Stack
With an Adjacency List, the order in which we select
the Next Position to Visit depends on the order in
which the Positions appear in an adjacency list.
Recall that with a Stack we go as deep as possible
(Depth First) before backing up. The sequence to
Depth First Paths we take depends on the order of
nodes in the adjacency lists.
The advantage of the linked list is to insert elements
in the beginning of the list in constant time.

March 3, 2021 © Osmar R. Zaïane : University of Alberta 36


Doubly-Linked List Diagrams
A doubly-linked list node has two links, one
forward and one backward.
The doubly-linked list has references to its head
and tail nodes.
This symmetry makes the implementation
simpler.
size head tail
3

“Fred” “Wilma” “Barney”

March 3, 2021 © Osmar R. Zaïane : University of Alberta 37


Constructing a Node
When a DoublyLinkedListElement (node) is
constructed, four links may need to be set.
“Wilma”
3 1
4 2
“Fred” “Barney”

If one or both of the “neighbouring” nodes is


Null, then fewer links must be set.
“Wilma”
3 1
2
None “Barney”
March 3, 2021 © Osmar R. Zaïane : University of Alberta 38
DLinkedListNode in Python
class DLinkedListNode:
def __init__(self, initData, initNext, initPrevious):
# constructs a new node and initializes it to contain
# the given object (initData) and links to the given next
# and previous nodes.
self.data = initData
self.next = initNext
self.previous = initPrevious

if (initPrevious != None): better practice to use:


initPrevious.next = self initPrevious.setNext(self)
if (initNext != None): better practice to use:
initNext.previous = self
initNext.setPrevious(self)

self.previous self self.next


someData initData otherData
The new node
March 3, 2021 © Osmar R. Zaïane : University of Alberta 39
DLinkedListNode in Python
def getData(self):
return self.data

def getNext(self):
return self.next

def getPrevious(self):
return self.previous

getData() getPrevious()
def setData(self, newData):
self.data = newData
setNext() data next getNext()
def setNext(self, newNext):
self.next= newNext previous

def setPrevious(self, newPrevious):


self.previous= newPrevious setPrevious() setData()

March 3, 2021 © Osmar R. Zaïane : University of Alberta 40


DLinkedList in Python
class DLinkedList:
def __init__(self):
self.head=None
self.tail=None
self.size=0

self.head == None

def isEmpty(self):
return self.size == 0
def length(self):
return self.size

March 3, 2021 © Osmar R. Zaïane : University of Alberta 41


DLinkedList – search(item)
def search(self, item):
current = self.head
found = False
while current != None and not found:
if current.getData() == item: Identical to the
found= True search method for
else: SLinkedList
current = current.getNext()

return found

“Fred” “Wilma” “Barney”

March 3, 2021 © Osmar R. Zaïane : University of Alberta 42


DLinkedList – search(item)
def search(self, item):
current = self.tail
found = False
while current != None and not found:
if current.getData() == item: Identical to the
found= True search method for
else: SLinkedList
current = current.getPrevious()

return found
Note that we could also
start the traversal from
the tail and use
3 previous

“Fred” “Wilma” “Barney”

March 3, 2021 © Osmar R. Zaïane : University of Alberta 43


DLinkedList – index(item)
def index(self, item):
current = self.head
found = False
index = 0
while current != None and not found:
Identical to the
if current.getData() == item:
found= True index method for
else: SLinkedList
current = current.getNext()
index = index + 1
if not found:
index = -1
return index

“Fred” “Wilma” “Barney”


March 3, 2021 © Osmar R. Zaïane : University of Alberta 44
DLinkedList – index(item)
def index(self, item):
current = self.tail
found = False
index = self.size - 1
while current != None and not found:
Identical to the
if current.getData() == item:
found= True index method for
else: SLinkedList
current = current.getPrevious()
index = index - 1
if not found:
index = -1 Note that we could also
return index start the traversal from
the tail and use
previous
3

“Fred” “Wilma” “Barney”


March 3, 2021 © Osmar R. Zaïane : University of Alberta 45
DLinkedList – add(item)
def add(self, item):
# adds an item to list at the beginning

temp = DLinkedListNode(item, self.head, None)


if self.head != None: # there is a head
self.head.setPrevious(temp)
else: # adding to empty list
self.tail=temp
self.head = temp
self.size += 1
add(“Fred”) Step 1: construct a new node with “Fred”
Step 2: make the previous of old head to point
to new node if the list isn’t empty otherwise
the tail should point to the new node
head tail Step 3: head is now pointing to this new node
size
Step 4: update size
“Fred” 2 3

“Wilma” “Barney”
March 3, 2021 © Osmar R. Zaïane : University of Alberta 46
DLinkedList – add(item)
def add(self, item):
# adds an item to list at the beginning

temp = DLinkedListNode(item, self.head, None)


if self.head != None: # there is a head
self.head.setPrevious(temp)
else: # adding to empty list
self.tail=temp
self.head = temp
self.size += 1
add(“Fred”) Step 1: construct a new node with “Fred”
Step 2: make the previous of old head to point
to new node if the list isn’t empty otherwise
the tail should point to the new node
head tail Step 3: head is now pointing to this new node
size
Step 4: update size
“Fred” 0 1

March 3, 2021 © Osmar R. Zaïane : University of Alberta 47


DLinkedList – remove(item)
def remove(self, item):
# search for the item and remove it
# the method assumes the item exists
# Traverse the list from head to search for item
# If first node, adjust the head to be the next
H . item …
# If not first node, make the previous to point to next
… item …
# If not last node, make the next to point to previous
… item …
# If last node, adjust the tail to be the previous
T … item .
# Reduce size by 1
remove(“Wilma”) 3

“Fred” “Wilma” “Barney”


March 3, 2021 © Osmar R. Zaïane : University of Alberta 48
DLinkedList – remove(item)
def remove(self, item):
# search for the item and remove it
# the method assumes the item exists
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: # removing first node
self.head = current.getNext()
else:
previous.setNext(current.getNext())
if (current.getNext() != None):
current.getNext().setPrevious(previous)
else : # removing last node
self.tail=previous
self.size -= 1
remove(“Wilma”) 32

“Fred” “Wilma” “Barney”


March 3, 2021 © Osmar R. Zaïane : University of Alberta 49
DLinkedList – append(item)
def append(self, item):
# adds the item to the end of the list
temp = DLinkedListNode(item, None, None)
if (self.head == None):
self.head=temp
else:
self.tail.setNext(temp)
temp.setPrevious(self.tail)
self.tail=temp
self.size +=1 There is no need for traversal

append(“Pebbles”)
34 temp “Pebbles”

“Fred” “Wilma” “Barney”


March 3, 2021 © Osmar R. Zaïane : University of Alberta 50
DLinkedList – Remaining Methods
insert(pos,item) - adds an item at a given position in list
pop() - removes and returns the last item
pop(pos) - removes and returns the item at a position

Left as an exercise
Try to adapt the methods from SLinkedList Class

March 3, 2021 © Osmar R. Zaïane : University of Alberta 51


Recall Unbounded Queue
Rear at position 0. Front at position 0.
enqueue Rear Front dequeue dequeue Front Rear enqueue
… …
0 n 0 n

dequeue operation is O(1) dequeue operation is O(n)


enqueue operation is O(n) enqueue operation is O(1)

There is a more efficient implementation of the


ADT queue that allows adding and removing
element with O(1): Doubly-Linked-List

March 3, 2021 © Osmar R. Zaïane : University of Alberta 52


Implement Queue with a
Doubly-Linked List
Dequeue at the head: O(1) Enqueue at the tail: O(1)
Queue
dequeue
3 enqueue

10 240 75

No need for shifting elements O(1) regardless of size of queue

March 3, 2021 © Osmar R. Zaïane : University of Alberta 53

You might also like