0% found this document useful (0 votes)
5 views651 pages

File 3

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)
5 views651 pages

File 3

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/ 651

1 : Introduction to Data Structures

IT3206 – Data Structures and Algorithms

Level II - Semester 3

© e-Learning Centre, UCSC


Overview

• This course module section provides fundamental


knowledge in the application of different data structures
and Algorithms.

© e-Learning Centre, UCSC 2


Intended Learning Outcomes

• At the end of this lesson, you will be able to;


• Explain the use of data structures

• Demonstrate different implementation techniques of


data structures

• Compare different applications of data structures

© e-Learning Centre, UCSC 3


List of subtopics

1. Introduction to data structures


1. Introduction to data structures [Ref 3:pg.9, Ref
1:pg.230 ]
2. Use of Data Structures [Ref 3:pg.10-11]
1. Real- world data storage [Ref 3:pg.10-11]
2. Programmer’s Tools [Ref 3:pg.11]
3. Real-world Modeling [Ref 3:pg.11]
3. Overview of Data Structures [Ref 3:pg.11-12]
4. Classification of Data Structures [Ref 4:pg.18]

© e-Learning Centre, UCSC 4


1.1 Introduction to data structures

• A data structure is an arrangement of data in a computer’s


memory or disk.
• Algorithms manipulate the data in the data structure such as
searching for a particular data item, sorting the data etc.
• Data structures include arrays, linked lists, queues, stacks,
binary trees, and hash tables etc.
• Examples

Array

Linked list

© e-Learning Centre, UCSC 5


1.1 Introduction to data structures cont.

Queue

Stack

© e-Learning Centre, UCSC 6


1.2 Use of Data Structures

The use of data structures can be studied mainly in these


three categories:
• Real-world data storage
• Programmer’s tools
• Real-world modeling

© e-Learning Centre, UCSC 7


1.2.1 Real-world data storage

• Many of the structures and techniques considered here are


about how to handle real-world data storage.
• Real-world data mean that the data that describes physical
entities external to the computer.

Examples:
• A personnel record describes an actual human being.
• An inventory record describes an existing car part or
grocery items.
• Financial transaction record describes an actual check
written to pay the electric bill.

© e-Learning Centre, UCSC 8


1.2.1 Real-world data storage cont.

• A stack of index cards can be considered as a non-


computer related example of real-world data storage.

• These cards can be used for a variety of purposes.


• If each card holds a person's name, address, and
phone number, the result is an address book.
• If each card holds the name location, and value of a
household possession, the result is a home inventory.

© e-Learning Centre, UCSC 9


1.2.1 Real-world data storage cont.

• Most programs are more complex than index cards.


• Imagine the database the Department of Motor Vehicles
uses to keep track of drivers’ licenses, or an airline
reservations system that stores passenger and flight
information.
• Such systems may include many data structures.

© e-Learning Centre, UCSC


10
1.2.2 Programmer’s Tools

• Not all data storage structures are used to store real-world


data.
• Typically, real-world data is accessed more or less directly by
the users of some programs.
• Some data storage structures, however, are not meant to be
accessed by the user, but by the program itself.
• A programmer uses such structures as tools to facilitate
some other operation.

Examples: Stacks, queues, and priority queues are often used


in this way

11
© e-Learning Centre, UCSC
1.2.3 Real-world Modeling

• Some data structures directly model real-world situations.

Examples
• evaluation of mathematical expressions
• Queue of print jobs to the printer
• Queue of programs/process to be run
• Queue of network data packets to be send
• Graphs to represent airline routes between cities or
connections in an electric circuit or tasks in a project.
• Queues to model customers waiting in line at a bank or
cars waiting at a toll booth.

© e-Learning Centre, UCSC 12


1.3 Overview of Data Structures

• Another way to look at data structures is to focus on their


strengths and weaknesses.
• Following is a bird’s-eye view of a landscape that we’ll be
covering later at ground level, so don’t be alarmed if the
terms used are not familiar.
Data Structure Advantages Disadvantages

Array Quick insertion, Fast access if Slow search


index known Slow deletes
Fixed size

Ordered Array Quicker search than Slow inserts


unsorted array Slow deletes
Fixed size

Stack Last-in, first-out acces Slow access to other items

Queue First-in, first-out access Slow access to other items

Linked List Quick insertion, quick deletion Slow search


© e-Learning Centre, UCSC
13
1.3 Overview of Data Structures cont.

Data Structure Advantages Disadvantages

Binary Tree Quick search Deletion algorithm is complex


Quick insertion
Quick deletion
(If the tree remains balanced)

Red-Black Tree Quick search Implementation is complex


Quick insertion
Quick deletion
(Tree always remains
balanced)

2-3-4 Tree Quick search Implementation is complex


Quick insertion
Quick deletion
(Tree always remains
balanced)
(Similar trees good for disk
storage)

© e-Learning Centre, UCSC


14
1.3 Overview of Data Structures cont.

Data Structure Advantages Disadvantages

Hash Table Very fast access if key is Slow deletion


known Access slow if key is not
Quick inserts known
Inefficient memory usage

Heap Quick insertion Slow access to other items


Quick deletion
Quick access to largest item

Graph Models real-world Some algorithms are slow and


situations complex

© e-Learning Centre, UCSC


15
1.4 Classification of Data Structures

• A data structure is a special format for organizing and


storing data.
• Depending on the organization of the elements, data
structures are classified into two types:

1. Linear data structures: Elements are accessed in a


sequential order but it is not compulsory to store all
elements sequentially.

Examples:
Arrays, Linked Lists, Stacks and Queues.

2. Non – linear data structures: Elements of this data


structure are stored/accessed in a non-linear order.

Examples: Trees and graphs.


© e-Learning Centre, UCSC
16
Summary

Real-world data mean that the data that


1.2.1 describes physical entities external to the
computer.

A programmer uses data structures as tools


1.2.2 to facilitate the required operations.

Some data structures directly model real-


1.2.3 world situations.

© e-Learning Centre, UCSC 17


2 : Arrays and Linked Lists

IT 3206– Data Structures and Algorithms

Level II - Semester 3

© e-Learning Centre, UCSC


Overview

• This section will illustrate how arrays are defined, declared,


initialized, and accessed.
• It will also discuss the different operations that can be
performed on array elements.
• Further this section will discuss about different types of
linked lists and the operations that can be performed on
these lists.

© e-Learning Centre, UCSC 2


Intended Learning Outcomes

• At the end of this lesson, you will be able to;


• Explain the use of Arrays and Linked Lists.
• Compare the difference between Arrays and Linked Lists
• Apply Arrays and Linked Lists for problem solving

© e-Learning Centre, UCSC 3


List of subtopics

2.1 Introduction to Arrays


2.1.1 One dimensional arrays
2.1.2 Multi dimensional arrays
2.1.3 Basic operations on arrays
2.2 Comparison of Arrays and Linked Lists
2.3 Singly Linked Lists
2.4 Doubly Linked Lists
2.5 Circular Linked Lists
2.6 Skip Lists

© e-Learning Centre, UCSC 4


2.1 Introduction to Arrays

• An array is a data structure that contains a group of


elements.
• Arrays are used to store multiple values in a single variable,
instead of declaring separate variables for each value
• Array is the simplest data structure where each data element
can be randomly accessed by using its index number
• Typically, these elements are all same data type, such as an
integer or string.
• Arrays are commonly used in computer programs to
organize data so that a related set of values can be easily
sorted or searched.

© e-Learning Centre, UCSC 5


2.1 Introduction to Arrays

• In Java, the array is not a primitive type. Instead, it behaves


very much like an object.
• Thus, many of the rules for objects also apply to arrays.
• One memory block is allocated for the entire array to hold
the elements of the array.
• The array elements can be accessed in constant time by
using the index of the particular element as the subscript.

© e-Learning Centre, UCSC 6


2.1.1 One dimensional arrays

• Array Representation

© e-Learning Centre, UCSC 7


2.1.1 One dimensional arrays

• Array Representation

• Arrays are indexed starting at zero.


• Array declaration
int[] intArray; // defines a reference to an array
intArray = new int[100]; // creates the array, and sets intArray to
refer to it
• Or you can use the equivalent single-statement approach:
int[] intArray = new int[100];
• You can also use an alternative syntax for [ ] operator, placing it after
the name instead of the type:
int intArray[] = new int[100]; // alternative syntax

© e-Learning Centre, UCSC 8


2.1.1 One dimensional arrays

• Example for declaring an array variable myList with 10


elements of double type
double[] myList = new double[10];

[dotibieQ myList = mew doubte[10ji|


myList |referenceÿ
5.6

t
Amy reference
variable
myList(0]
myLutfl]
myLLst[2)
myList(3] 13.2
4.5
3.3

myList(4j 4
Array element at,
index 5 myListf 5] 34.33 4 Element value
myLiit(6] 34
myUst(7j 45.45
myList(S) 99.993

myList(9] 11123

© e-Learning Centre, UCSC


I
9
2.1.1 One dimensional arrays cont.

• Accessing Array Elements


• Array elements are accessed using an index number in
square brackets.
temp = intArray[3]; // get contents of fourth element
of array
intArray[7] = 66; // insert 66 into the eighth cell
• Remember that in Java, as in C and C++, the first
element is numbered 0, so that the indices in an array of
10 elements run from 0 to 9.
• If you use an index that’s less than 0 or greater than the
size of the array less 1, you’ll get the Array Index Out of
Bounds runtime error.

© e-Learning Centre, UCSC 10


2.1.1 One dimensional arrays cont.

• Initialization
• Say you create an array of objects like this:
autoData[] carArray = new autoData[4000];
• Until the array elements are given explicit values, they
contain the special null object.
• You can initialize an array of a primitive type to
something besides 0 using this syntax:
int[] intArray = { 0, 3, 6, 9, 12, 15, 18, 21, 24, 27 };
• this single statement takes the place of both the
reference declaration and the use of new to create
the array.
• The numbers within the curly brackets are called the
initialization list.
• The size of the array is determined by the number of
values in this list.
© e-Learning Centre, UCSC 11
2.1.1 One dimensional arrays cont.

• An Example for printing elements in an array


class ArrayApp
{
public static void main(String[] args)
{
long[] arr; // reference to array
arr = new long[100]; // make array
int nElems = 0; // number of items
int j; // loop counter

//--------------------------------------------------------------
arr[0] = 77; // insert 10 items
arr[1] = 99;
arr[2] = 44;

© e-Learning Centre, UCSC 12


2.1.1 One dimensional arrays cont.

arr[3] = 55;
arr[4] = 22;
arr[5] = 88;
arr[6] = 11;
arr[7] = 00;
arr[8] = 66;
arr[9] = 33;
nElems = 10; // now 10 items in array
//--------------------------------------------------------------
for(j=0; j<nElems; j++) // display items
System.out.print(arr[j] + “ “);
System.out.println(“”);

© e-Learning Centre, UCSC 13


2.1.2 Multi dimensional arrays

• Sometimes arrays need to be accessed by more than one


index.
• In Java and Java Programming languages, we can create an
array of arrays. These arrays are known as multidimensional
arrays.
• A multidimensional array is an array that is accessed by
more than one index.
• A common example of this is a matrix.
• It is allocated by specifying the size of its indices, and each
element is accessed by placing each index in its own pair of
brackets.

© e-Learning Centre, UCSC 14


2.1.2 Multi dimensional arrays

• For example
int[][] a = new int[3][4];

Here, we have created a multidimensional array named a. It is a 2-


dimensional array, that can hold a maximum of 12 elements.

You can think the array as a table with 3 rows and each row has 4 columns.
© e-Learning Centre, UCSC 15
2.1.2 Multi dimensional arrays cont.

• An example to print the contents of a two-dimensional


public class MatrixDemo
{
public static void printMatrix( int [ ][ ] m )
{
for( int i = 0; i < m.length; i++ )
{
if( m[ i ] == null )
System.out.println( "(null)" );
else
{
for( int j = 0; j < m[i].length; j++ )
System.out.print( m[ i ][ j ] + " " );
System.out.println( );
}
}
}

© e-Learning Centre, UCSC 16


2.1.2 Multi dimensional arrays cont.

public static void main( String [ ] args )


{
int [ ][ ] a = { { 1, 2 }, { 3, 4 }, { 5, 6 } };
int [ ][ ] b = { { 1, 2 }, null, { 5, 6 } };
int [ ][ ] c = { { 1, 2 }, { 3, 4, 5 }, { 6 } };

System.out.println( "a: " ); printMatrix( a );


System.out.println( "b: " ); printMatrix( b );
System.out.println( "c: " ); printMatrix( c );
}
}

© e-Learning Centre, UCSC 17


2.1.3 Basic operations on arrays

• Insertion
• Inserting an item into the array is easy; we use the normal array syntax:
arr[0] = 77;
• We also keep track of how many items we’ve inserted into the array

Algorithm for inserting an element in the end of the array

Add new
element
here
Upper
bound
Step 1: Set upper_bound = upper_bound + 1
Step 2: Set A[upper_bound] = VAL
Step 3: EXIT

© e-Learning Centre, UCSC 18


2.1.3 Basic operations on arrays

Algorithm for inserting element in the middle of the array

INSERT (A, N, POS, VAL).


• A - the array in which the element has to be inserted
• N - the number of elements in the array
• POS - the position at which the element has to be inserted
• VAL - the value that has to be inserted
Step 1: SET I = N // Initialize Counter
Step 2: Repeat Steps 3 and 4 while I >= POS
Step 3: SET A[I + 1] = A[I] //Move Ith element downward
Step 4: SET I = I – 1 // Decrease
Counter
[END OF LOOP]
Step 5: SET N = N + 1 // Reset N
Step 6: SET A[POS] = VAL // Insert element
Step 7: EXIT © e-Learning Centre, UCSC 19
2.1.3 Basic operations on arrays

• Searching
• To search for an item, we step through the array, comparing a
particular value with each element.

Algorithm for searching element in an array


• A is a linear array with N elements
• K is a positive integer such that K<=N.

Step 1:Start
Step 2:Set J=0
Step 3:Repeat Step 4 & 5 while J<N
Step 4: If A[J] = ITEM THEN GO TO Step 6
Step 5:Set J=J+1
Step 6:Print J, Item
Step 7:Stop

© e-Learning Centre, UCSC 20


2.1.3 Basic operations on arrays

• Example for search a key from an array :

searchKey = 66; // find item with key 66


for(j=0; j<nElems; j++) // for each element,
if(arr[j] == searchKey) // found item?
break; // yes, exit before end
if(j == nElems) // at the end?
System.out.println(“Can’t find “ + searchKey); // yes
else
System.out.println(“Found “ + searchKey); // no

• The searchKey variable holds the value we’re looking for.


• If the loop variable j reaches the last occupied cell with no
match being found, the value isn’t in the array. Appropriate
messages are displayed. Example :Found 66 or Can’t find 27.
© e-Learning Centre, UCSC 21
2.1.3 Basic operations on arrays cont.

• Deletion
• Deletion begins with a search for the specified item.
• For simplicity, we assume that the item is present.

Algorithm for deleting an element in the middle of the array

Step 1: [INITIALIZATION] SET I = POS


Step 2: Repeat Steps 3 and 4 while I <= N – 1
Step 3: SET A[I] = A[I + 1]
Step 4: SET I = I + 1
[END OF LOOP]
Step 5: SET N = N – 1
Step 6: EXIT
© e-Learning Centre, UCSC 22
2.1.3 Basic operations on arrays cont.

• Example for delete an element from an array

deleteKey = 55; // delete item with key 55


for(j=0; j<nElems; j++) // look for it
if(arr[j] == deleteKey)
break;
for(int k=j; k<nElems-1; k++) // move higher ones down
arr[k] = arr[k+1];
nElems--; // decrement size

• When we find it, we move all the items with higher index
values down one element to fill in the “hole” left by the
deleted element, and we decrement nElems.
• In a real program, we would also take appropriate action if the
item to be deleted could not be found.
© e-Learning Centre, UCSC 23
2.1.3 Basic operations on arrays cont.

• Display elements

• Displaying all the elements is straightforward: We step


through the array, accessing each one with arr[j] and
displaying it.
• Example:

for(j=0; j<nElems; j++) // display items


System.out.print( arr[j] + “ “);

© e-Learning Centre, UCSC 24


Introduction to Linked Lists

Data
Structure Arrays
Stacks
Array Queues

Linked Linked(singly) list


Doubly linked List
List Circular Linked List
Linked list based Stacks
and Queues

© e-Learning Centre, UCSC


I
25
Introduction to Linked Lists

data --->
Pointer to the next
Head node
A Node

5 ---) 7 2 -- 15

A Linked List
¥
NULL

© e-Learning Centre, UCSC


I
26
Introduction to Linked Lists

• The array is a linear collection of data elements


• It has following limitations:
• Rigid Structure.
• Can be hard to add/remove elements.
• Cannot be dynamically resized in most languages.
• Memory loss

• These limitations can be overcome by using linked structures


• While declaring arrays, we have to specify the size of the array,
which will restrict the number of elements that the array can store.
• For example, if we declare an array as int marks[10], then the array
can store a maximum of 10 data elements but not more than that.
© e-Learning Centre, UCSC 27
Introduction to Linked Lists cont.

• A linked structure is a collection of nodes storing data and links to


other nodes.
• A linked list can be perceived as a train or a sequence of nodes in
which each node contains one or more data fields and a pointer to
the next node.
data link

28

Contains data Contains


of the node address of
the next
node

HEAD data next data next data next NULL

© e-Learning Centre, UCSC


I
28
Introduction to Linked Lists cont.

• A linked list has the following properties


• Successive elements are connected by pointers
• The last element points to NULL
• Can grow or shrink in size during execution of a program
• Can be made just as long as required (until systems memory
exhausts)
• Does not waste memory space (but takes some extra memory
for pointers). It
• allocates memory as list grows.
• Linked structures can be implemented in a variety of ways, the
most flexible implementation is by using a separate object for
each node.
• A list where we can navigate backward as well

© e-Learning Centre, UCSC 29


Introduction to Linked Lists cont.

• Think of each element in a linked list as being an individual


piece in a child's pop chain.
• To form a chain, insert the connector into the back of the
next piece

© e-Learning Centre, UCSC 30


Introduction to Linked Lists cont.

• Inserting a new piece into the chain


❏ breaking a connection and
❏ reconnecting the chain at both ends of the new piece.

© e-Learning Centre, UCSC 31


Introduction to Linked Lists cont.

●Removal of a piece
○ breaking its two connections
○ removing the piece, and then reconnecting the chain.

© e-Learning Centre, UCSC 32


2.2 Comparison of Arrays and Linked Lists

Arrays Linked lists


Fixed size Dynamic size
Random access No random access
Insertions and deletions are Insertions and deletions are
inefficient efficient
No memory wastage, if array is full Since memory is dynamically
or almost full. Otherwise memory allocated (according to our
wastage requirement) there is no waste of
memory
Sequential access is faster Sequential access is not faster
Elements are in contiguous Elements are not in contiguous
memory locations memory locations

© e-Learning Centre, UCSC


I
33
2.2 Comparison of Arrays and Linked Lists cont.

• Advantages of Arrays

• Simple and easy to use


• Faster access to the elements (constant access)
• No need to declare large number of variables
individually.
• Variables are not scattered in memory,they are stored in
contiguous memory

© e-Learning Centre, UCSC 34


2.2 Comparison of Arrays and Linked Lists cont.

• Disadvantages of Arrays
• Fixed size: The size of the array is static (specify the array
size before using it).
• One block allocation: To allocate the array itself at the
beginning, sometimes it may not be possible to get the
memory for the complete array (if the array size is big).
• Complex position-based insertion: To insert an element
at a given position, we may need to shift the existing
elements. This will create a position for us to insert the
new element at the desired position. If the position at
which we want to add an element is at the beginning,
then the shifting operation is more expensive.
© e-Learning Centre, UCSC 35
2.2 Comparison of Arrays and Linked Lists cont.

• Advantages of Linked Lists


• Linked lists can be expanded in constant time : With a
linked list, we can start with space for just one allocated
element and add on new elements easily without the
need to do any copying and reallocating.

• Disadvantages of Linked Lists


• Access time to individual elements : Array is random-
access, which means it takes O(1) to access any element
in the array. Linked lists take O(n) for access to an
element in the list in the worst case.
• Linked lists waste memory in terms of extra reference
points.
© e-Learning Centre, UCSC 36
2.3 Singly Linked Lists

• Generally “linked list” means a singly linked list.


• This list consists of a number of nodes in which each node
has a next pointer to the following element.
• Each node consists of the data element and a link to the
next node in the list.
• The link of the last node in the list is NULL, which indicates
the end of the list.
© e-Learning Centre, UCSC 37
2.3 Singly Linked Lists

• Linked lists contain a pointer variable START /HEAD that stores the
address of the first node in the list.
• We can traverse the entire list using START which contains the
address of the first node;
• If START = NULL, then the linked list is empty and contains no
nodes
• Linked List type declaration example :
Public class ListNode {
private int data;
private ListNode next;
© e-Learning Centre, UCSC 38
2.3 Singly Linked Lists

public ListNode (int data){


this.data = data;
}
public void setData (int data){
this.data = data;
}
public int getData(){
return data;
}
public void setNext (ListNode next){
this.next = next;
}
public ListNode getNext(){
return this.next;
}
}
© e-Learning Centre, UCSC 39
2.3 Singly Linked Lists

• Linked list with AVAIL and START pointers

START
● Every linked list has a 1 Roll No Marks Next

pointer variable START I >ÿ 1 SOI 78 2

which stores the address


2 S02 84 3
3 S03 45 5
of the first node of the I *- 4 1)S12 6 4) -1

list. 4 5 S04 98 7
AVAIL 2) Avail 6
Likewise, for the free
9

7 S05 55 8
pool (which is a linked 8 S06 34 10
list of all free memory 9 14

cells), we have a pointer 10 S07 90 11


11 S08 87 12
variable AVAIL which 12 S09 86 13
stores the address of the 13 S10 67 15

first free space. 14 -1


15 Sll 56 -1 3) 6

© e-Learning Centre, UCSC


I
40
2.3 Singly Linked Lists

• For example, when a new student’s record has to be


added, the memory address pointed by AVAIL will be
taken and used to store the desired information.
• After the insertion, the next available free space’s address
will be stored in AVAIL.
• According to the above table, when the first free memory
space is utilized for inserting the new node, AVAIL will be
set to contain address 6.

© e-Learning Centre, UCSC 41


2.3 Singly Linked Lists cont.

• Basic Operations on a List


• Traversing the list
• Inserting an item in the list
• Deleting an item from the list

© e-Learning Centre, UCSC 42


2.3 Singly Linked Lists cont.

• Traversing the list START

Let us assume that the head points to the first node of the list.
To traverse the list we do the following
• Follow the pointers.
• Display the contents of the nodes (or count) as they are
traversed.
• Stop when the next pointer points to NULL.

5 +> 1 17 * 4 NULL
i L

Head

© e-Learning Centre, UCSC


I
43
2.3 Singly Linked Lists cont.

• Algorithm for traversing a linked list

Step 1: [INITIALIZE] SET PTR = START


Step 2: Repeat Steps 3 and 4 while PTR != NULL
Step 3: Apply Process to PTR.DATA
Step 4: SET PTR = PTR.NEXT
[END OF LOOP]
Step 5: EXIT

© e-Learning Centre, UCSC 44


2.3 Singly Linked Lists cont.

• Algorithm to print the number of nodes in a linked list

Step 1: [INITIALIZE] SET COUNT = 0


Step 2: [INITIALIZE] SET PTR = START
Step 3: Repeat Steps 4 and 5 while PTR != NULL
Step 4: SET COUNT = COUNT +1
Step 5: SET PTR = PTR.NEXT
[END OF LOOP]
Step 6: Write COUNT
Step 7: EXIT

© e-Learning Centre, UCSC 45


2.3 Singly Linked Lists cont.

The function given below can be used for printing the list data
with extra print function.

Public int ListLength (ListNode headNode) {


int length = 0;
ListNode currentNode = headNode;
while(currentNode != null){
length++;
currentNode = currentNode.getNext();
}
return length;
}
• The ListLength() function takes a linked list as input and
counts the number of nodes in the list.
© e-Learning Centre, UCSC 46
2.3 Singly Linked Lists cont.

• Insertion into a singly-linked list has three cases:


• Inserting a new node before the head (at the beginning)
• Inserting a new node after the tail (at the end of the list)
• Inserting a new node at the middle of the list (random
location)

Inserting a Node in Singly Linked List at the Beginning


• In this case, a new node is inserted before the current head node.
• Only one next pointer needs to be modified (new node’s next
pointer) and it can be done in two steps:
• Update the next pointer of new node, to point to the current
head.
• Update head pointer to point to the new node.

© e-Learning Centre, UCSC 47


2.3 Singly Linked Lists cont.

• Update the next pointer of new node, to point to the current


head.

• Update head pointer to point to the new node.

© e-Learning Centre, UCSC 48


2.3 Singly Linked Lists cont.

• Algorithm for inserting a Node in Singly Linked List at the


Beginning

Step 1: IF AVAIL = NULL AVAIL is


Write OVERFLOW advanced

Go to Step 7
[END OF IF]
Step 2: SET NEW_NODE = AVAIL
Step 3: SET AVAIL = AVAIL.NEXT
Step 4: SET NEW_NODE.DATA = VAL
Step 5: SET NEW_NODE.NEXT = START
Step 6: SET START = NEW_NODE
Step 7: EXIT
© e-Learning Centre, UCSC 49
2.3 Singly Linked Lists cont.

Inserting a Node in Singly Linked List at the End


In this case, we need to modify two next pointers (last nodes next
pointer and new nodes next pointer).
• New nodes next pointer points to NULL.

• Last nodes next pointer points to the new node.

© e-Learning Centre, UCSC 50


2.3 Singly Linked Lists cont.
• Algorithm for inserting a Node in Singly Linked List at the End
Step 1: IF AVAIL = NULL
Write OVERFLOW
Go to Step 10
[END OF IF]
Step 2: SET NEW_NODE = AVAIL
Step 3: SET AVAIL = AVAIL.NEXT
Step 4: SET NEW_NODE.DATA = VAL
Step 5: SET NEW_NODE.NEXT = NULL
Step 6: SET PTR = START
Step 7: Repeat Step 8 while PTR.NEXT != NULL
Step 8: SET PTR = PTR NEXT
[END OF LOOP]
Step 9: SET PTR NEXT = NEW_NODE
Step 10: EXIT
© e-Learning Centre, UCSC 51
2.3 Singly Linked Lists cont.

Inserting a Node in Singly Linked List at the Middle


• Let us assume that we are given a position where we want to
insert the new node. In this case also, we need to modify two next
pointers.
• If we want to add an element at position 3 then we stop at
position 2. That means we traverse 2 nodes and insert the new
node. For simplicity let us assume that the second node is
called position node. The new node points to the next node of
the position where we want to add this node.

© e-Learning Centre, UCSC 52


2.3 Singly Linked Lists cont.

• Position node’s next pointer now points to the new


node.

© e-Learning Centre, UCSC 53


2.3 Singly Linked Lists cont.

• Algorithm to insert a new node after a node that has value NUM
Step 1: IF AVAIL = NULL
Write OVERFLOW
Go to Step 12
[END OF IF]
Step 2: SET NEW_NODE = AVAIL
Step 3: SET AVAIL = AVAIL.NEXT
Step 4: SET NEW_NODE.DATA = VAL
Step 5: SET PTR = START
Step 6: SET PREPTR = PTR
Step 7: Repeat Steps 8 and 9 while PREPTR.DATA != NUM
Step 8: SET PREPTR = PTR
Step 9: SET PTR = PTR.NEXT
[END OF LOOP]
Step 1 : PREPTR .NEXT == NEW_NODE
Step 11: SET NEW_NODE. NEXT = PTR
Step 12: EXIT © e-Learning Centre, UCSC 54
2.3 Singly Linked Lists cont.

• Example 1 : Insert a node at the beginning of the list

public void insertBegin(int new_data)


{
Node new_node = new Node(new_data);
new_node.next = head;
head = new_node;
}

© e-Learning Centre, UCSC 55


2.3 Singly Linked Lists cont.

• Example 2 : Insert a node at the end of the list


public void insertEnd(int new_data)
{
Node new_node = new Node(new_data);
if (head == null)
{
head = new Node(new_data);
return;
}
new_node.next = null;
Node last = head;
while (last.next != null)
Node last = last.next;
last.next = new_node;
return;
}
© e-Learning Centre, UCSC 56
2.3 Singly Linked Lists cont.

• Example 3 : Insert a node after a given node

public void insertAfter(Node prev_node, int new_data)


{
if (prev_node == null)
{
System.out.println("The given previous node cannot be
null");
return;
}
Node new_node = new Node(new_data);
new_node.next = prev_node.next;
prev_node.next = new_node;
}

© e-Learning Centre, UCSC 57


2.3 Singly Linked Lists cont.

Singly Linked List Deletion


Similar to insertion, here also we have three cases.
• Deleting the first node
• Deleting the last node
• Deleting an intermediate node.

Deleting the First Node in Singly Linked List


• First node (current head node) is removed from the list. It can be
done in two steps:
• Create a temporary node which will point to the same node as
that of head.
• move the head nodes pointer to the next node and dispose of
the temporary node.

© e-Learning Centre, UCSC 58


2.3 Singly Linked Lists cont.

• Create a temporary node which will point to the same node


as that of head.

• Now, move the head nodes pointer to the next node and
dispose of the temporary node.

© e-Learning Centre, UCSC 59


2.3 Singly Linked Lists cont.

• Algorithm to delete the First Node in Singly Linked List

Step 1: IF START = NULL


Write UNDERFLOW
Go to Step 5
[END OF IF]
Step 2: SET PTR = START
Step 3: SET START = START.NEXT
Step 4: FREE PTR
Step 5: EXIT

© e-Learning Centre, UCSC 60


2.3 Singly Linked Lists cont.

Deleting the Last Node in Singly Linked List


In this case, the last node is removed from the list. It can be done in three
steps:
• Traverse the list and while traversing maintain the previous node
address also. By the time we reach the end of the list, we will have
two pointers, one pointing to the tail node and the other pointing to
the node before the tail node.

© e-Learning Centre, UCSC 61


2.3 Singly Linked Lists cont.

• Update previous node’s next pointer with NULL

• Dispose of the tail node.

© e-Learning Centre, UCSC 62


2.3 Singly Linked Lists cont.

• Algorithm to delete the Last Node in Singly Linked List

Step 1: IF START = NULL


Write UNDERFLOW
Go to Step 8
[END OF IF]
Step 2: SET PTR = START
Step 3: Repeat Steps 4 and 5 while PTR.NEXT != NULL
Step 4: SET PREPTR = PTR
Step 5: SET PTR = PTR.NEXT
[END OF LOOP]
Step 6: SET PREPTR .NEXT = NULL
Step 7: FREE PTR
Step 8: EXIT © e-Learning Centre, UCSC 63
2.3 Singly Linked Lists cont.

Deleting an Intermediate Node in Singly Linked List


In this case, the node to be removed is always located between two
nodes.
Head and tail links are not updated in this case. Such a removal can
be done in two steps:
• Similar to the previous case, maintain the previous node while
traversing the list. Once we find the node to be deleted,
change the previous node’s next pointer to the next pointer of
the node to be deleted.

© e-Learning Centre, UCSC 64


2.3 Singly Linked Lists cont.
• Dispose of the current node to be deleted.

© e-Learning Centre, UCSC 65


2.3 Singly Linked Lists cont.

• Algorithm to delete the node after a given node


Step 1: IF START = NULL
Write UNDERFLOW
Go to Step 9
[END OF IF]
Step 2: SET PTR = START
Step 3: SET PREPTR = PTR
Step 4: Repeat Steps 5 and 6 while PREPTR.DATA != NUM
Step 5: SET PREPTR = PTR
Step 6: SET PTR = PTR.NEXT
[END OF LOOP]
Step 7: SET TEMP = PTR
Step 8: SET PREPTR. NEXT = PTR .NEXT
Step 9 : EXIT
© e-Learning Centre, UCSC 66
2.3 Singly Linked Lists cont.

Example 1 : Delete first node in Singly Linked List

static Node removeFirstNode(Node head)


{
if (head == null)
{
return null;
}
Node temp = head;
head = head.next;
return head;
}
© e-Learning Centre, UCSC 67
2.3 Singly Linked Lists cont.

Example 2 :Delete Last node in Singly Linked List

static Node removeLastNode(Node head) {

if(head == null) {
return null;
}

Node temp = head;


while(temp.next.next != null) {
temp = temp.next;
}
temp.next = null;

return head;
}
© e-Learning Centre, UCSC 68
2.4 Doubly Linked Lists

• A doubly linked list allows bidirectional traversal by storing


two links per node.
• The advantage of a doubly linked list is that given a node in
the list, we can navigate in both directions.
• Doubly linked list cell consists of three parts:
• Data
• A pointer to the next node
• A pointer to the previous node
• Doubly Linked List type declaration example :
Public class ListNode {
private int data;
private ListNode prev;
private ListNode next;
© e-Learning Centre, UCSC 69
2.4 Doubly Linked Lists Cont.

Doubly Linked List Insertion


• Insertion into a doubly-linked list has three cases (same as
singly linked list):
• Inserting a new node before the head.
• Inserting a new node after the tail (at the end of the list).
• Inserting a new node at the middle of the list.
Inserting a Node in Doubly Linked List at the Beginning
• In this case, new node is inserted before the head node.
Previous and next pointers need to be modified and it can
be done in two steps:
• Update the right pointer of the new node to point to the current head
node (dotted link in below figure) and also make left pointer of new
node as NULL.
•Update head node’s left pointer to point to the new node and make
new node as head. Head

© e-Learning Centre, UCSC 70


2.4 Doubly Linked Lists Cont.

• Update the right pointer of the new node to point to the current
head node (dotted link in below figure) and also make left
pointer of new node as NULL.

• Update head node’s left pointer to point to the new node and
make new node as head. Head

© e-Learning Centre, UCSC 71


2.4 Doubly Linked Lists Cont.

• Algorithm to insert a new node at the beginning

Step 1: IF AVAIL = NULL


Write OVERFLOW
Go to Step 9
[END OF IF]
Step 2: SET NEW_NODE= AVAIL
Step 3: SET AVAIL = AVAIL.NEXT
Step 4: SET NEW_NODE.DATA = VAL
Step 5: SET NEW_NODE.PREV = NULL
Step 6: SET NEW_NODE.NEXT = START
Step 7: SET START.PREV = NEW_NODE
Step 8: SET START =NEW_NODE
Step 9: EXIT

© e-Learning Centre, UCSC 72


2.4 Doubly Linked Lists Cont.

Inserting a Node in Doubly Linked List at the Ending


• In this case, traverse the list till the end and insert the new
node.
• New node right pointer points to NULL and left pointer
points to the end of the list.
• Update right pointer of last node to point to new node.

© e-Learning Centre, UCSC 73


2.4 Doubly Linked Lists Cont.

• Algorithm to insert a new node at the end

Step 1: IF AVAIL = NULL


Write OVERFLOW
Go to Step 11
[END OF IF]
Step 2: SET NEW_NODE = AVAIL
Step 3: SET AVAIL = AVAIL..NEXT
Step 4: SET NEW_NODE..DATA = VAL
Step 5: SET NEW_NODE.NEXT = NULL
Step 6: SET PTR = START
Step 7:Repeat Step 8 while PTR NEXT != NULL
Step 8: SET PTR = PTR NEXT
[END OF LOOP]
Step 9: SET PTR NEXT = NEW_NODE
Step 10 : SET NEW_NODE.PREV = PTR
Step 11: EXIT

© e-Learning Centre, UCSC 74


2.4 Doubly Linked Lists Cont.

Inserting a Node in Doubly Linked List at Middle


• Similar to singly linked lists, traverse the list to the position
node and insert the new node.
• New node right pointer points to the next node of the position node
where we want to insert the new node. Also, new node left pointer
points to the position node.

© e-Learning Centre, UCSC 75


2.4 Doubly Linked Lists Cont.

• Position node right pointer points to the new node and


the next node of position node left pointer points to
new node.

© e-Learning Centre, UCSC 76


2.4 Doubly Linked Lists Cont.

• Algorithm to insert a new node at the middle

Step 1: IF AVAIL = NULL


Write OVERFLOW
Go to Step 12
[END OF IF]
Step 2: SET NEW_NODE = AVAIL
Step 3: SET AVAIL = AVAIL..NEXT
Step 4: SET NEW_NODE..DATA = VAL
Step 5: SET PTR = START
Step 6:Repeat Step 7 while PTR DATA != NULL
Step 7: SET PTR = PTR NEXT
[END OF LOOP]
Step 8: SET NEW_NODE. NEXT = PTR.NEXT
Step 9: SET NEW_NODE.PREV = PTR
Step 10 : SET PTR.NEXT =NEW_NODE
Step 11 : SET PTR.NEXT.PREV =NEW_NODE
Step 12: EXIT
© e-Learning Centre, UCSC 77
2.4 Doubly Linked Lists Cont.

Doubly Linked List Deletion


• Similar to singly linked list deletion, here we have three cases:
• Deleting the first node
• Deleting the last node
• Deleting an intermediate node

Deleting the First Node in Doubly Linked List


• In this case, the first node (current head node) is removed from
the list. It can be done in two steps:
• Create a temporary node which will point to the same node as
that of head.
• Now, move the head nodes pointer to the next node and
change the heads left pointer to NULL. Then, dispose of the
temporary node.

© e-Learning Centre, UCSC 78


2.4 Doubly Linked Lists Cont.

• Create a temporary node which will point to the same node as


that of head.

• Move the head nodes pointer to the next node and change
the heads left pointer to NULL. Then, dispose of the
temporary node.

© e-Learning Centre, UCSC 79


2.4 Doubly Linked Lists Cont.

• Algorithm to delete the first node

Step 1: IF START = NULL


Write UNDERFLOW
Go to Step 5
[END OF IF]
Step 2: SET PTR = START
Step 3: SET START = START.NEXT
Step 4 : SET START. PREV = NULL
Step 5: EXIT

© e-Learning Centre, UCSC 80


2.4 Doubly Linked Lists Cont.

Deleting the Last Node in Doubly Linked List


• This operation is a bit trickier than removing the first node,
because the algorithm should find a node, which is previous
to the tail first. This can be done in three steps:
• Traverse the list and while traversing maintain the
previous node address also. By the time we reach the
end of the list, we will have two pointers, one pointing to
the tail and the other pointing to the node before the
tail.
• Update the next pointer of previous node to the tail
node with NULL.
• Dispose the tail node.

© e-Learning Centre, UCSC 81


2.4 Doubly Linked Lists Cont.

• Traverse the list and while traversing maintain the previous node
address also. By the time we reach the end of the list, we will have
two pointers, one pointing to the tail and the other pointing to
the node before the tail.

• Update the next pointer of previous node to the tail node with
NULL.

© e-Learning Centre, UCSC 82


2.4 Doubly Linked Lists Cont.

• Dispose the tail node.

© e-Learning Centre, UCSC 83


2.4 Doubly Linked Lists Cont.

• Algorithm to delete the last node

Step 1: IF START = NULL


Write UNDERFLOW
Go to Step 7
[END OF IF]
Step 2: SET PTR = START
Step 3: Repeat Step 4 while PTR.NEXT != NULL
Step 4: SET PTR = PTR NEXT
[END OF LOOP]
Step 5: SET PTR.PREV.NEXT = NULL
Step 6: FREE PTR
Step 7: EXIT

© e-Learning Centre, UCSC 84


2.4 Doubly Linked Lists Cont.

Deleting the Intermediate Node in Doubly Linked List


• In this case, the node to be removed is always located between
two nodes, and the head and tail links are not updated. The
removal can be done in two steps:
• Similar to the previous case, maintain the previous node while
also traversing the list. Upon locating the node to be deleted,
change the previous node’s next pointer to the next node of
the node to be deleted.

© e-Learning Centre, UCSC 85


2.4 Doubly Linked Lists Cont.

• Dispose of the current node to be deleted.

© e-Learning Centre, UCSC 86


2.4 Doubly Linked Lists Cont.

• Algorithm to delete a node after a given node


Step 1: IF START = NULL
Write UNDERFLOW
Go to Step 9
[END OF IF]
Step 2: SET PTR = START
Step 3: Repeat Step 4 while PTR.DATA != NUM
Step 4: SET PTR = PTR.NEXT
[END OF LOOP]
Step 5: SET TEMP = PTR.NEXT
Step 6: SET PTR. NEXT = TEMP. NEXT
Step 7: SET TEMP. NEXT.PREV = PTR
Step 8: FREE TEMP
Step 9: EXIT

© e-Learning Centre, UCSC 87


2.4 Doubly Linked Lists Cont.

• Example: Adding To The End


public void addToEnd ()
{
Node anotherNode = new Node (currentDataValue);
Node temp;
if (isEmpty() == true)
head = anotherNode;
else {
temp = head;
while (temp.next != null){
temp = temp.next;
}
temp.next = anotherNode;
anotherNode.previous = temp;
}
currentDataValue += 10;
length++;
}
© e-Learning Centre, UCSC 88
2.4 Doubly Linked Lists Cont.

• Example :Adding Anywhere (1)


public void addToPosition (int position)
{
Node anotherNode = new Node (currentDataValue);
Node temp;
Node prior;
Node after;
int index;

if ((position < 1) || (position > (length+1)))


{
System.out.println("Position must be a value between 1-" +
(length+1));
}

© e-Learning Centre, UCSC 89


2.4 Doubly Linked Lists Cont.
• Example :Adding Anywhere (2)
else
{
// List is empty
if (head == null)
{
if (position == 1)
{
currentDataValue += 10;
length++;
head = anotherNode;
}
else
System.out.println("List empty, unable to add node to " +"position " +
position);
} © e-Learning Centre, UCSC 90
2.4 Doubly Linked Lists Cont.

• Example :Adding Anywhere (3)


// List is not empty, inserting into first position.
else if (position == 1)
{
head.previous = anotherNode;
anotherNode.next = head;
head = anotherNode;
currentDataValue += 10;
length++;
}

© e-Learning Centre, UCSC 91


2.4 Doubly Linked Lists Cont.

• Example :Adding Anywhere (4)


// List is not empty inserting into a position other than the first
else
{
prior = head;
index = 1;
// Traverse list until current is referring to the node in front
// of the position that we wish to insert the new node into.
while (index < (position-1))
{
prior = prior.next;
index++;
}
after = prior.next;

© e-Learning Centre, UCSC 92


2.4 Doubly Linked Lists Cont.

• Example :Adding Anywhere (5)


// Set the references to the node before the node to be inserted.
prior.next = anotherNode;
anotherNode.previous = prior;
// Set the references to the node after the node to be
// inserted.
if (after != null)
after.previous = anotherNode;
anotherNode.next = after;
currentDataValue += 10;
length++;
}
}
}

© e-Learning Centre, UCSC 93


2.4 Doubly Linked Lists Cont.

• Example: Deleting A Node (1)


public void delete (int key)
{
int indexToDelete;
int indexTemp;
Node previous;
Node toBeDeleted;
Node after;
indexToDelete = search(key);
// No match, nothing to delete.
if (indexToDelete == -1)
{
System.out.println("Cannot delete element with a data value of "
+ key + " because it was not found.");
} © e-Learning Centre, UCSC 94
2.4 Doubly Linked Lists Cont.

• Example :Deleting A Node (2)


else
{
// Deleting first element.
if (indexToDelete == 1)
{
head = head.next;
length--;
}
else
{
previous = null;
toBeDeleted = head;
indexTemp = 1;

© e-Learning Centre, UCSC 95


2.4 Doubly Linked Lists Cont.

• Example :Deleting A Node (3)


while (indexTemp < indexToDelete)
{
previous = toBeDeleted;
toBeDeleted = toBeDeleted.next;
indexTemp++;
}
previous.next = toBeDeleted.next;
after = toBeDeleted.next;
after.previous = previous;
length--;
}
}
}

© e-Learning Centre, UCSC 96


2.5 Circular Linked Lists

• In singly linked lists and doubly linked lists, the end of lists
are indicated with NULL value.
• But circular linked lists do not have ends. While traversing
the circular linked lists we should be careful; otherwise we
will be traversing the list infinitely.

© e-Learning Centre, UCSC 97


2.5 Circular Linked Lists Cont.

• While traversing a circular linked list, we can begin at any node


and traverse the list in any direction, forward or backward, until we
reach the same node where we started.
• In circular linked lists, each node has a successor.
• Note that unlike singly linked lists, there is no node with NULL
pointer in a circularly Linked list.
• In some situations, circular linked lists are useful.
• For example, when several processes are using the same
computer resource (CPU) for the same amount of time, we
have to assure that no process accesses the resource before
all other processes do (round robin algorithm).
• When we are surfing the Internet, we can use the Back button
and the Forward button to move to the previous pages that
we have already visited.

© e-Learning Centre, UCSC 98


2.5 Circular Linked Lists Cont.

• An Example Of Traversing A Circular Linked List

public void display ()


{
Node temp = list;
System.out.println("Displaying list");
if (isEmpty() == true)
{
System.out.println("Nothing to display, list is empty.");
}
do
{
System.out.println(temp.data);
temp = temp.next;
} while (temp != list);
System.out.println();
}

© e-Learning Centre, UCSC 99


2.5 Circular Linked Lists Cont.

Inserting a Node at the End of a Circular Linked List

• Let us add a node containing data, at the end of a list (circular


list) headed by head. The new node will be placed just after the
tail node (which is the last node of the list), which means it will
have to be inserted in between the tail node and the first node.

• Create a new node and initially keep its next pointer pointing to
itself.

© e-Learning Centre, UCSC 100


2.5 Circular Linked Lists Cont.

• Update the next pointer of the new node with the head node and
also traverse the list to the tail. That means in a circular list we
should stop at the node whose next node is head.

© e-Learning Centre, UCSC 101


2.5 Circular Linked Lists Cont.

•Update the next pointer of the previous node to point to the new
node and we get the list as shown below.

© e-Learning Centre, UCSC 102


2.5 Circular Linked Lists Cont.

Inserting a Node at the front of a Circular Linked List

• The only difference between inserting a node at the beginning


and at the end is that, after inserting the new node, we just need
to update the pointer. The steps for doing this are given below:

• Create a new node and initially keep its next pointer pointing to
itself.

© e-Learning Centre, UCSC 103


2.5 Circular Linked Lists Cont.

• Update the next pointer of the new node with the head node and
also traverse the list until the tail. That means in a circular list we
should stop at the node which is its previous node in the list.

© e-Learning Centre, UCSC 104


2.5 Circular Linked Lists Cont.

• Update the previous head node in the list to point to the new
node.

© e-Learning Centre, UCSC


105
2.5 Circular Linked Lists Cont.

• Make the new node as the head.

© e-Learning Centre, UCSC 106


2.5 Circular Linked Lists Cont.

Deleting the Last Node in a Circular Linked List


The list has to be traversed to reach the last but one node.
This has to be named as the tail node,and its next field has to
point to the first node. Consider the following list.
• To delete the last node 40, the list has to be traversed
till you reach 7. The next field of 7 has to be changed
to point to 60, and this node must be renamed.
• Traverse the list and find the tail node and its previous
node.

© e-Learning Centre, UCSC 107


2.5 Circular Linked Lists Cont.

• Update the next pointer of tail node’s previous node to


point to head.

© e-Learning Centre, UCSC 108


2.5 Circular Linked Lists Cont.

• Dispose of the tail node.

© e-Learning Centre, UCSC 109


2.5 Circular Linked Lists Cont.

Deleting the First Node in a Circular Linked List


The first node can be deleted by simply replacing the next
field of the tail node with the next field of the first node.
• Find the tail node of the linked list by traversing the
list. Tail node is the previous node to the head node
which we want to delete.

© e-Learning Centre, UCSC 110


2.5 Circular Linked Lists Cont.

• Create a temporary node which will point to the head.


Also, update the tail nodes next pointer to point to next
node of head (as shown below).

© e-Learning Centre, UCSC 111


2.5 Circular Linked Lists Cont.

• Now, move the head pointer to next node. Create a


temporary node which will point to head. Also, update the
tail nodes next pointer to point to next node of head (as
shown below).

© e-Learning Centre, UCSC 112


2.6 Skip Lists

• Skip lists are a probabilistic alternative to balanced trees.


• Skip list is a data structure that can be used as an
alternative to balanced binary trees
• It is basically a linked list with additional pointers such that
intermediate nodes can be skipped.
• The skip list is used to store a sorted list of elements or
data with a linked list.
• It allows the process of the elements or data to view
efficiently.
• It allows the user to search, remove, and insert the
element very quickly.
• It consists of a base list that includes a set of elements
which maintains the link hierarchy of the subsequent
elements.

© e-Learning Centre, UCSC 113


2.6 Skip Lists Cont.

• In an ordinary sorted linked list, search, insert, and delete


are in O(n) because the list must be scanned node-by-
node from the head to find the relevant node.
• If somehow we could scan down the list in bigger steps
(skip down, as it were), we would reduce the cost of
scanning.
• This is the fundamental idea behind Skip Lists.

Skip Lists with One Level

© e-Learning Centre, UCSC 114


2.6 Skip Lists Cont.

Skip Lists with Two Levels

Skip Lists with Three Levels

© e-Learning Centre, UCSC 115


2.6 Skip Lists Cont.

• In a skip list of n nodes, for each k and i such that 1 <= k


<= [log n] and 1 <= i <= [n/2k-1] - 1, the node in position 2k-
1• i points to the node in position 2k-1 • (i + 1).

• This means that every second node points to the node two
positions ahead, every fourth node points to the node four
positions ahead, and so on.
• This is accomplished by having different numbers of
reference fields in nodes on the list:
- Half of the nodes have just one reference field
- one-fourth of the nodes have two reference fields
- one-eighth of the nodes have three reference fields and
etc.
• The number of reference fields indicates the level of each
node, and the number of levels is maxLevel = [lg n] + 1.

© e-Learning Centre, UCSC 116


2.6 Skip Lists Cont.

• Insertion Operation in Skip Lists

© e-Learning Centre, UCSC 117


2.6 Skip Lists Cont.

• Insertion Operation in Skip Lists

We will start from highest level in the list and compare key of next node of
the current node with the key to be inserted. Basic idea is If :
a. Key of next node is less than key to be inserted then we keep

on moving forward on the same level


b. Key of next node is greater than the key to be inserted then

we store the pointer to current node i at update[i] and move


one level down and continue our search.
At the level 0, we will definitely find a position to insert given key.

© e-Learning Centre, UCSC 118


2.6 Skip Lists Cont.

• Insertion Operation in Skip Lists

Insert(key)
p = Search(key)
q = null
i=1
repeat
i=i+1 //Height of tower for new element
if i >= h
h=h+1
createNewLevel() //Creates new linked list level

© e-Learning Centre, UCSC 119


2.6 Skip Lists Cont.

• Insertion Operation in Skip Lists Cont.


while (p.above == null)
p = p.prev //Scan backwards until you can go up
p = p.above
q = insertAfter(key, p) //Insert our key after position p
until CoinFlip() == 'Tails'
n=n+1
return q
We use a function called CoinFlip() that mimics a fair coin and returns
either heads or tails. Finally, the function insertAfter(a, b) simply inserts
the node a after the node b.

© e-Learning Centre, UCSC 120


2.6 Skip Lists Cont.

• Insertion Operation in Skip Lists Cont.

• First, we always insert the key into the bottom list at the correct
location.
• Then, we have to promote the new element. We do so by flipping a
fair coin.
• If it comes up heads, we promote the new element. By flipping this
fair coin, we are essentially deciding how big to make the tower for
the new element.
• We scan backwards from our position until we can go up, and then
we go up a level and insert our key right after our current position.
• While we are flipping our coin, if the number of heads starts to
grow larger than our current height, we have to make sure to
create new levels in our skip list to accommodate this.

© e-Learning Centre, UCSC 121


2.6 Skip Lists Cont.

• Search Operation in Skip Lists

Searching an element is very similar to approach for searching a spot for


inserting an element in Skip list. The basic idea is if :

1. Key of next node is less than search key then we keep on moving

forward on the same level.


2. Key of next node is greater than the key to be inserted then we store

the pointer to current node i at update[i] and move one level down
and continue our search.

At the lowest level (0), if the element next to the rightmost element
(update[0]) has key equal to the search key, then we have found key
otherwise failure.
© e-Learning Centre, UCSC 122
2.6 Skip Lists Cont.

• Search Operation in Skip Lists


Search(key)
p = top-left node in S
while (p.below != null) do //Scan down
p = p.below
while (key >= p.next) do //Scan forward
p = p.next
return p

© e-Learning Centre, UCSC 123


2.6 Skip Lists Cont.

• Deletion Operation in Skip Lists

© e-Learning Centre, UCSC 124


2.6 Skip Lists Cont.

• Deletion Operation in Skip Lists

• Once the element is located, rearrangement of pointers is


done to remove element form list just like we do in singly
linked list.
• We start from lowest level and do rearrangement until
element next to update[i] is not k.
• After deletion of element there could be levels with no
elements, so we will remove these levels as well by
decrementing the level of Skip list.

© e-Learning Centre, UCSC 125


2.6 Skip Lists Cont.

• Deletion Operation in Skip Lists

Delete(key)

Search for all positions p_0, ..., p_i where key exists

if none are found

return

Delete all positions p_0, ..., p_i

Remove all empty layers of skip list

Delete can be implemented in many ways. Since we know when we find our first
instance of key, it will be connected to all others instances of key, and we can easily
delete them all at once.

© e-Learning Centre, UCSC 126


Summary

An array is a collection of elements of the same data


type. The elements of an array are stored in
Arrays consecutive memory locations and are referenced by
an index.

A linked list is a collection of data elements called


Linked Lists nodes in which the linear representation is given by
links from one node to the next node.

A doubly linked list is a linked list which contains a


Doubly Linked Lists pointer to the next as well as the previous node in
the sequence. Therefore, it consists of three parts.

© e-Learning Centre, UCSC 127


3 : Stacks and Queues

IT3206 – Data Structures and Algorithms

Level II - Semester 3

© e-Learning Centre, UCSC


Overview

• This section provides important features of stacks &


queues to understand how and why they organize the
data so uniquely.
• The section will also illustrate the implementation of
stacks & queues by using both arrays as well as linked
lists.
• Finally, the section will discuss in detail some of the very
useful areas where stacks & queues are primarily used.

© e-Learning Centre, UCSC 2


Intended Learning Outcomes

• At the end of this lesson, you will be able to;


• Explain the usage stacks and queues
• Demonstrate the basic operations of stacks and queues
• Apply stacks and queues for problem-solving

© e-Learning Centre, UCSC 3


List of subtopics

3.1 Stacks
3.1.1 Introduction to Stacks [Ref 4:pg.163-165,Ref 2:pg.232]
3.1.1.1 Array based Stack implementation [Ref 4:pg.165-167, Ref 3:pg.
116-123, Ref 1:pg.596-599, Ref 2:pg.233-234]
3.1.1.2 Linked List based Stack implementation [Ref 4:pg.171-175,
Ref1:pg.606-609]
3.1.2 Applications of Stacks [Ref 4:pg.165, Ref 4:pg.174-185]
3.2 Queues
3.2.1 Introduction to queues [Ref 4:pg.205-206, Ref 2:pg.234]
3.2.1.1 Array based Queue implementation [Ref 1:pg.260-261, pg.600-
604, Ref 3:pg.132-142, Ref 2:pg.235]
3.2.1.2 Linked List based Queue implementation [Ref 4: pg. 212-213,
Ref1:pg.609-612]
3.2.2 Applications of queues [Ref 4:pg.207]
3.2.3 Circular queue [Ref 4:pg.207-208, Ref 3:pg.36-137]
3.2.4 Priority queue [Ref 4:pg.369-371, Ref 1:pg.274-276, Ref 3:pg.143-149]

© e-Learning Centre, UCSC 4


3.1.1 Introduction to Stacks

• A stack is a simple data structure used for storing data


(similar to Linked Lists).

• In a stack, the order in which the data arrives is important.


• A pile of plates in a cafeteria is a good example of a stack.
The plates are added to the stack as they are cleaned, and
they are placed on the top. When a plate, is required it is
taken from the top of the stack. The first plate placed on
the stack is the last one to be used.

© e-Learning Centre, UCSC 5


3.1.1 Introduction to Stacks cont.

• A stack is an ordered list in which insertion and deletion


are done at one end, called top.

• The last element inserted is the first one to be deleted.


• Hence, it is called the Last in First out (LIFO) or First in
Last out (FILO) list.

• The INSERT operation on a stack is often called PUSH.


• DELETE operation which does not take an element
argument is often called POP.

• Trying to pop out an empty stack is called underflow and


trying to push an element in a full stack is called overflow.
© e-Learning Centre, UCSC 6
3.1.1 Introduction to Stacks cont.

Main stack operations


• Push (int data): Inserts data onto stack.
• int Pop(): Removes and returns the last inserted element
from the stack.

Auxiliary stack operations


• int IsEmptyStack(): Indicates whether any elements are
stored in the stack or not.
• int IsFullStack(): Indicates whether the stack is full or not.
• int Top(): Returns the last inserted element without
removing it.
• int Size(): Returns the number of elements stored in the
stack.

© e-Learning Centre, UCSC 7


3.1.1 Introduction to Stacks cont.

How stack works

https://miro.medium.com/max/800/0*SESFJYWU5a-3XM9m.gif

© e-Learning Centre, UCSC 8


3.1.1 Introduction to Stacks cont.

• Push Operation Algorithm


• Step 1 − Checks if the stack is full.
• Step 2 − If the stack is full, produces an error and exit.
• Step 3 − If the stack is not full, increments top to point next
empty space.
• Step 4 − Adds data element to the stack location, where top
is pointing.

• Push Operation Pseudocode


begin procedure push: stack, data
if stack is full
return null
endif
top ← top + 1
stack[top] ← data
end procedure
© e-Learning Centre, UCSC 9
3.1.1 Introduction to Stacks cont.

• Pop Operation Algorithm


• Step 1 − Checks if the stack is empty.
• Step 2 − If the stack is empty, produces an error and exit.
• Step 3 − If the stack is not empty, accesses the data element
at which top is pointing.
• Step 4 − Decreases the value of top by 1.

• Pop Operation Pseudocode


begin procedure pop: stack
if stack is empty
return null
endif
data ← stack[top]
top ← top - 1
return data
end procedure © e-Learning Centre, UCSC 10
3.1.1 Introduction to Stacks cont.

• IsEmptyStack Operation Pseudocode

begin procedure IsEmptyStack

if top less than 1


return true
else
return false
endif

end procedure

© e-Learning Centre, UCSC 11


3.1.1 Introduction to Stacks cont.

• IsFullStack Operation Pseudocode

begin procedure IsFullStack

if top equals to MAXSIZE


return true
else
return false
endif

end procedure

© e-Learning Centre, UCSC 12


3.1.1 Introduction to Stacks cont.

• Top Operation Pseudocode

begin procedure Top


return stack[top]
end procedure

© e-Learning Centre, UCSC 13


3.1.1.1 Array based Stack implementation

• To push an item into an empty stack, we insert it at array


location 0. ( since all java arrays start at 0)

• To push the next item into the location 0 over the location
to make room for new item.

© e-Learning Centre, UCSC 14


3.1.1.1 Array based Stack implementation Cont.

• This is easily done by defining an auxiliary integer variable


known as stack pointer, which stores the array index
currently being used as the top of the stack.
• A stack can be implemented with an array and an integer.
• The integer TOS (top of stack) provides the array index of
the top element of the stack, when TOS is –1 , the stack is
empty.

© e-Learning Centre, UCSC 15


Stacks specifies two data fields such as

• The array (which is expanded as needed stores the items


in the stack)

• TopOfStack (TOS) ( gives the index of the current top of


the stack, if stack is empty, this index is –1.)

© e-Learning Centre, UCSC 16


Algorithms For Pushing & Popping

PUSH

• If stack is not full then


• Add 1 to the stack pointer.
• Store item at stack pointer location.

© e-Learning Centre, UCSC 17


Algorithms For Pushing & Popping cont.

POP

• If stack is not empty then


• Read item at stack pointer location.
• Subtract 1 from the stack pointer.

© e-Learning Centre, UCSC 18


How to stack routines work:

empty stack; push(a),push(b); pop

© e-Learning Centre, UCSC 19


Java implementation

Zero parameter constructor for array based stack

public stackar( )
/* construct the stack
{
thearray= new object[default-capacity];
Tos = -1;
}

© e-Learning Centre, UCSC 20


Isempty : returns true if stack is empty, fals
otherwise

Isempty( )

public Boolean Isempty( )


{
return tos= = -1
}

© e-Learning Centre, UCSC 21


Isfull( ) : returns true if stack is full , false otherwise

Isfull( )

public Boolean isfull( )


{
return tos= = stacksize-1; (default capacity)
}

© e-Learning Centre, UCSC 22


push method for array based stack

Insert a new item into the stack

public void push (object x)


{
If isfull( )
throw new stackexception (“ stack is full”)
theArray[++tos]=x;
}

© e-Learning Centre, UCSC 23


Pop method for array based stack

Remove the most recently inserted item from the stack


Exception underflow if the stack is empty

public void pop( ) throws underflow


{
If (isempty( ))
throw new underflow (“stackpop”);
tos - - ;
}

© e-Learning Centre, UCSC 24


Top method for array based stack

Return the most recently inserted item from the stack


Exception underflow if the stack is empty

public object top( ) throws underflow


{
if (isEmpty( ))
throw new underflow( “stacktop”)
return theArray[tos];
}

© e-Learning Centre, UCSC 25


Top and pop method for array based stack

Return and remove the most recently inserted item from the
stack
Exception underflow if the stack is empty

public object topandpop( ) throws underflow


{
if isEmpty( ) )
throw new underflow (“stack topandpop”);
return theArray[tos - - ];
}

© e-Learning Centre, UCSC 26


Java Code for a Stack
import java.io.*; // for I/O
class StackX
{
private int maxSize; // size of stack array
private double[ ] stackArray;
private int top; // top of stack
//-------------------------------------------------------------

public StackX(int s) // constructor


{
maxSize = s; // set array size
stackArray = new double[maxSize]; // create array
top = -1; // no items yet
}
//-------------------------------------------------------------
© e-Learning Centre, UCSC 27
Java Code for a Stack

public void push(double j) // put item on top of stack {


stackArray[++top] = j; // increment top, insert item
}
//-------------------------------------------------------------

public double pop() // take item from top of stack {


return stackArray[top--]; // access item, decrement top
}
//-------------------------------------------------------------

public double peek() // peek at top of stack {


return stackArray[top];
}
//-------------------------------------------------------------
© e-Learning Centre, UCSC 28
Java Code for a Stack

//-------------------------------------------------------------
-
public boolean isFull() // true if stack is full
{
return (top == maxSize-1);
}
//-------------------------------------------------------------
-
} // end class StackX

© e-Learning Centre, UCSC 29


Java Code for a Stack
class StackApp {
public static void main(String[] args)
{
StackX theStack = new StackX(10); // make new stack
theStack.push(20); // push items onto stack
theStack.push(40);
theStack.push(60);
theStack.push(80);
while( !theStack.isEmpty() ) // until it's empty,
{ // delete item from
stack double value = theStack.pop();
System.out.print(value); // display it
System.out.print(" ");
} // end while
System.out.println("");
} // end main()
} // end class StackApp
© e-Learning Centre, UCSC 30
Java Code for a Stack

The main() method in the StackApp class creates a stack that


can hold 10 items, pushes 4 items onto the stack, and then
displays all the items by popping them off the stack until it's
empty.
Here's the output:
80 60 40 20

© e-Learning Centre, UCSC 31


StackX Class Methods

The constructor creates a new stack of a size specified in its


argument.
The fields of the stack comprise a variable to hold its
maximum size (the size of the array), the array itself, and a
variable top, which stores the index of the item on the top of
the stack.
(Note that we need to specify a stack size only because the
stack is implemented using an array. If it had been
implemented using a linked list, for example, the size
specification would be unnecessary.)

© e-Learning Centre, UCSC 32


StackX Class Methods
The push() method increments top so it points to the space
just above the previous top, and stores a data item there.
Notice that top is incremented before the item is inserted.

The pop() method returns the value at top and then


decrements top. This effectively removes the item from the
stack; it's inaccessible, although the value remains in the array
(until another item is pushed into the cell).

The peek() method simply returns the value at top, without


changing the stack.

The isEmpty() and isFull() methods return true if the stack is


empty or full, respectively. The top variable is at –1 if the stack
is empty and maxSize-1 if the stack is full.
© e-Learning Centre, UCSC 33
Error Handling

There are different philosophies about how to handle stack


errors. What happens if you try to push an item onto a stack
that's already full, or pop an item from a stack that's empty?

We've left the responsibility for handling such errors up to the


class user. The user should always check to be sure the stack is
not full before inserting an item:

© e-Learning Centre, UCSC 34


Error Handling

if( !theStack.isFull() )
insert(item);
else
System.out.print("Can't insert, stack is full");

• In the interest of simplicity, we've left this code out of the


main() routine (and anyway, in this simple program, we know
the stack isn't full because it has just been initialized).

• We do include the check for an empty stack when main() calls


pop().

© e-Learning Centre, UCSC 35


3.1.1.2 Linked List based Stack implementation

• The other way of implementing stacks is by using Linked


lists.

• To implement a push, we create a new node in the list and


attach it as the new first element.

• To implement a pop, we merely advance the top of the


stack to the second item in the list (if there is one).

• An empty stack is represented by an empty linked list.


• Clearly, each operation is performed in constant time
because, by restricting operations to the first node, we
have made all calculations independent of the size of the
list
© e-Learning Centre, UCSC 36
3.1.1.2 Linked List based Stack implementation cont.

• Skeleton for linked list-based stack class


public class ListStack<AnyType> implements Stack<AnyType>
{
public boolean isEmpty( ){
return topOfStack == null;
}
public void makeEmpty( ){
topOfStack = null;
}
public void push( AnyType x ) {}
public void pop( ) {}
public AnyType top( ) {}
public AnyType topAndPop( ) {}
private ListNode<AnyType> topOfStack = null;
} © e-Learning Centre, UCSC
37
3.1.1.2 Linked List based Stack implementation cont.

• Skeleton for linked list-based stack class


class ListNode<AnyType>
{
public ListNode( AnyType theElement ){
this( theElement, null );
}

public ListNode( AnyType theElement, ListNode<AnyType> n


){
element = theElement; next = n;
}

public AnyType element; © e-Learning Centre, UCSC 38


3.1.1.2 Linked List based Stack implementation cont.

• The push and pop routines for the ListStack class

public void push( AnyType x ){


topOfStack = new ListNode<AnyType>( x, topOfStack );
}

public void pop( ){


if( isEmpty( ) )
throw new UnderflowException( "ListStack pop" );
topOfStack = topOfStack.next;
}

© e-Learning Centre, UCSC 39


3.1.1.2 Linked List based Stack implementation cont.

• The top and topAndPop routines for the ListStack class

public AnyType top( ){


if( isEmpty( ) )
throw new UnderflowException( "ListStack top" );
return topOfStack.element;
}
public AnyType topAndPop( ){
if( isEmpty( ) )
throw new UnderflowException( "ListStack topAndPop" );
AnyType topItem = topOfStack.element;
topOfStack = topOfStack.next;
return topItem;
} © e-Learning Centre, UCSC 40
3.1.2 Applications of Stacks
Following are some of the applications of stacks

Direct Applications
• Balancing of symbols
• Infix-to-postfix conversion
• Evaluation of postfix expression
• Implementing function calls (including recursion)
• Finding of spans (finding spans in stock markets, refer to
Problems section)
• Page-visited history in a Web browser [Back Buttons]
• Undo sequence in a text editor
• Matching Tags in HTML and XML
• more direct applications using stacks?

© e-Learning Centre, UCSC 41


3.1.2 Applications of Stacks cont.

Indirect Applications
• Auxiliary data structure for other algorithms
(Example: Tree traversal algorithms)
• Component of other data structures
(Example: Simulating queues)

© e-Learning Centre, UCSC 42


3.2.1 Introduction to queues

• A queue is a data structure used for storing data (similar


to Linked Lists and Stacks).
• In general, a queue is a line of people or things waiting to
be served in sequential order starting at the beginning of
the line or sequence.

© e-Learning Centre, UCSC 43


© e-Learning Centre, UCSC 44
3.2.1 Introduction to queues cont.

• A queue is an ordered list in which insertions are done at


one end (rear) and deletions are done at other end
(front).

• The first element to be inserted is the first one to be


deleted. Hence, it is called First in First out (FIFO) or Last
in Last out (LILO) list.

• When an element is inserted in a queue, the concept is


called EnQueue.

• When an element is removed from the queue, the


concept is called DeQueue.

• DeQueueing an empty queue is called underflow and


EnQueuing an element in a full queue is called overflow.
© e-Learning Centre, UCSC 45
3.2.1 Introduction to queues cont.

Main Queue Operations


• EnQueue(int data): Inserts an element at the end of the
queue
• int DeQueue(): Removes and returns the element at the
front of the queue

Auxiliary Queue Operations


• int Front(): Returns the element at the front without
removing it
• int IsEmptyQueue: Indicates whether no elements are
stored in the queue or not
• int QueueSize(): Returns the number of elements stored in
the queue

© e-Learning Centre, UCSC 46


3.2.1 Introduction to queues cont.

How queue works

https://i1.faceprep.in/Companies-1/queue-operations.gif

© e-Learning Centre, UCSC 47


3.2.1 Introduction to queues cont.

• EnQueue Operation Algorithm


• Step 1 − Check if the queue is full.
• Step 2 − If the queue is full, produce overflow error and exit.
• Step 3 − If the queue is not full, increment rear pointer to
point the next empty space.
• Step 4 − Add data element to the queue location, where the
rear is pointing.
• EnQueue Operation Pseudocode
procedure enqueue(data)
if queue is full
return overflow
endif
rear ← rear + 1
queue[rear] ← data
return true
end procedure © e-Learning Centre, UCSC 48
3.2.1 Introduction to queues cont.
• DeQueue Operation Algorithm
• Step 1 − Check if the queue is empty.
• Step 2 − If the queue is empty, produce underflow error and
exit.
• Step 3 − If the queue is not empty, access the data where
front is pointing.
• Step 4 − Increment front pointer to point to the next
available data element.
• DeQueue Operation Pseudocode
procedure dequeue
if queue is empty
return underflow
end if
data = queue[front]
front ← front + 1
return true
end procedure © e-Learning Centre, UCSC 49
3.2.1 Introduction to queues cont.

• IsEmptyQueue Operation Algorithm

begin procedure IsEmptyQueue

if front is less than MIN OR front is greater than rear


return true
else
return false
endif

end procedure
© e-Learning Centre, UCSC 50
3.2.1 Introduction to queues cont.

• Front Operation Algorithm

begin procedure Front


return queue[front]
end procedure

© e-Learning Centre, UCSC 51


3.2.1.1 Array based Queue implementation

• The queue.java program features a Queue class with


insert(), remove(), peek(), isFull(), isEmpty(), and size()
methods.
• The main() program creates a queue of five cells, inserts
four items, removes three items, and inserts four more.
The sixth insertion invokes the wraparound feature. All the
items are then removed and displayed.
• The output looks like this:
• 40 50 60 70 80

© e-Learning Centre, UCSC 52


The Queue.java Program

import java.io.*; // for I/O


class Queue {
private int maxSize;
private int[] queArray;
private int front;
private int rear;
private int nItems;
//-------------------------------------------------------------

© e-Learning Centre, UCSC 53


The Queue.java Program Cont.

public Queue(int s) // constructor


{
maxSize = s;
queArray = new int[maxSize];
front = 0;
rear = -1;
nItems = 0;
}
//-------------------------------------------------------------

© e-Learning Centre, UCSC 54


The Queue.java Program

public void insert(int j) // put item at rear of queue


{
if(rear == maxSize-1) // deal with wraparound
rear = -1;
queArray[++rear] = j; // increment rear and
insert
nItems++; // one more item
}
//-------------------------------------------------------------

© e-Learning Centre, UCSC 55


The Queue.java Program Cont.

public int remove() // take item from front of queue


{
int temp = queArray[front++]; // get value and incr front
if(front == maxSize) // deal with wraparound
front = 0;
nItems--; // one less item
return temp;
}
//-------------------------------------------------------------

© e-Learning Centre, UCSC 56


The Queue.java Program

public int peekFront() { // peek at front of queue


return queArray[front];
}
//-------------------------------------------------------------
public boolean isEmpty() { // true if queue is empty
return (nItems==0);
}
//-------------------------------------------------------------
public boolean isFull() { // true if queue is full
return (nItems==maxSize);
}
© e-Learning Centre, UCSC 57
The Queue.java Program Cont.

//-------------------------------------------------------------
public int size() { // number of items in queue
return nItems;
}
//-------------------------------------------------------------
} // end class Queue

© e-Learning Centre, UCSC 58


The Queue.java Program
class QueueApp {
public static void main(String[] args) {
Queue theQueue = new Queue(5); // queue holds 5 items
theQueue.insert(10); // insert 4 items
theQueue.insert(20);
theQueue.insert(30);
theQueue.insert(40);
theQueue.remove(); // remove 3 items
theQueue.remove(); // (10, 20, 30)
theQueue.remove();
theQueue.insert(50); // insert 4 more items
theQueue.insert(60); // (wraps around)
theQueue.insert(70);
theQueue.insert(80);
while( !theQueue.isEmpty() ) { // remove and display all items
int n = theQueue.remove(); // (40, 50, 60, 70, 80)
System.out.print(n);
© e-Learning Centre, UCSC 59
The Queue.java Program

System.out.print(" ");
}
System.out.println("");
} // end main()
} // end class QueueApp

© e-Learning Centre, UCSC 60


3.2.1.2 Linked List based Queue implementation

• The ListQueue class is similar to the ListStack class.

• The only new thing here is that we maintain two


references instead of one.

© e-Learning Centre, UCSC 61


3.2.1.2 Linked List based Queue implementation cont.

• Skeleton for the linked list-based queue class.


public class ListQueue<AnyType>
{
public ListQueue( ){}
public boolean isEmpty( ){}
public void enqueue( AnyType x ){}
public AnyType dequeue( ){}
public AnyType getFront( ){}
public void makeEmpty( ){}

private ListNode<AnyType> front;


private ListNode<AnyType> back;
} © e-Learning Centre, UCSC 62
3.2.1.2 Linked List based Queue implementation cont.

• Constructor for the linked list-based ListQueue class

public ListQueue( ){
front = back = null;
}

© e-Learning Centre, UCSC


63
3.2.1.2 Linked List based Queue implementation cont.

• The enqueue and dequeue routines for the ListQueue


class
public void enqueue( AnyType x ) {
if( isEmpty( ) )
back = front = new ListNode<AnyType>( x );
else
back = back.next = new ListNode<AnyType>( x );
}
public AnyType dequeue( ){
if( isEmpty( ) )
throw new UnderflowException( "ListQueue dequeue" );
AnyType returnValue = front.element;
front = front.next;
return returnValue;
} © e-Learning Centre, UCSC 64
3.2.1.2 Linked List based Queue implementation cont.

• Supporting routines for the ListQueue class


public AnyType getFront( ){
if( isEmpty( ) )
throw new UnderflowException( "ListQueue getFront" );
return front.element;
}
public void makeEmpty( ){
front = null;
back = null;
}
public boolean isEmpty( ){
return front == null;
}
© e-Learning Centre, UCSC 65
3.2.2 Applications of queues

Following are some of the applications of queues


Direct Applications
• Operating systems schedule jobs (with equal priority) in
the order of arrival (e.g., a print queue).
• Simulation of real-world queues such as lines at a ticket
counter or any other first-come first-served scenario
requires a queue.
• Multiprogramming.
• Asynchronous data transfer (file IO, pipes, sockets).
• Waiting times of customers at call center.
• Determining number of cashiers to have at a supermarket.
Indirect Applications
• Auxiliary data structure for algorithms
• Component of other data structures

© e-Learning Centre, UCSC 66


3.2.3 Circular queue

• When we insert a new item in the queue in the Workshop


applet, the Front arrow moves upward, toward higher
numbers in the array.
• When we remove an item, Rear also moves upward.
• we may find the arrangement counter-intuitive, because
the people in a line at the movies all move forward,
toward the front, when a person leaves the line.
• We could move all the items in a queue whenever we
deleted one, but that wouldn't be very efficient.
• Instead we keep all the items in the same place and move
the front and rear of the queue.

© e-Learning Centre, UCSC 67


A Circular Queue cont.

• To avoid the problem of not being able to insert more


items into the queue even when it's not full, the Front and
Rear arrows wrap around to the beginning of the array.
The result is a circular queue.

© e-Learning Centre, UCSC 68


Circular Queue Cont.

• There are two problems associated with linear queue.


• They are:
• Time consuming: linear time to be spent in shifting the
elements to the beginning of the queue.
• Signaling (indicating) queue full: even if the queue is
having vacant position.

© e-Learning Centre, UCSC 69


Circular Queue Cont.

© e-Learning Centre, UCSC 70


For example, let us consider a linear

• If one wants to insert 66 to the queue.


• The rear crossed the maximum size of the queue (i.e., 5).
• There will be queue full signal.
• The queue status is as follows:

© e-Learning Centre, UCSC 71


For example, let us consider a linear

• The queue status is as follows:

• This difficulty can be overcome if we treat queue position


with index zero as a position
• that comes after position with index four then we treat the
queue as a circular queue.

© e-Learning Centre, UCSC 72


Representation of Circular Queue cont..

• Let us consider a circular queue, which can hold maximum


(MAX) of six elements.
• Initially the queue is empty.

© e-Learning Centre, UCSC 73


Representation of Circular Queue cont.

• Now, insert 11 to the circular queue. Then circular


queue status will be:

© e-Learning Centre, UCSC 74


Representation of Circular Queue cont..

• Insert new elements 22, 33, 44 and 55 into the


circular queue

© e-Learning Centre, UCSC 75


Representation of Circular Queue cont.

• Now, delete an element. The element deleted is the


element at the front of the circular queue. So, 11 is
deleted

© e-Learning Centre, UCSC 76


Representation of Circular Queue cont.

• Again, delete an element. The element to be deleted


is always pointed to by the FRONT pointer. So, 22 is
deleted.

© e-Learning Centre, UCSC 77


Representation of Circular Queue cont.

• Again, insert another element 66 to the circular


queue

© e-Learning Centre, UCSC 78


Representation of Circular Queue cont..

• Now, insert new elements 77 and 88 into the circular


queue

© e-Learning Centre, UCSC 79


Wraparound routine(increment)‫‏‬

//internal method to increment with wraparound


// param x any index in theArray’s range.
// return x+1, or 0, if x is at the end of the array.
Private int increment( int x)‫‏‬
{
If (++x==theArray.length)‫ ‏‬//maxarray-1
x=0
return x;
} A B

C D E F G H I
© e-Learning Centre, UCSC 80
Wraparound routine(increment)‫‏‬

The increment routine adds 1 to its parameter and


returns the new value. Since it implements wraparound,
if the result would equal the array size it is wraparound
to zero.

© e-Learning Centre, UCSC 81


Representation of Circular Queue cont..

• Now, if we insert an element to the circular queue, as


COUNT = maxarray-1, we cannot add the element to
circular queue.
• So, the circular queue is full.

© e-Learning Centre, UCSC 82


3.2.4. Priority Queues

• A priority queue is a more specialized data structure than


a stack or a queue.
• However, it's a useful tool in a surprising number of
situations.
• Like an ordinary queue, a priority queue has a front and a
rear, and items are removed from the front.
• However, in a priority queue, items are ordered by key
value, so that the item with the lowest key (or in some
implementations the highest key) is always at the front.
• Items are inserted in the proper position to maintain the
order.

© e-Learning Centre, UCSC 83


Efficiency of Priority Queues

• In the priority-queue implementation we show here,


insertion runs in O(N) time, while deletion takes O(1) time.

© e-Learning Centre, UCSC 84


Summary

A stack is a linear data structure in which elements


3.1 are added and removed only from one end. LIFO

3.2 A queue is a linear data structure in which the


element that is inserted first is the first one to be
taken out. FIFO

A priority queue is a data structure in which each


3.2.4 element is assigned a priority.

© e-Learning Centre, UCSC 85


4 : Recursion

IT 3206 – Data Structures and Algorithms

Level II - Semester 3

© e-Learning Centre, UCSC


Overview

• This section introduces recursion and discusses the


differences between iteration and recursion approaches.

• How recursion works and theories behind recursion will be


also illustrated in this section.

• Further in this section, different implementations of


recursions will be discussed.

© e-Learning Centre, UCSC 2


Intended Learning Outcomes

• At the end of this lesson, you will be able to;


• Explain the importance of recursion
• Classify recursive methods
• Explain method calls in a recursion
• Compare different types of recursion

© e-Learning Centre, UCSC 3


List of Subtopics

4.1. Introduction to Recursion


4.2. Recursion versus iteration
4.3. How recursion works
4.4. Implementation in recursion
4.4.1. Tail recursion
4.4.2. Nontail recursion
4.4.3. Indirect recursion
4.4.4. Nested Recursion
4.4.5. Excessive recursion

© e-Learning Centre, UCSC 4


4.1. Introduction to Recursion

• Any function which calls another instance of the same


function is called recursive.
• A recursive method solves a problem by calling another
instance of itself to work on a smaller problem. This is called
the recursion step. The recursion step can result in many
more such recursive calls.
• It is important to ensure that the recursion terminates.
Each time the function calls itself with a slightly simpler
version of the original problem. The sequence of smaller
problems must eventually converge on the base case.

© e-Learning Centre, UCSC 5


4.1. Introduction to Recursion Contd.

• Recursion breaks a problem into smaller identical problems.


• Each recursion call solves an identical but smaller
problem.

• Recursion stops the break-down process at a special case


whose solution is obvious. That case is called a base case.
• Each recursive call will check the base case condition to
eventually stop.
• Otherwise, recursion falls into an infinite recursion.

© e-Learning Centre, UCSC 6


4.2. Recursion versus Iteration

Recursion Iteration

Terminates when a base case is reached. Terminates when a condition is proven to


be false.

Each recursive call requires extra space on Each iteration does not require extra space.
the stack frame (memory).

If we get infinite recursion, the program An infinite loop could loop forever since
may run out of memory and result in stack there is no extra memory being created.
overflow.

Solutions to some problems are easier to Iterative solutions to a problem may not
formulate recursively. always be as obvious as a recursive
solution.

© e-Learning Centre, UCSC 7


4.3. How Recursion Works

• When we use recursion, we solve a problem by reducing it


to a simpler problem of the same kind.

• We keep doing this until we reach a problem that is simple


enough to be solved directly.

• This simplest problem is known as the base case.

public static void printSeries(int n1, int n2) {


if (n1 == n2) { // base case
System.out.println(n2);
} else {
System.out.print(n1 + ", ");
printSeries(n1 + 1, n2);
}
}
© e-Learning Centre, UCSC 8
4.3. How Recursion Works Contd.

• The base case stops the recursion, because it doesn't make


another call to the method.

• If the base case hasn't been reached, we execute the


recursive case.

public static void printSeries(int n1, int n2) {


if (n1 == n2) { // base case
System.out.println(n2);
} else { // recursive case
System.out.print(n1 + ", ");
printSeries(n1 + 1, n2);
}
}

© e-Learning Centre, UCSC 9


4.3. How Recursion Works Contd.

• The recursive case:


• reduces the overall problem to one or more simpler
problems of the same kind
• makes recursive calls to solve the simpler problems

• Structure of a recursive method:

recursiveMethod(parameters) {
if (stopping condition) {
// handle the base case
} else {
// recursive case:
// possibly do something here
recursiveMethod(modified parameters);
possibly do something here
}
}
© e-Learning Centre, UCSC 10
4.3. How Recursion Works Contd.

• There can be multiple base cases and recursive cases.

• When we make the recursive call, we typically use


parameters that bring us closer to a base case.

• We have to ensure that a recursive method will eventually


reach a base case, regardless of the initial input.

• Otherwise, we can get infinite recursion, which produces


stack overflow.

© e-Learning Centre, UCSC 11


Example : Factorial

• Let us write a recursive program to perform a popular


mathematical calculation.

• Consider the factorial of a positive integer n, written n!

• Which is the product

n * (n – 1) * (n – 2) * … * 1

with 1! equal to 1 and 0! defined to be 1.

© e-Learning Centre, UCSC 12


Example : Factorial Contd.

• A recursive declaration of the factorial method is arrived at


by observing the following relationship:

n! = n * (n – 1)

• For an example, 5! can be broken down as follows.

5! = 5 * 4!
4! = 4 * 3!
3! = 3 * 2!
2! = 2 * 1!

1! = 1 which is given as a base condition.

© e-Learning Centre, UCSC 13


Example : Factorial Contd.

• Recursive evaluation of 5!.

© e-Learning Centre, UCSC 14


Example : Factorial Contd.

• Factorial recursive function pseudo code.

Fact(n)
Begin
if n == 0 or 1 then
Return 1;
else
Return n*Call Fact(n-1); // recursive call
endif
End

© e-Learning Centre, UCSC 15


Example : Factorial Contd.

• Factorial - recursive function java code.

static int factorial(int n){


if (n == 0 || n==1){
return 1;
} else {
return(n * factorial(n-1)); //recursive call
}
}

© e-Learning Centre, UCSC 16


4.4. Implementation in Recursion

• There are several implementations of recursions based on


how the recursive call is placed in the function.

• Tail Recursion
• NonTail Recursion
• Indirect Recursion
• Nested Recursion
• Excessive Recursion

© e-Learning Centre, UCSC 17


4.4.1. Tail Recursion

• All recursive definitions contain a reference to a set or


function being defined.

• There are, however, a variety of ways such a reference can


be implemented.

• This reference can be done in a straightforward manner or


in an intricate fashion, just once or many times.

• There may be many possible levels of recursion or different


levels of complexity.

© e-Learning Centre, UCSC 18


4.4.1. Tail Recursion Contd.

• Tail recursion is characterized by the use of only one


recursive call at the very end of a method implementation.

• In other words, when the call is made, there are no


statements left to be executed by the method; the recursive
call is not only the last statement but there are no earlier
recursive calls, direct or indirect.

© e-Learning Centre, UCSC 19


4.4.1. Tail Recursion Contd.

• Example : The method tail() defined as

void tail (int i) {


if (i > 0) {
System.out.print (i + “ ”);
tail (i-1);
}
}

© e-Learning Centre, UCSC 20


4.4.1. Tail Recursion Contd.

• Tail recursion is simply a glorified loop and can be easily


replaced by one.

• In this example, it is replaced by substituting a loop for the if


statement and incrementing or decrementing the variable i
in accordance with the level of recursion.

• In this way, tail ( ) can be expressed by an iterative method:


void iterativeEquivalentOfTail(int i) {
for ( ; i > 0; i-- )
System. out. print (i+ "");
}

© e-Learning Centre, UCSC


21
4.4.1. Tail Recursion Contd.

• Is there any advantage in using tail recursion over iteration?

• For languages such as Java, there may be no


compelling advantage, but in a language such as
Prolog, which has no explicit loop construct (loops are
simulated by recursion), tail recursion acquires a much
greater weight.

• In languages endowed with a loop or its equivalents,


such as an if statement combined with a goto statement
or labeled statement, tail recursion should not be used.

© e-Learning Centre, UCSC 22


4.4.2. NonTail Recursion

• Recursions that are not tail recursions are called non- tail
recursions.

• Here is a simple non-tail recursive implementation:

void reverse() {
char ch = getChar();
if (ch != '\n') {
reverse() ;
System.out.print(ch);
}
}

© e-Learning Centre, UCSC 23


4.4.3. Indirect Recursion

• Direct recursion - where a method f( ) called itself.

• f( ) can call itself indirectly via a chain of other calls. For


example, f( ) can call g(), and g( ) can call f( ) . This is the
simplest case of indirect recursion.

• The chain of intermediate calls can be of an arbitrary length,


as in:

f() → f1() → f2() → ……………….. → fn() → f()

© e-Learning Centre, UCSC 24


4.4.3. Indirect Recursion Contd.

• There is also the situation when f( ) can call itself indirectly


through different chains.

• Thus, in addition to the chain just given, another chain might


also be possible. For instance

f() → g1() → g2() → ……………….. → gm() → f()

© e-Learning Centre, UCSC 25


4.4.3. Indirect Recursion Contd.

• This situation can be exemplified by three methods used for


decoding information.
• receive() stores the incoming information in a buffer
• decode() converts it into legible form
• store() stores it in a file

• receive() fills the buffer and calls decode(), which in turn,


after finishing its job, submits the buffer with decoded
information to store().

• After store() accomplishes its tasks, it calls receive() to


intercept more encoded information using the same buffer.

© e-Learning Centre, UCSC


26
4.4.3. Indirect Recursion Contd.

• Therefore, we have the chain of calls

receive() → decode() → store() → receive() → …………...

• Above three methods work in the following manner:

receive (buffer)
while buffer is not filled up
if information is still incoming
get a character and store it in buffer;
else exit( );
decode (buffer);

© e-Learning Centre, UCSC 27


4.4.3. Indirect Recursion Contd.

decode (buffer)
decode information in buffer;
store (buffer);

store (buffer)
transfer information from buffer to file;
receive (buffer);

• As usual in the case of recursion, there has to be an


anchor in order to avoid falling into an infinite loop of
recursive calls.

© e-Learning Centre, UCSC


28
4.4.4. Nested Recursion

• A more complicated case of recursion is found in definitions


in which a function is not only defined in terms of itself, but
also is used as one of the parameters. The following
definition is an example of such a nesting:

© e-Learning Centre, UCSC 29


4.4.4. Nested Recursion Contd.

• Function h has a solution for all n >= 0.

This fact is obvious for all n > 4 and n = 0, but it has to be


proven for n = 1,2,3, and 4.

Thus, h(2) = h(2 + h(4)) = h(2 + h(2 + h(8))) = 12.

What are the values of h(n) for n = 1,3, and 4?

© e-Learning Centre, UCSC 30


4.4.4. Nested Recursion Contd.

• Another example of nested recursion is a very important


function originally suggested by Wilhelm Ackermann in 1928
and later modified by Rozsa Peter:

© e-Learning Centre, UCSC 31


4.4.4. Nested Recursion Contd.

• Above function is interesting because of its remarkably rapid


growth.

• It grows so fast that it is guaranteed not to have a


representation by a formula that uses arithmetic operations
such as addition, multiplication, and exponentiation.

© e-Learning Centre, UCSC 32


4.4.4. Nested Recursion Contd.

• To illustrate the rate of growth of the Ackermann function,


we need only show that

• with a stack of m 2s in the exponent;

which exceeds even the number of atoms in the universe


(which is 1080 according to current theories).

• The definition translates very nicely into Java, but the task
of expressing it in a non-recursive form is truly troublesome.

© e-Learning Centre, UCSC 33


4.4.5. Excessive Recursion

• Logical simplicity and readability are used as an argument


supporting the use of recursion.

• The price for using recursion is slowing down execution time


and storing on the run-time stack more things than required
in a non-recursive approach.

• If recursion is too deep (for example, computing 5.6100'000),


then we can run out of space on the stack and our program
terminates abnormally by raising an unrecoverable
StackOverflowError.

© e-Learning Centre, UCSC 34


4.4.5. Excessive Recursion Contd.

• But usually, the number of recursive calls is much smaller


than 100,000, so the danger of overflowing the stack may
not be imminent. However, if some recursive function
repeats the computations for some parameters, the run time
can be prohibitively long even for very simple cases.

• Consider Fibonacci numbers. A sequence of Fibonacci


numbers is defined as follows:

© e-Learning Centre, UCSC 35


4.4.5. Excessive Recursion Contd.

• The definition states that if the first two numbers are 0 and
1, then any number in the sequence is the sum of its two
predecessors. But these predecessors are in turn sums of
their predecessors, and so on, to the beginning of the
sequence. The sequence produced by the definition is

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...

© e-Learning Centre, UCSC 36


4.4.5. Excessive Recursion Contd.

• How can this definition be implemented in Java? It takes


almost term-by-term translation to have a recursive version,
which is

int Fib(int n) {
if (n < 2)
return n;
else return Fib(n-2) + Fib(n-l);
}

• The method is simple and easy to understand but extremely


inefficient fibonacci heap.

© e-Learning Centre, UCSC 37


Summary

Introduction to Any function which calls itself is called


Recursion recursive.

Solutions to some problems are


Recursion versus easier to formulate recursively than
Iteration iteratively.

Recursion solve a problem by


How Recursion
reducing it to a simpler problem of the
Works same kind.

Tail recursion, Nontail recursion,


Implementation in Indirect recursion, Nested Recursion,
Recursion Excessive recursion

© e-Learning Centre, UCSC 38


5 : Trees

IT 3206– Data Structures and Algorithms

Level II - Semester 3

© e-Learning Centre, UCSC


Overview

• In this chapter, you will learn about a non-linear data structure


called tree.
• A tree is a structure which is mainly used to store data that is
hierarchical in nature.
• Further, from this chapter you will learn the followings :
• Introduction to trees.
• Different types of selected trees and their application
• Implementation of different trees

© e-Learning Centre, UCSC 2


Intended Learning Outcomes

• At the end of this lesson, you will be able to;


• Explain tree structures and properties.
• Demonstrate implementation of trees, tree traversal
techniques and tree balancing techniques.
• Explain the usage of a heap

© e-Learning Centre, UCSC 3


List of subtopics

5.1 Introduction to trees


5.1.1 Introduction to general trees, properties of general trees
5.1.2 Introduction to binary trees, properties of binary trees
5.2 Tree traversal
5.2.1 Depth First Traversal
5.2.1.1 Preorder Traversal
5.2.1.2 Inorder Traversal
5.2.1.3 Postorder Traversal
5.2.2 Breadth First Traversal (Level Order Traversal)
5.3 Binary search trees
5.4 Tree Balancing
5.4.1 Introduction to tree balancing
5.4.2 Global tree balancing (The DSW algorithm)
5.4.3 Local tree balancing (AVL Tree)
5.5 Heaps
© e-Learning Centre, UCSC 4
5.1 Introduction to trees

• A tree is a data structure similar to a linked list but instead of each


node pointing simply to the next node in a linear fashion, each
node points to a number of nodes.
• Tree is an example of a nonlinear data structure.
• A tree structure is a way of representing the hierarchical nature of
a structure in a graphical form.(think of a family tree, where the
children are grouped under their parents in the tree)

© e-Learning Centre, UCSC 5


5.1 Introduction to trees

• Tree is one of the most important non-linear data structures in


computing.
• Different types of trees discuss in this chapter.
• General tree — each node can have an arbitrary number of children.
• Binary tree — each node has at most two children
• Binary search trees
• AVL trees

• It allows us to implement faster algorithms( compared with


algorithms using linear data structures).
• Mostly all operating systems store files in trees or tree like structures.
• Compilers use a syntax tree to validate the syntax of every program you
write
• Practical usage in trees
• Mostly all operating systems store files in trees or tree like structures.
• Compilers use a syntax tree to validate the syntax of every program you
write

© e-Learning Centre, UCSC 6


5.1 Introduction to trees

• Features and application of trees

• A binary tree is a type of data structure for storing data such


as numbers in an organized way.
• Binary search trees allow binary search for fast lookup,
addition and removal of data items, and can be used to
implement dynamic sets and lookup tables
• Directory structure in many common operating systems,
including Unix, DOS, and windows.
• AVL trees are mostly used for in-memory sorts of sets and
dictionaries.
• AVL trees are also used extensively in database applications
in which insertions and deletions are fewer but there are
frequent lookups for data required.

© e-Learning Centre, UCSC 7


5.1 Introduction to trees

Example for a general tree:

© e-Learning Centre, UCSC 8


5.1.1 Introduction to general trees, properties of
general trees

• A tree consists of a set of nodes and a set of directed edges that


connect pairs of nodes.
• A tree has the following properties.
• One node is distinguished as the root.
• Every node c, except the root, is connected by an edge from exactly one other
node p. Node p is c’s parent, and c is one of p’s children.
• A unique path traverses from the root to each node. The number of edges
that must be followed is the path length.

• Parents and children are naturally defined.


• A directed edge connects the parent to the child.
• Trees can be defined in two ways :
• Recursive
• Non- recursive
Implementation of the tree is more convenient in a recursive
approach than a non-recursive approach.
© e-Learning Centre, UCSC 9
5.1.1 Introduction to general trees, properties of
general trees

Non-recursive definition:
• A (rooted) tree consists of a set of nodes, and a set of directed
edges between nodes.
• One node is the root; For every node c that is not the root, there
is exactly one edge (p, c) pointing to c;
• For every node c there is a unique path from the root to c.

© e-Learning Centre, UCSC 10


5.1.1 Introduction to general trees, properties of
general trees

General trees - definition:

• A tree is a collection of nodes. The collection can be empty;


otherwise a tree consists of a distinguish node n, called root,
and zero or more non-empty (sub)trees T1,T2,T3,….Tn. . Each of
whose roots are connected by a directed edge from n.

© e-Learning Centre, UCSC 11


5.1.1 Introduction to general trees, properties of
general trees
Recursive definition:
Example:

© e-Learning Centre, UCSC 12


5.1.1 Introduction to general trees, properties of
general trees

A tree is a collection of nodes. The collection can be empty; otherwise a


tree consists of a distinguish node r, called root, and zero or more nonempty
(sub)trees T1,T2,T3,….TK. Each of whose roots are connected by a directed edge
from r.

• The root node is A.


• A’s children are B, C, D, and E.
• Since A is the root, it has no parent; all
other nodes have parents.
• For instance, B’s parent is A.
• A node that has no children is called a
leaf.
• The leaves in this tree are C, F, G, H, I,
and K.
• The length of the path from A to K is 3
(edges)
• The length of the path from A to A is 0
(edges).
© e-Learning Centre, UCSC
13
5.1.1 Introduction to general trees, properties of
general trees

• Basic Terminology
• tree - a non-empty collection of vertices & edges
• vertex (node) - can have a name and carry other associated
information
• path - list of distinct vertices in which successive vertices are
connected by edges
• Sub-trees -If the root node R is not NULL, then the trees T1,
T2, and T3 are called the sub-trees of R.
• Leaf node -A node that has no children is called the leaf node
or the terminal node.
• Non-leaf node-In any tree the node which has at least one
child is called internal/non-leaf node.

© e-Learning Centre, UCSC 14


5.1.1 Introduction to general trees, properties of
general trees

• Basic Terminology
• Level number Every node in the tree is assigned a level
number in such a way that the root node is at level 0, children
of the root node are at level number 1.
• Thus, every node is at one level higher than its parent. So, all
child nodes have a level number given by parent’s level
number + 1.
Example:

© e-Learning Centre, UCSC 15


5.1.1 Introduction to general trees, properties of
general trees

• Basic Terminology
• Degree: Degree of a node is equal to the number of children
that a node has.
• The degree of a leaf node is zero.
• In-degree: In-degree of a node is the number of edges
arriving at that node. For example, in degree of the node B is
one i.e. one edge merges.
• Out-degree: Out-degree of a node is the number of edges
leaving that node. For example, out degree of the node A is
two i.e. two edges comes out of this root node.

© e-Learning Centre, UCSC 16


5.1.1 Introduction to general trees, properties of
general trees

• A tree with N nodes must have N – 1 edges because every node


except the parent has an incoming edge.
• The depth of a node is the length of the path from the root to the
node.
• The height of a node is the length of the path from the node to
the deepest leaf.(Thus the height of E is 2)
• The height of any node is 1 more than the height of its maximum-
height child. Thus the height of a tree is the height of the root.
Example:

© e-Learning Centre, UCSC 17


5.1.1 Introduction to general trees, properties of
general trees

© e-Learning Centre, UCSC 18


5.1.1 Introduction to general trees, properties of
general trees

• Nodes with the same parent are


called siblings; thus B, C, D, and E
are all siblings
• If there is a path from node u to
node v, then u is an ancestor of v
and v is a descendant of u.
• If u ≠ v, then u is a proper ancestor
of v and v is a proper descendant
of u.
• The size of a node is the number of
descendants the node has
(including the node itself). Thus the
size of B is 3, and the size of C is 1.
• The size of a tree is the size of the
root. Thus the size of the tree
shown in Figure is the size of its
root A, or 11.
© e-Learning Centre, UCSC 19
5.1.1 Introduction to general trees, properties of
general trees

© e-Learning Centre, UCSC 20


5.1.1 Introduction to general trees, properties of
general trees

Representation of Trees
• Every tree node:
• object – useful information
• children – pointers to its children nodes

© e-Learning Centre, UCSC 21


5.1.1 Introduction to general trees, properties of
general trees

•A tree consists of set of nodes and set of edges that connected pair
of nodes.

© e-Learning Centre, UCSC 22


5.1.1 Introduction to general trees, properties of
general trees

List Representation of trees


● ( A ( B ( E ( K, L ), F ), C ( G ), D ( H ( M ), I, J ) ) )
● How many link fields are needed to represent the tree?
● The root comes first, followed by a list of sub-trees

● In worst case we need n links and for best case, we need 2 links

© e-Learning Centre, UCSC 23


5.1.1 Introduction to general trees, properties of
general trees

• Implementation
• One way to implement a tree would be to have in each node a
link to each child of the node in addition to its data.
• However, as the number of children per node can vary greatly
and is not known in advance, making the children direct links
in the data structure might not be feasible.
• There would be too much wasted space.
• The solution is called the first child/next sibling method

© e-Learning Centre, UCSC 24


5.1.1 Introduction to general trees, properties of
general trees

• first child/next sibling method


• Keep the children of each node in a linked list of tree nodes,
with each node keeping two links, one to its leftmost child (if
it is not a leaf) and one to its right sibling (if it is not the
rightmost sibling).

© e-Learning Centre, UCSC 25


5.1.2 Introduction to binary trees, properties of
binary trees

• A binary tree is a tree in which no node can have more than two
children.
• The two children of each node in a binary tree are called the left
child and the right child.
• A node in a binary tree doesn’t necessarily have the maximum of
two children; it may have only a left child, or only a right child, or
it can have no children at all (in which case it’s a leaf).

© e-Learning Centre, UCSC 26


5.1.2 Introduction to binary trees, properties of
binary trees

• An expression tree is one example of the use of binary trees. Such


trees are central data structures in compiler design.
• A second use of the binary tree is the Huffman coding tree, which
is used to implement a simple but relatively effective data
compression algorithm.
• Each symbol in the alphabet is stored at a leaf. Its code is obtained
by following the path to it from the root.
Examples :

© e-Learning Centre, UCSC 27


5.1.2 Introduction to binary trees, properties of
binary trees

• Types of Binary Trees


• Strict Binary Tree: A binary tree is called strict binary tree if
each node has exactly two children or no children.

© e-Learning Centre, UCSC 28


5.1.2 Introduction to binary trees, properties of
binary trees

• Full Binary Tree: A binary tree is called full binary tree if each
node has exactly two children and all leaf nodes are at the
same level.

© e-Learning Centre, UCSC 29


5.1.2 Introduction to binary trees, properties of
binary trees

• Complete Binary Tree: A binary tree is called complete binary


tree if all leaf nodes are at height h or h – 1 and also without
any missing number in the sequence.

© e-Learning Centre, UCSC 30


5.1.2 Introduction to binary trees, properties of
binary trees

• Properties of Binary Trees


Let us assume that the height of the tree is h. Also, assume that
root node is at height zero.

© e-Learning Centre, UCSC 31


5.1.2 Introduction to binary trees, properties of
binary trees

© e-Learning Centre, UCSC 32


5.1.2 Introduction to binary trees, properties of
binary trees

• Properties of Binary Trees

© e-Learning Centre, UCSC 33


5.1.2 Introduction to binary trees, properties of
binary trees

• Properties of Binary Trees


• The number of nodes n in a full binary tree is 2h+1 – 1. Since,
there are h levels we need to add all nodes at each level [20
+ 21+ 22 + ··· + 2h = 2h+1 – 1].
• The number of nodes n in a complete binary tree is between
2h (minimum) and 2h+1 – 1 (maximum).
• The number of leaf nodes in a full binary tree is 2h.
• The number of NULL links (wasted pointers) in a complete
binary tree of n nodes is n + 1.

© e-Learning Centre, UCSC 34


5.1.2 Introduction to binary trees, properties of
binary trees

• Properties of Binary Trees

© e-Learning Centre, UCSC 35


5.1.2 Introduction to binary trees, properties of
binary trees

• Representation of Binary Trees in the Memory


• In the computer’s memory, a binary tree can be maintained
either by using a linked representation or by using a
sequential representation.
• In the linked representation of a binary tree, every node will
have three parts: the data element, a pointer to the left
node, and a pointer to the right node.

© e-Learning Centre, UCSC 36


5.1.2 Introduction to binary trees, properties of
binary trees

• Representation of Binary Trees in the Memory


• Sequential representation of trees is done using single or
one-dimensional arrays.
• A one-dimensional array, called TREE, is used to store the
elements of tree.
• The root of the tree will be stored in the first location. That
is, TREE[1] will store the data of the root element.
• The children of a node stored in location K will be stored in
locations (2 × K) and (2 × K+1).
• The maximum size of the array TREE is given as (2h–1),
where h is the height of the tree.
• An empty tree or sub-tree is specified using NULL. If TREE[1]
= NULL, then the tree is empty.
© e-Learning Centre, UCSC 37
5.1.2 Introduction to binary trees, properties of
binary trees

• Sequential representation of Binary Tree

© e-Learning Centre, UCSC 38


5.1.2 Introduction to binary trees, properties of
binary trees

• Representation of Binary Trees in the Memory (pointer based)


In the computer’s memory, a binary tree can be maintained either by
using a linked representation or by using a sequential
representation.
• Linked representation of binary trees
• In the linked representation of a binary tree, every node will
have three parts:
• the data element,
• a pointer to the left node, and
• a pointer to the right node.
•So in JAVA, the binary tree is built with a node type given below

© e-Learning Centre, UCSC 39


5.1.2 Introduction to binary trees, properties of
binary trees

• Implementation of Binary trees


class Node
{
int key;
Node left, right;

public Node(int item)


{
key = item;
left = right = null;
}
}

© e-Learning Centre, UCSC 40


5.1.2 Introduction to binary trees, properties of
binary trees

• Representation of Binary Trees in the Memory (pointer


based)

© e-Learning Centre, UCSC 41


5.1.2 Introduction to binary trees, properties of
binary trees

The above tree is represented in the main memory using a linked list
as follows:

© e-Learning Centre, UCSC 42


5.1.2 Introduction to binary trees, properties of
binary trees

• Implementation of Binary trees


There are other approaches to designing class Node. Instead of
placing the data items directly into the node, you could use a
reference to an object representing the data item:
class Node
{
person p1; // reference to person object
node leftChild; // this node's left child
node rightChild; // this node's right child
}
class person
{
int iData;
float fData;
} © e-Learning Centre, UCSC 43
5.2 Tree traversal

• The process of visiting all nodes of a tree is called tree traversal.


• Each node is processed only once but it may be visited more
than once.
• As we have already seen in linear data structures (like linked
lists, stacks, queues, etc.), the elements are visited in sequential
order. But, in tree structures there are many different ways.
• Tree traversal is like searching the tree, except that in traversal
the goal is to move through the tree in a particular order.
• In addition, all nodes are processed in the traversal but
searching stops when the required node is found.

© e-Learning Centre, UCSC 44


5.2.1 Depth First Traversal

• There are three basic traversal mechanisms under the Depth


First Traversal :
• Pre-order traversal
• In-order traversal
• Post-order traversal

© e-Learning Centre, UCSC 45


5.2.1 Depth First Traversal

• Pre-order traversal
• In preorder traversal, each node is processed before (pre)
either of its sub trees.
• Even though each node is processed before the sub trees, it
still requires that some information must be maintained
while moving down the tree.
• In the figure below, 1 is processed first, then the left sub
tree, and this is followed by the right sub tree.

© e-Learning Centre, UCSC 46


5.2.1 Depth First Traversal

• Pre-order traversal
• Therefore, processing must return to the right sub tree after
finishing the processing of the left sub tree.
• To move to the right sub tree after processing the left sub
tree, we must maintain the root information.

• Algorithm
• Preorder traversal is defined as follows:
• Visit the root.
• Traverse the left sub tree in Preorder.
• Traverse the right sub tree in Preorder.

© e-Learning Centre, UCSC 47


5.2.1 Depth First Traversal

• Pre-order traversal

Algorithm Example 1 :Traversal order

© e-Learning Centre, UCSC 48


5.2.1 Depth First Traversal

• Pre-order traversal
Example 2 :

The nodes of tree would be visited in the order: 1 2 4 5 3 6 7

© e-Learning Centre, UCSC 49


5.2.1 Depth First Traversal

• Pre-order traversal
Code segment :
private void preOrder(Node localRoot)
{
if(localRoot != null)
{
System.out.print(localRoot.iData + “ “);
preOrder(localRoot.leftChild);
preOrder(localRoot.rightChild);
}
}

© e-Learning Centre, UCSC 50


5.2.1 Depth First Traversal

• In-order traversal
• In In-order Traversal the root is visited between the sub
trees.

• Algorithm
• In-order traversal is defined as follows:
• Traverse the left sub tree in In-order.
• Visit the root.
• Traverse the right sub tree in In-order.

© e-Learning Centre, UCSC 51


5.2.1 Depth First Traversal

• In-order traversal
Example 1 :Traversal order
Algorithm

© e-Learning Centre, UCSC 52


5.2.1 Depth First Traversal

• In-order traversal
Example 2 :

The nodes of tree would be visited in the order: 4 2 5 1 6 3 7

© e-Learning Centre, UCSC 53


5.2.1 Depth First Traversal

• In-order traversal
Code segment :
private void inOrder(Node localRoot)
{
if(localRoot != null)
{
inOrder(localRoot.leftChild);
System.out.print(localRoot.iData + “ “);
inOrder(localRoot.rightChild);
}
}

© e-Learning Centre, UCSC


54
5.2.1 Depth First Traversal

• Post-order traversal
• In post-order traversal, the root is visited after both sub
trees.

• Algorithm
• Post-order traversal is defined as follows:
• Traverse the left sub tree in Post-order.
• Traverse the right sub tree in Post-order.
• Visit the root.

© e-Learning Centre, UCSC 55


5.2.1 Depth First Traversal

• Post-order traversal

Example 1 :Traversal order


Algorithm

© e-Learning Centre, UCSC 56


5.2.1 Depth First Traversal

• Post-order traversal
Example 2 :

The nodes of the tree would be visited in the order: 4 5 2 6 7 3 1

© e-Learning Centre, UCSC 57


5.2.1 Depth First Traversal

• Post-order traversal
Code segment :
private void postOrder(Node localRoot)
{
if(localRoot != null)
{
postOrder(localRoot.leftChild);
postOrder(localRoot.rightChild);
System.out.print(localRoot.iData + “ “);
}
}
© e-Learning Centre, UCSC 58
5.2.1 Depth First Traversal

Example:

© e-Learning Centre, UCSC 59


5.2.2 Breadth First Traversal

• breadth-first search (BFS) is a graph search algorithm that


begins at the root node and explores all the neighboring nodes.
Then for each of those nearest nodes, it explores their
unexplored neighbor nodes, and so on, until it finds the goal.

• This algorithm is also called as the breadth-first


traversal/Breadth search (BFT/BFS) Algorithm or Level order
traversal algorithm

© e-Learning Centre, UCSC 60


5.2.2 Breadth First Traversal

• In level-order traversal, all the nodes at a level are accessed


before going to the next level.
• Level order traversal is defined as follows:
• Visit the root.
• While traversing level (, keep all the elements at level ( + 1
in queue.
• Go to the next level and visit all the nodes at that level.
• Repeat this until all levels are completed.

© e-Learning Centre, UCSC 61


5.2.2 Breadth First Traversal

• How it works

• Breadth-first search (BFS) is an uninformed search method that


aims to expand and examine all nodes of a graph systematically
in search of a solution. In other words, it exhaustively searches
the entire graph without considering the goal until it finds it. It
does not use a heuristic.

• From the standpoint of the algorithm, all child nodes obtained


by expanding a node are added to a FIFO queue. In typical
implementations, nodes that have not yet been examined for
their neighbors are placed in some container (such as a queue
or linked list) called "open" and then once examined are placed
in the container "closed".

© e-Learning Centre, UCSC 62


5.2.2 Breadth First Traversal

• In the breadth first traversal, the nodes are visited level by level,
from left to right.

© e-Learning Centre, UCSC 63


5.2.1 Breadth First Traversal

• Example:

The nodes of the tree are visited in the order: 1 2 3 4 5 6 7

© e-Learning Centre, UCSC 64


5.2.2 Breadth First Traversal

• Applications of BFS

• Breadth-first search can be used to solve many problems in


graph theory, for example:
• Finding all connected components in a graph.
• Finding all nodes within one connected component
• Copying Collection, Cheney's algorithm
• Finding the shortest path between two nodes u and v (in an
unweighted graph)
• Testing a graph for bipartiteness
• (Reverse) Cuthill–McKee mesh numbering

© e-Learning Centre, UCSC 65


5.2.2 Breadth First Traversal

• Recursion cannot be used to implement a breadth-first traversal


since the recursive calls must follow the links that lead deeper
into the tree.
• The best way to save a node's children for later access is to use
a queue
• We can then use an iterative loop to move across the tree in the
correct node order to produce a breadth-first traversal.
• The above Listing uses a queue to implement the breadth first
traversal.
• The process starts by saving the root node and in turn priming
the iterative loop.
• During each iteration, we remove a node from the queue, visit it,
and then add its children to the queue.
• The loop terminates after all nodes have been visited.
© e-Learning Centre, UCSC 66
5.2.2 Breadth First Traversal

Pseudo-Code for Breadth-First Traversal


• put root node onto a queue
• while the queue is not empty
• dequeue the next node
• visit the node
• enqueue the left child node
• enqueue the right child node

© e-Learning Centre, UCSC 67


5.2.2 Breadth First Traversal

• Example

We start from node(1), and


put it in the queue

© e-Learning Centre, UCSC 68


5.2.2 Breadth First Traversal

• Example

Next, we go through all the neighbors of node(1) Again, we dequeue from the queue and this time we
and put all the unvisited node on the queue. node(2) get node(2). We print it and go for all the neighbor
and node(5) will go on to the queue and marked as node, node(3) and node(4) and mark them as
visited.Traversal = {1} visited.Traversal = {1,2}

© e-Learning Centre, UCSC 69


5.2.2 Breadth First Traversal

• Example

node(5) is dequeued next and printed. Here, even though Now, we pop node(3) and print it, however,
node(4) is a neighbor of node(5), it is already visited and node(4) is already visited. Hence, nothing is
hence not put on to the queue again. But node(6) is not added to the queue. Traversal = {1,2,5,3}
yet visited, so put it on to the queue.Traversal = {1,2,5}

© e-Learning Centre, UCSC 70


5.2.2 Breadth First Traversal

• Example

Next, node(4) is taken out from queue and Last, we pop node(6) and print it.
printed, nothing goes on to queue. Traversal = Traversal = {1,2,5,3,4,6}.
{1,2,5,3,4}

© e-Learning Centre, UCSC 71


5.3 Binary Search trees

• A binary search tree, also known as an ordered binary tree, is a


variant of binary trees in which the nodes are arranged in an
order.
• In binary search trees, all the left sub tree elements should be
less than root data and all the right sub tree elements should be
greater than root data. This is called binary search tree property.
• In a binary search tree, each non leaf node v stores an element e
such that
• the elements stored in the left sub tree of v are less than e.
• the elements stored in the right sub tree of v are greater
than or equal to e.
• Both the left and right sub trees must also be binary search
trees.
© e-Learning Centre, UCSC 72
5.3 Binary Search trees

© e-Learning Centre, UCSC 73


5.3 Binary Search trees

© e-Learning Centre, UCSC 74


5.3 Binary Search trees

• Operations on Binary Search Trees


• Searching an element in a binary search tree
• Find the minimum element from a binary search tree
• Find the maximum element from a binary search tree
• Inserting an element in a binary search tree
• Deleting an element from a binary search tree

© e-Learning Centre, UCSC 75


5.3 Binary Search trees

• Finding an Element in Binary Search Trees


• Find operation is straightforward in a BST.
• Start with the root and keep moving left or right using the
BST property.
• If the data we are searching is same as nodes data then we
return current node.
• If the data we are searching is less than nodes data then
search left sub tree of current node; otherwise search right
sub tree of current node.
• If the data is not present, we end up in a NULL link.

© e-Learning Centre, UCSC 76


5.3 Binary Search trees

• Finding an Element in Binary Search Trees


Algorithm:

© e-Learning Centre, UCSC 77


5.3 Binary Search trees

• Finding an Element in Binary Search Trees


Example 1: Find element 7

© e-Learning Centre, UCSC 78


5.3 Binary Search trees

• Finding the minimum element from a Binary Search Trees


Example 1:

© e-Learning Centre, UCSC 79


5.3 Binary Search trees

• Find the minimum element from a binary search tree


Algorithm:

© e-Learning Centre, UCSC 80


5.3 Binary Search trees

• Find the minimum element from a binary search tree


Example 2:

© e-Learning Centre, UCSC 81


5.3 Binary Search trees

• Find the minimum element from a binary search tree


Example 2:

© e-Learning Centre, UCSC 82


5.3 Binary Search trees

• Find the minimum element from a binary search tree


Example 2:

© e-Learning Centre, UCSC 83


5.3 Binary Search trees

• Find the maximum element from a binary search tree


Algorithm:

© e-Learning Centre, UCSC 84


5.3 Binary Search trees

• Find the maximum element from a binary search tree


Example:

© e-Learning Centre, UCSC 85


5.3 Binary Search trees

• Find the maximum element from a binary search tree


Example:

© e-Learning Centre, UCSC 86


5.3 Binary Search trees

• Find the maximum element from a binary search tree


Example:

© e-Learning Centre, UCSC 87


5.3 Binary Search trees

• Find the maximum element from a binary search tree


Example:

© e-Learning Centre, UCSC 88


5.3 Binary Search trees

• Inorder Predecessor and Successor


• If X has two children then its inorder predecessor is the
maximum value in its left sub tree and its inorder successor
the minimum value in its right sub tree.

© e-Learning Centre, UCSC 89


5.3 Binary Search trees

• Inorder Predecessor and Successor

If it does not have a left child, then a node’s inorder predecessor


is its first left ancestor.

© e-Learning Centre, UCSC 90


5.3 Binary Search trees

• Inserting an Element to Binary Search Tree


Example 1:

© e-Learning Centre, UCSC 91


5.3 Binary Search trees

• Inserting an Element to Binary Search Tree


• To insert data into binary search tree, first we need to find
the location for that element.
• We can find the location of insertion by following the same
mechanism as that of find operation.
• While finding the location, if the data is already there then
we can simply neglect and come out.
• Otherwise, insert data at the last location on the path
traversed.

© e-Learning Centre, UCSC 92


5.3 Binary Search trees

• Inserting an Element to Binary Search Tree


Algorithm:

© e-Learning Centre, UCSC 93


5.3 Binary Search trees

• Inserting an Element from Binary Search Tree


Example : Insert 10,12,5,4,20,8,7,15,13 to a Binary Search Tree

Final Tree

© e-Learning Centre, UCSC 94


5.3 Binary Search trees

• Inserting an Element from Binary Search Tree


Java implementation

public void insert(int id, double dd){


Node newNode = new Node(); // make new node
newNode.iData = id; // insert data
newNode.dData = dd;
if(root==null) // no node in root
root = newNode;
else // root occupied
{
Node current = root; // start at root
Node parent;
while(true) // (exits internally)
{
parent = current;
if(id < current.iData) // go left?
© e-Learning Centre, UCSC 95
{
5.3 Binary Search trees

• Inserting an Element from Binary Search Tree


Java implementation

current = current.leftChild;
if(current == null) // if end of the line,
{ // insert on left
parent.leftChild = newNode;
return;
}
} // end if go left

© e-Learning Centre, UCSC 96


5.3 Binary Search trees

• Inserting an Element from Binary Search Tree


Java implementation

else // or go right?
{
current = current.rightChild;
if(current == null) // if end of the line
{ // insert on right
parent.rightChild = newNode;
return;
}
} // end else go right
} // end while
} // end else not root
} // end insert()

© e-Learning Centre, UCSC 97


5.3 Binary Search trees

• Deleting an Element from Binary Search Tree


• The delete operation is more complicated than other
operations.
• This is because the element to be deleted may not be the
leaf node.
• In this operation also, first we need to find the location of
the element which we want to delete.
• Once we have found the node to be deleted, consider the
following cases:

© e-Learning Centre, UCSC 98


5.3 Binary Search trees

• Case 1: The Node to Be Deleted Has No Children


• If the element to be deleted is a leaf node: return NULL to
its parent. That means make the corresponding child pointer
NULL
• In the tree below to delete 5, set NULL to its parent node 2.

Example :

© e-Learning Centre, UCSC 99


5.3 Binary Search trees

• Case 1: The Node to Be Deleted Has No Children


Example 2 : Delete 78

© e-Learning Centre, UCSC 100


5.3 Binary Search trees

• Case 2: The Node to Be Deleted Has One Child


• If the element to be deleted has one child: In this case we
just need to send the current node’s child to its parent.
• In the tree below, to delete 4, 4 left sub tree is set to its
parent node 2.
Example :

© e-Learning Centre, UCSC 101


5.3 Binary Search trees

• Case 2: The Node to Be Deleted Has One Child


Example 2: Delete 54

© e-Learning Centre, UCSC 102


5.3 Binary Search trees

• Case 3: The Node to Be Deleted Has Two Children


• If the deleted node has two children, you can’t just replace it
with one of these children, at least if the child has its own
children.
• this method we shall use is to replace the node being
deleted by the rightmost node in its left sub-tree Or
Leftmost mode in its right-sub-tree.

© e-Learning Centre, UCSC 103


5.3 Binary Search trees

• Case 3: The Node to Be Deleted Has Two Children


Example:

© e-Learning Centre, UCSC 104


5.3 Binary Search trees

• Deleting an Element from Binary Search Tree


Algorithm (All three cases):

© e-Learning Centre, UCSC 105


5.3 Binary Search trees

• Height of a Binary Search Tree


• In order to determine the height of a binary search tree, we
calculate the height of the left sub-tree and the right sub-
tree.
• Recursive view used to calculate the height of a tree :
HT=max(HL +1 ,HR +1)

© e-Learning Centre, UCSC 106


5.3 Binary Search trees

• //* Return the height of the binary tree rooted at t.

If (t = = null)
return 0;
else
return 1+maximum(height(t->left),height(t- >right);

© e-Learning Centre, UCSC 107


5.3 Binary Search trees

• Size of a Binary Search tree

//* Return the size of the binary tree


ST=SL+SR+1 rooted at t.
if (t = = null)
return 0
else
return 1+size(t->left)+ size(t->right)

© e-Learning Centre, UCSC 108


5.3 Binary Search trees

• Balanced Binary Search Trees


• Binary search trees allow binary search for fast lookup, insertion
and deletion of data items, and can be used to implement
dynamic sets and lookup tables.
• The order of nodes in a BST means that each comparison skips
about half of the remaining tree, so the whole lookup takes time
proportional to the binary logarithm of the number of items stored
in the tree.
• Binary search trees are a nice idea, but they fail to accomplish our
goal of doing lookup, insertion and deletion each in time
O(log2(n)), when there are n items in the tree. Imagine starting with
an empty tree and inserting 1, 2, 3 and 4, in that order

© e-Learning Centre, UCSC 109


5.3 Binary Search trees

• Balanced Binary Search Trees


• Binary search trees are a nice idea, but they fail to accomplish our
goal of doing lookup, insertion and deletion each in time
O(log2(n)), when there are n items in the tree.
• Imagine starting with an empty tree and inserting 1, 2, 3 and 4, in
that order.

© e-Learning Centre, UCSC 110


5.3 Binary Search trees

• Self-Balancing Binary Search Trees


• A self-balancing binary search tree (BST) is a binary search tree that
automatically tries to keep its height as minimal as possible at all
times (even after performing operations such as insertions or
deletions).
• Hence having the height as small as possible is better when it
comes to performing a large number of operations. Hence, self-
balancing BSTs were introduced which automatically maintain the
height at a minimum.
• However, you may think having to self-balance every time an
operation is performed is not efficient, but this is compensated by
ensuring a large number of fast operations which will be performed
later on the BST.

© e-Learning Centre, UCSC 111


5.3 Binary Search trees

• Self-Balancing Binary Search Trees


A binary tree with height h can have at most 20+21+..2h = 2(h+1) -1 nodes

Hence, for self-balancing BSTs, the minimum height must always be log₂(n)
rounded down. Moreover, a binary tree is said to be balanced if the height
of left and right children of every node differ by either -1, 0 or +1. This value
is known as the balance factor.

© e-Learning Centre, UCSC 112


5.3 Binary Search trees

• How do Self-Balancing Binary Search Trees Balance?

When it comes to self-balancing, BSTs perform rotations after performing


insert and delete operations.
Given below are the two types of rotation operations that can be performed
to balance BSTs without violating the binary-search-tree property.
• Left rotation
• Right rotation

© e-Learning Centre, UCSC 113


5.3 Binary Search trees

• Left rotation
When we left rotate about node x, node y becomes the new root of
the subtree. Node x becomes the left child of node y and subtree b
becomes the right child of node x.

© e-Learning Centre, UCSC 114


5.3 Binary Search trees

• Right rotation
When we right rotate about node y, node x becomes the new root
of the subtree. Node y becomes the right child of node x and
subtree b becomes the left child of node y.

© e-Learning Centre, UCSC 115


5.3 Binary Search trees

• Few types of BSTs that are self-balancing.

• AVL trees
• Red-black trees
• Splay trees
• Treaps

© e-Learning Centre, UCSC 116


5.4 Tree Balancing

• BSTs where introduced because in theory they give nice fast


search time.
• We have seen that depending on how the data arrives the tree
can degrade into a linked list
• So what is a good programmer to do.
• Of course, they are to balance the tree

© e-Learning Centre, UCSC 117


5.4.1 Introduction to tree balancing

Consider the following three examples

• A binary tree is height-balanced or simply balanced if the


difference in height of both sub trees of any node in the tree is
either zero or one.
• For example, for node K in Figure b, the difference between the
heights of its sub trees being equal to one is acceptable. But for
node B this difference is three, which means that the entire tree
is unbalanced.
© e-Learning Centre, UCSC 118
5.4.1 Introduction to tree balancing

• For the same node B in c, the difference is the worst possible,


namely, five. Also, a tree is considered perfectly balanced if it is
balanced and all leaves are to be found on one level or two
levels.

© e-Learning Centre, UCSC 119


5.4.1 Introduction to tree balancing

• There are a number of techniques to properly balance a binary


tree.
• Some of them consist of constantly restructuring the tree when
elements arrive and lead to an unbalanced tree.
• Some of them consist of reordering the data themselves and
then building a tree, if an ordering of the data guarantees that
the resulting tree is balanced.

© e-Learning Centre, UCSC 120


5.4.1 Introduction to tree balancing

• We have seen the searching benefits of a balance tree, but how


to we have a balance a tree
• Consider a tree with 10,000 nodes
• At its least efficient (linked list) at most 10,000 elements need to
be tested find the element
• When balance, just 14 tests need to be performed
• The height of the tree is lg(10,000)=12,289=14
• Assume all the data is in a stored array.
• The middle element becomes the root
• The middle element of one half becomes a child
• The idle element of the other half becomes the other child.
• Then recursive…..
© e-Learning Centre, UCSC 121
5.4.1 Introduction to tree balancing

• How to balance?
Template < T>
Void BST <T>:: Balance (T Data[], int First, int last){
If (first<=last) {
int middle=(first+last)/2;
insert(data[middle]);
balance(data, first,middle-1);
balance (data,middle+1, last);
}
}

• This algorithm is quite inefficient as it relies on using extra space to store an


array of values, and all values must be in this array(perhaps by in-order
traversal).
• Let look at some alternative.
© e-Learning Centre, UCSC 122
5.4.2 Global tree balancing (The DSW algorithm)

• The very elegant DSW algorithm was devised by Colin Day and
later improved by Quentin F. Stout and Bette L.Warren.
• The building block for tree transformations in this algorithm is
the rotation.
• There are two types of rotation, left and right, which are
symmetrical to one another.
• The right rotation of the node Ch about its parent Par is
performed according to the following algorithm:

© e-Learning Centre, UCSC


123
5.4.2 Global tree balancing (The DSW algorithm)

The steps involved in this compound operation are shown in the


image below.

© e-Learning Centre, UCSC 124


5.4.2 Global tree balancing (The DSW algorithm)

Example :

© e-Learning Centre, UCSC 125


5.4.2 Global tree balancing (The DSW algorithm)

• So the idea is to take a tree and perform some rotations to it to


make it balanced.
• First you create a backbone or a vine
• Then you transform the backbone into a nicely balanced tree

© e-Learning Centre, UCSC 126


5.4.2 Global tree balancing (The DSW algorithm)

Transforming a binary search tree into a backbone.

© e-Learning Centre, UCSC 127


5.4.2 Global tree balancing (The DSW algorithm)

Transforming a backbone into a perfectly balanced tree.

© e-Learning Centre, UCSC 128


5.4.2 Global tree balancing (The DSW algorithm)

Example :

© e-Learning Centre, UCSC 129


5.4.2 Global tree balancing (The DSW algorithm)

• The DSW algorithm is effective at balancing an entire tree.


(Actually O(n))
• Sometimes trees need only be balanced periodically,in which
case this cost can be amortised.
• Alternatively the tree may only become unstable after a series of
insertions and deletions,in which case a DSW balancing may be
appropriate.
• An alternative approach is to ensure the tree remains balanced
by incorporating balancing into any insertion/deletion
algorithms.
• In an AVL insertion and deletion considers the structure of
the tree
• All nodes have a balance factor - i.e. a difference
between the number of nodes in the right subtree and
the left subtree.This difference must remain at +1,0 or -
1
• An AVL tree may not appear completely balanced as
after the DSW algorithm
© e-Learning Centre, UCSC 130
5.4.3 Local tree balancing (AVL Tree)

• Named after its inventors Adel’son-Vel’skii and Landis, hence


AVL
• The heights of any subtree can only differ by at most one.
• Each nodes will indicate balance factors.
• Worst case for an AVL tree is 44% worst then a perfect tree.
• In practice, it is closer to a perfect tree.
• Each time the tree structure is changed, the balance factors are
checked and if an imbalance is recognized, then the tree is
restructured.
• For insertion there are four cases to be concerned with.
• Deletion is a little trickier.

© e-Learning Centre, UCSC 131


5.4.3 Local tree balancing (AVL Tree)

• Each time the tree structure is changed, the balance factors are
checked and if an imbalance is recognized, then the tree is
restructured.
• For insertion there are four cases to be concerned with.
• Deletion is a little trickier
• The balance factor of any node in the tree is -1 , o or +1. It
implies that the tree is an AVL tree.
• Example :

© e-Learning Centre, UCSC 132


5.4.3 Local tree balancing (AVL Tree)

Examples for AVL and Non-AVL tree

AVL Tree NOT an AVL Tree

© e-Learning Centre, UCSC 133


5.4.3 Local tree balancing (AVL Tree)

Examples for AVL and Non-AVL tree

© e-Learning Centre, UCSC 134


5.4.3 Local tree balancing (AVL Tree)

• Algorithm for Inserting new nodes into an AVL trees


• Insert the node in the same way as in an ordinary binary
search tree.
• Beginning with the new node, trace a path back towards the
root, checking the difference in height of the sub-trees at
each node along the way.
• If you find a node with an imbalance ( a height difference
other than 0,+1,-1), stop your trace at this point.
• Consider the node with the imbalance and two nodes on
the layers immediately below this point on the path back to
the new node.
• If these three nodes lie in a straight line, apply a single
rotation to correct the imbalance.
• If these three nodes lie in a dog-leg pattern, apply a double
rotation to correct the imbalance.
© e-Learning Centre, UCSC 135
5.4.3 Local tree balancing (AVL Tree)

• Rotations
• When the tree structure changes (e.g., with insertion or
deletion), we need to modify the tree to restore the AVL tree
property.
• This can be done using single rotations or double rotations.
Since an insertion/deletion involves adding/deleting a single
node, this can only increase/decrease the height of a sub
tree by 1.
• So, if the AVL tree property is violated at a node X, it means
that the heights of left(X) and right(X) differ by exactly 2.
This is because, if we balance the AVL tree every time, then
at any point, the difference in heights of left(X) and right(X)
differ by exactly 2.
• Rotations is the technique used for restoring the AVL tree
property. This means, we need to apply the rotations for the
node X.
© e-Learning Centre, UCSC 136
5.4.3 Local tree balancing (AVL Tree)

• Rotations

The rules for deciding which type of rotations to be used.

1. When you have found the first node is out of balance,


restrict your attention to that node and the two nodes in the
two layers immediately below it.
2. If these three nodes lie in a straight line, single rotation is
needed to restore the balance.
3. If these three nodes lie in a “dog leg” pattern you need
double rotation to restore the balance.

© e-Learning Centre, UCSC 137


5.4.3 Local tree balancing (AVL Tree)

• Types of Violations
• Let us assume the node that must be rebalanced is X. Since any
node has at most two children, and a height imbalance requires
that X’s two sub tree heights differ by two, we can observe that a
violation might occur in four cases:
1. An insertion into the left sub tree of the left child of X.
2. An insertion into the right sub tree of the left child of X.
3. An insertion into the left sub tree of the right child of X.
4. An insertion into the right sub tree of the right child of X

Cases 1 and 4 are symmetric and easily solved with single rotations.
Similarly, cases 2 and 3 are also symmetric and can be solved with double
rotations

© e-Learning Centre, UCSC 138


5.4.3 Local tree balancing (AVL Tree)

• Single Rotations

• Left Left Rotation (LL Rotation) [Case-1]: In the case


below, node X is not satisfying the AVL tree property. The
rotation does not have to be done at the root of a tree.
• In general, we start at the node inserted and travel up the
tree, updating the balance information at every node on the
path.

© e-Learning Centre, UCSC 139


5.4.3 Local tree balancing (AVL Tree)

• Single Rotations
• Left Left Rotation (LL Rotation) [Case-1]:

For example, in the figure above, after the insertion of 7 in the original AVL tree
on the left, node 9 becomes unbalanced. So, we do a single left-left rotation at
9. As a result we get the tree on the right.
© e-Learning Centre, UCSC 140
5.4.3 Local tree balancing (AVL Tree)

• Single Rotations
• Left Left Rotation (LL Rotation):
Example 2

© e-Learning Centre, UCSC 141


5.4.3 Local tree balancing (AVL Tree)

• Single Rotations
• Right Right Rotation (RR Rotation) [Case-4]: In this case, node X
is not satisfying the AVL tree property.

© e-Learning Centre, UCSC 142


5.4.3 Local tree balancing (AVL Tree)

• Single Rotations
• Right Right Rotation (RR Rotation) [Case-4]:

For example, in the figure, after the insertion of 29 in the original AVL tree on
the left, node 15 becomes unbalanced. So, we do a single right-right rotation
at 15. As a result we get the tree on the right.
© e-Learning Centre, UCSC 143
5.4.3 Local tree balancing (AVL Tree)

• Single Rotations
• Right Right Rotation (RR Rotation):
Example 2 :

© e-Learning Centre, UCSC 144


5.4.3 Local tree balancing (AVL Tree)

• Double Rotations
• Left Right Rotation (LR Rotation) [Case-2]: For case-2 and
case-3 single rotation does not fix the problem. We need to
perform two rotations.

© e-Learning Centre, UCSC 145


5.4.3 Local tree balancing (AVL Tree)

• Double Rotations
• Left Right Rotation (LR Rotation) [Case-2]:

As an example, let us consider the following tree: The insertion of


7 is creating the case-2 scenario and the right side tree is the one
after the double rotation.

© e-Learning Centre, UCSC 146


5.4.3 Local tree balancing (AVL Tree)

• Double Rotations
• Left Right Rotation (LR Rotation):
Example 2:

© e-Learning Centre, UCSC 147


5.4.3 Local tree balancing (AVL Tree)

• Double Rotations
• Right Left Rotation (RL Rotation) [Case-3]: Similar to
case-2, we need to perform two rotations to fix this
scenario.

© e-Learning Centre, UCSC 148


5.4.3 Local tree balancing (AVL Tree)

• Double Rotations
• Right Left Rotation (RL Rotation) [Case-3]:

As an example, let us consider the following tree: The


insertion of 6 is creating the case-3 scenario and the right
side tree is the one after the double rotation.

© e-Learning Centre, UCSC 149


5.4.3 Local tree balancing (AVL Tree)

• Double Rotations
• Right Left Rotation (RL Rotation):
Example 2:

© e-Learning Centre, UCSC 150


5.4.3 Local tree balancing (AVL Tree)

© e-Learning Centre, UCSC 151


5.4.3 Local tree balancing (AVL Tree)

© e-Learning Centre, UCSC 152


5.4.3 Local tree balancing (AVL Tree)

Example : Add a new node 105 to the below tree

© e-Learning Centre, UCSC 153


5.4.3 Local tree balancing (AVL Tree)

Example : Add a new node 105 to the below tree

Insert 105

Do RL rotation

© e-Learning Centre, UCSC 154


5.4.3 Local tree balancing (AVL Tree)

• Deletion is a bit trickier.


• With insertion after the rotation we were done.
• Not so with deletion.
• We need to continue checking balance factors as we travel up
the tree
• Go ahead and delete the node just like in a BST.
• There are 4 cases after the deletion:

© e-Learning Centre, UCSC 155


5.4.3 Local tree balancing (AVL Tree)

• Case 1: Deletion from a left subtree from a tree with a right high
root and a right high right subtree.
• Requires one left rotation about the root
• Case 2: Deletion from a left subtree from a tree with a right high
root and a balanced right subtree.
• Requires one left rotation about the root
• Case 3: Deletion from a left subtree from a tree with a right high
root and a left high right subtree with a left high left subtree.
• Requires a right rotation around the right subtree root and
then a left rotation about the root
• Case 4: Deletion from a left subtree from a tree with a right high
root and a left high right subtree with a right high left subtree
• Requires a right rotation around the right subtree root and
then a left rotation about the root
© e-Learning Centre, UCSC 156
5.4.3 Local tree balancing (AVL Tree)

Example 1 : Delete node 30

© e-Learning Centre, UCSC 157


5.4.3 Local tree balancing (AVL Tree)

Example 1 : Delete node 30

© e-Learning Centre, UCSC 158


5.4.3 Local tree balancing (AVL Tree)

Example 2 : Delete node 55

© e-Learning Centre, UCSC 159


5.4.3 Local tree balancing (AVL Tree)

Example 2 : Delete node 55

© e-Learning Centre, UCSC 160


5.4.3 Local tree balancing (AVL Tree)

Example 3 : Delete node 60

© e-Learning Centre, UCSC 161


5.4.3 Local tree balancing (AVL Tree)

Example 3 : Delete node 60

© e-Learning Centre, UCSC 162


5.4.3 Local tree balancing (AVL Tree)

Code Segment :

Node rotateRight(Node y) {
Node x = y.left;
Node z = x.right;
x.right = y;
y.left = z;
updateHeight(y);
updateHeight(x);
return x;
}

© e-Learning Centre, UCSC 163


5.4.3 Local tree balancing (AVL Tree)

Node rotateLeft(Node y) {
Node x = y.right;
Node z = x.left;
x.left = y;
y.right = z;
updateHeight(y);
updateHeight(x);
return x;
}

© e-Learning Centre, UCSC 164


5.4.3 Local tree balancing (AVL Tree)

Node rebalance(Node z) {
updateHeight(z);
int balance = getBalance(z);
if (balance > 1) {
if (height(z.right.right) >
height(z.right.left)) {
z = rotateLeft(z);
} else {
z.right = rotateRight(z.right);
z = rotateLeft(z);
}

© e-Learning Centre, UCSC 165


5.4.3 Local tree balancing (AVL Tree)

} else if (balance < -1) {


if (height(z.left.left) >
height(z.left.right))
z = rotateRight(z);
else {
z.left = rotateLeft(z.left);
z = rotateRight(z);
}
}
return z;
}

© e-Learning Centre, UCSC 166


5.4.3 Local tree balancing (AVL Tree)

Node insert(Node node, int key) {


if (node == null) {
return new Node(key);
} else if (node.key > key) {
node.left = insert(node.left, key);
} else if (node.key < key) {
node.right = insert(node.right, key);
} else {
throw new RuntimeException("duplicate Key!");
}
return rebalance(node);
}
© e-Learning Centre, UCSC 167
5.4.3 Local tree balancing (AVL Tree)

Node delete(Node node, int key) {


if (node == null) {
return node;
} else if (node.key > key) {
node.left = delete(node.left, key);
} else if (node.key < key) {
node.right = delete(node.right, key);
} else {
if (node.left == null || node.right == null) {
node = (node.left == null) ? node.right :
node.left;
}

© e-Learning Centre, UCSC 168


5.4.3 Local tree balancing (AVL Tree)

else {
Node mostLeftChild =
mostLeftChild(node.right);
node.key = mostLeftChild.key;
node.right = delete(node.right, node.key);
}
}
if (node != null) {
node = rebalance(node);
}
return node;
}

© e-Learning Centre, UCSC 169


5.5 Heaps

• A Heap is a special Tree-based data structure in which the tree is


a complete binary tree. Generally, Heaps can be of two types:

• Max-Heap: In a Max-Heap the key present at the root node


must be greatest among the keys present at all of it’s
children. The same property must be recursively true for all
sub-trees in that Binary Tree.

• Min-Heap: In a Min-Heap the key present at the root node


must be minimum among the keys present at all of it’s
children. The same property must be recursively true for all
sub-trees in that Binary Tree

© e-Learning Centre, UCSC 170


5.5 Heaps

• Example :

© e-Learning Centre, UCSC 171


5.5 Heaps

Binary Heap
• A Binary Heap is a Binary Tree with following properties.

• It’s a complete tree (All levels are completely filled except


possibly the last level and the last level has all keys as left as
possible). This property of Binary Heap makes them suitable
to be stored in an array.

• A Binary Heap is either Min Heap or Max Heap. In a Min


Binary Heap, the key at root must be minimum among all
keys present in Binary Heap. The same property must be
recursively true for all nodes in Binary Tree. Max Binary Heap
is similar to MinHeap.

© e-Learning Centre, UCSC 172


5.5 Heaps

● Examples of Min Heap:

© e-Learning Centre, UCSC 173


5.5 Heaps

● How is Binary Heap represented?

A Binary Heap is a Complete Binary Tree. A binary heap is typically


represented as an array.

© e-Learning Centre, UCSC 174


5.5 Heaps

● Applications of Heaps

○ Heap Data Structure is generally taught with Heapsort.


Heapsort algorithm has limited uses because Quicksort is
better in practice. Nevertheless, the Heap data structure
itself is enormously used. Following are some uses other
than Heapsort.

○ Priority Queues: Priority queues can be efficiently


implemented using Binary Heap because it supports insert(),
delete() and extractmax(), decreaseKey() operations in
O(logn) time. Binomoial Heap and Fibonacci Heap are
variations of Binary Heap.

© e-Learning Centre, UCSC 175


5.5 Heaps

● Heap is a special case of balanced binary tree data structure


where the root-node key is compared with its children and
arranged accordingly. If α has child node β then −
key(α) ≥ key(β)
● As the value of parent is greater than that of child, this property
generates Max Heap.
● Based on this criteria, a heap can be of two types
● Max-Heap − Where the value of the root node is greater than
or equal to either of its children

© e-Learning Centre, UCSC 176


5.5 Heaps

● Min-Heap − Where the value of the root node is less than or


equal to either of its children

© e-Learning Centre, UCSC 177


5.5 Heaps

● Max Heap Construction Algorithm


We are going to derive an algorithm for max heap by inserting one
element at a time. At any point of time, heap must maintain its
property. While insertion, we also assume that we are inserting a
node in an already heapified tree.
Step 1 − Create a new node at the end of heap.
Step 2 − Assign new value to the node.
Step 3 − Compare the value of this child node with its parent.
Step 4 − If value of parent is less than child, then swap them.
Step 5 − Repeat step 3 & 4 until Heap property holds.

© e-Learning Centre, UCSC 178


5.5 Heaps

● Example : 3,1,6,5,2,4
First Insert 3 in root of the empty heap:

Next Insert 1 at the bottom of the heap. No need to swap the child
node (1) with the parent node (3) , because 3 is greater than 1.

© e-Learning Centre, UCSC 179


5.5 Heaps

● Example : 3,1,6,5,2,4
Next insert 6 to the bottom of the heap, and since 6 is greater than 3,
swapping is needed

Swap the 6 and the 3

© e-Learning Centre, UCSC 180


5.5 Heaps

● Example : 3,1,6,5,2,4
Next insert 5 to the bottom of the heap, and since 5 is greater than 1,
swapping is needed

Swap the 5 and the 1. Since 5 is less than 6, so no further swapping


needed.

© e-Learning Centre, UCSC 181


5.5 Heaps

● Example : 3,1,6,5,2,4
Next insert 2 to the bottom of the heap, and since 2 is less than 5, no
need to swap the 5 with the 2.

Next insert 4 to the bottom of the heap, and since 4 is greater than 3,
we need to swap the 4 and the 3.

© e-Learning Centre, UCSC 182


5.5 Heaps

● Example : 3,1,6,5,2,4
Swap the 4 and the 3. Since 4 is less than 6 no further swapping
needed, and we are done.

The array will now look like the below:

© e-Learning Centre, UCSC 183


5.5 Heaps

● Max Heap Deletion Algorithm


Let us derive an algorithm to delete from max heap. Deletion in Max
(or Min) Heap always happens at the root to remove the Maximum
(or minimum) value.

Step 1 − Remove root node.


Step 2 − Move the last element of last level to root.
Step 3 − Compare the value of this child node with its parent.
Step 4 − If value of parent is less than child, then swap them.
Step 5 − Repeat step 3 & 4 until Heap property holds.

© e-Learning Centre, UCSC 184


5.5 Heaps

• Example :

© e-Learning Centre, UCSC 185


5.5 Heaps

• Example :
Delete node 10

© e-Learning Centre, UCSC 186


5.5 Heaps

• Example :

Replace the deleted node with the farthest right node.

© e-Learning Centre, UCSC 187


5.5 Heaps

• Example :

Heapify (Fix the heap):

Now the heap property holds true and we are done !

© e-Learning Centre, UCSC 188


5.5 Heaps

Code Segment :
public class deletionHeap {
static void heapify(int arr[], int n, int i)
{
int largest = i; // Initialize largest as root
int l = 2 * i + 1; // left = 2*i + 1
int r = 2 * i + 2; // right = 2*i + 2
if (l < n && arr[l] > arr[largest])
largest = l;
if (r < n && arr[r] > arr[largest])
largest = r;
if (largest != i) {
int swap = arr[i];
arr[i] = arr[largest];
arr[largest] = swap;
heapify(arr, n, largest);
}
}
© e-Learning Centre, UCSC 189
5.5 Heaps

Code Segment :
static int deleteRoot(int arr[], int n)
{
int lastElement = arr[n - 1];
arr[0] = lastElement;
n = n - 1;
heapify(arr, n, 0);
return n;
}
static void printArray(int arr[], int n)
{
for (int i = 0; i < n; ++i)
System.out.print(arr[i] + " ");
System.out.println();
}

© e-Learning Centre, UCSC 190


5.5 Heaps
Code Segment :
public static void main(String args[])
{

int arr[] = { 10, 5, 3, 2, 4 };

int n = arr.length;

n = deleteRoot(arr, n);

printArray(arr, n);
}
}

© e-Learning Centre, UCSC 191


Summary

A tree can be defined non recursively as a set of


Tree nodes and a set of directed edges that connect
them

An important use of binary trees is in other data


Binary Tree structures, notably the binary search tree and the
priority queue.

The AVL tree was the first balanced binary search


AV AVL Tree tree. It has historical significance and also illustrates
most of the ideas that are used in other schemes

© e-Learning Centre, UCSC 192


6 : Graphs

IT 3206 – Data Structures and Algorithms

Level II - Semester 3

© e-Learning Centre, UCSC


Overview

• This section introduces the graph data structure and its


applications while comparing it with the tree structure.

• The section will also cover various types of graphs and


graph representations.

• This section will further demonstrate two different algorithms


for graph traversal, as well as multiple algorithms for finding
the shortest paths, and their comparisons.

© e-Learning Centre, UCSC 2


Intended Learning Outcomes

• At the end of this lesson, you will be able to;

• Explain different types of graphs and their usage

• Implement graphs and graph operations

• Illustrate graph traversal and connectivity

• Compare and implement different shortest path algorithms

© e-Learning Centre, UCSC 3


List of Subtopics

6.1 Introduction to graphs


6.1.1 Directed graphs, undirected graphs, weighted graphs
6.1.2 Applications of graphs
6.2 Different types of Graph representations
6.2.1 Array based implementation
6.2.2 Linked-list based implementation
6.3 Graph traversal
6.3.1 Depth first traversal (DFT)
6.3.2 Breadth first traversal (BFT)
6.4 Shortest path algorithms
6.4.1 Shortest path in unweighted graph
6.4.2 Shortest path in weighted graph (Dijkstra’s algorithm)
6.4.3 Shortest path weighted graph with negative edges
(Bellman-Ford Algorithm)
© e-Learning Centre, UCSC 4
6.1 Introduction to graphs

• A Graph is a non-linear data structure


consisting of nodes and edges.

• The nodes are sometimes also referred to


as vertices and the edges are lines or arcs
that connect any two nodes in the graph

• Graphs are a powerful and versatile data


structure that easily allow you to represent
real life relationships between different
types of data (nodes).

• The best example of this would be google


maps.

© e-Learning Centre, UCSC 5


6.1 Introduction to graphs

• A graph G = (V,E) is a set of vertices (V) and a binary


relation between vertices (set of edges – E).

Components of a Graph

• Vertices(Nodes): Vertices are the fundamental units of the


graph. Sometimes, vertices are also known as nodes. Every
node/vertex can be labelled or unlabeled.

• Edges(Arcs): Edges are the drawn or used to connect two


nodes of the graph. It can be ordered pair of nodes in a
directed graph. Sometimes, edges are also known as arcs.
Every edge can be labelled/unlabeled.

© e-Learning Centre, UCSC 6


6.1 Introduction to graphs contd.
Example

© e-Learning Centre, UCSC 7


6.1 Introduction to graphs contd.

Some features of Trees vs Graphs

• Trees are connected and contains no cycles. Has V-1


number of edges.
• In the tree, there is exactly one root node, and every child
can have only one parent. As against, in a graph, there is no
concept of the root node.
• In a tree there exist only one path between any two vertices
whereas a graph can have unidirectional and bidirectional
paths between the nodes.
• A tree has a hierarchical structure whereas graph has a
network model.
• A graph need not be a tree, but a tree must be a graph.
© e-Learning Centre, UCSC 8
6.1 Introduction to graphs contd.

Graph Terminology

• Adjacent vertices: If (i,j) is an edge of the graph, then the


nodes i and j are adjacent.
• An edge (i,j) is Incident to vertices i and j.

Vertices 2 and 5 are not adjacent

© e-Learning Centre, UCSC 9


6.1 Introduction to graphs contd.

Graph Terminology contd.

• Path: A sequence of edges in the graph


• There can be more than one path between two vertices
• Vertex A is reachable from B if there is a path from A to B

© e-Learning Centre, UCSC 10


6.1 Introduction to graphs contd.

Graph Terminology contd.

• Simple Path: A path where all the vertices are distinct

1,4,5,3 is a simple path.

But 1,4,5,4 is not a simple


path.

© e-Learning Centre, UCSC 11


6.1 Introduction to graphs contd.

Graph Terminology contd.

• Length : Sum of the lengths of the edges on the path.

Length of the path 1,4,5,3 is


3

© e-Learning Centre, UCSC 12


6.1 Introduction to graphs contd.

Graph Terminology contd.

• Circuit: A path whose first and last vertices are the same
and no edge is repeated then the path is called a circuit.

The path 3,2,1,4,5,3 is a


circuit.

© e-Learning Centre, UCSC 13


6.1 Introduction to graphs contd.

Graph Terminology contd.

• Cycle: A cycle where all the vertices are distinct except for
the first (and the last) vertex.

1,4,5,3,1 is a cycle

1,4,5,4,1 is not a cycle

© e-Learning Centre, UCSC


14
6.1 Introduction to graphs contd.

Graph Terminology contd.

• Hamiltonian Cycle: A Cycle that contains all the vertices of


the graph

1,4,5,3,2,1 is a Hamiltonian
Cycle

© e-Learning Centre, UCSC 15


6.1.1 Directed graphs, undirected graphs, weighted
graphs

• Directed Graph
• A graph in which edge has direction. That is the nodes are
ordered pairs in the definition of every edge.

• Undirected Graph
• A graph in which edges do not have any direction. That is the
nodes are unordered pairs in the definition of every edge.

© e-Learning Centre, UCSC 16


6.1.1 Directed graphs, undirected graphs, weighted
graphs contd.

• Weighted Graph
• A graph in which a weight, or number, associated with each
edge.

© e-Learning Centre, UCSC 17


6.1.1 Directed graphs, undirected graphs, weighted
graphs contd.

• Weighted Graph Example


• In this example, vertices represent cities, edges represent
roads between cities and weight represents the distance of
roads.
42KM

103KM

222KM

146KM 251KM

44KM

© e-Learning Centre, UCSC


18
6.1.1 Directed graphs, undirected graphs, weighted
graphs contd.

Graph Terminology

• Degree of a Vertex : In an undirected graph, the no. of


edges incident to the vertex
• In-degree: The no. of edges entering the vertex in a
directed graph
• Out-Degree: The no. of edges leaving the vertex in a
directed graph

In-degree of 1 is 3

Out-degree of 1 is 1

© e-Learning Centre, UCSC 19


6.1.2 Applications of graphs

• Transportation networks: Highway network, Flight network

• Computer networks: Local area network, Internet, Web

© e-Learning Centre, UCSC 20


6.1.2 Applications of graphs contd.

• Social network graphs: Graphs that represent who knows whom,


who communicates with whom, who influences whom or other
relationships in social structures

© e-Learning Centre, UCSC 21


6.1.2 Applications of graphs contd.

• Dependence graphs: Graphs can be used to represent


dependencies or precedencies among items. Such graphs are
often used in large projects in laying out what components rely on
other components and used to minimize the total time or cost to
completion while abiding by the dependences

• Semantic networks. Vertices represent words or concepts, and


edges represent the relationships among the words or concepts.
These have been used in various models of how humans organize
their knowledge, and how machines might simulate such an
organization.
© e-Learning Centre, UCSC 22
6.2 Different types of Graph representations

• Generally, there are two types of graph representations.


1.Array Based Implementation
2.Linked List Based Implementation

© e-Learning Centre, UCSC 23


6.2.1 Array based implementation

• Adjacency Matrix
• In this method, the graph is stored in the form of the 2D matrix
where rows and column denote vertices.
• Each entry in the matrix represents the weight of the edge
between those vertices.
• The values of the Adjacency matrix are represented as
follows: 1 or sometimes denoted as true. That indicates an
edge from one node to another node; otherwise, 0 or false.

© e-Learning Centre, UCSC 24


6.2.1 Array based implementation contd.

• Path Matrix
• Path matrix has the same concept of adjacency matrix. But
instead of having an edge from one node to another, this
indicates whether there is a path from one node another.
• The values of the path matrix are represented as follows: 1 or
sometimes denoted as true. That indicates a path from one
node to another node with the given length; otherwise, 0 or
false.
• For an example, path matrix of length 2 denotes whether there
is a path from one node to another with length 2.
• Hence, we can get the path matrix of length n by taking path
matrix of length n-1 and multiplying it with path matrix of
length 1.

© e-Learning Centre, UCSC 25


6.2.1 Array based implementation contd.

• Path Matrix Example

V1 V2 V3 V4 V1 V2 V3 V4

V1 0 1 1 0 V1 1 1 0 1

V2 1 0 0 1 V2 0 1 1 0

V3 0 1 0 1 V3 1 0 1 1

V4 0 0 1 0 V4 0 1 0 1

Path Matrix of Length 1 Path Matrix of Length 2


© e-Learning Centre, UCSC 26
6.2.2 Linked-list based implementation

• Adjacency List
• This graph is represented as a collection of linked lists.
• There is an array of pointer which points to the edges
connected to that vertex.

© e-Learning Centre, UCSC 27


6.3.1 Depth first traversal (DFT)

• Depth first traversal is a strategy used for exploring a graph.

• Explore “deeper” in the graph whenever possible


• Start from an arbitrary node.
• Edges are explored out of the most recently discovered vertex
v that still has unexplored edges.
• When all of v’s edges have been explored, backtrack to the
vertex from which v was discovered.
• Stop when no unvisited nodes are found, and no backtracking
can be done.
• Implemented using a Stack.

© e-Learning Centre, UCSC 28


6.3.1 Depth first traversal (DFT) contd.

• Used data structures.

• color[v] : stores the color of the vertex (white: unvisited, grey:


visited, black: processed)
• parent[v] : stores the parent of v (if no parents null)
• d[u] : stores discovered time
• f[u] : stores finished time
• time : stores current time

© e-Learning Centre, UCSC 29


6.3.1 Depth first search (DFS) contd.

Algorithm

© e-Learning Centre, UCSC 30


6.3.1 Depth first search (DFS) Contd.

© e-Learning Centre, UCSC 31


6.3.1 Depth first traversal (DFT) Contd.

Pseudocode Algorithm for DFT

procedure DFT(G:graph; var color:carray; d, f:iarray;


parent:parray);
for each vertex u do
color[u]:=white;
parent[u]:=null;
end for
time:=0;
for each vertex u do
if color[u]=white then
DFT-Visit(u);
end if
end for
end DFT

© e-Learning Centre, UCSC 32


6.3.1 Depth first traversal (DFT) Contd.

DFT-Visit(u)
color[u]=:gray; time:=time+1; d[u]:=time
for each v in adj[u] do
if color[v]=white then
parent[v]:=u; DFT-Visit(v);
end if
end for
color[u]:=black; time:=time+1; f[u]:=time;
end DFT-Visit

© e-Learning Centre, UCSC 33


6.3.1 Depth first traversal (DFT) Contd.

Depth First Traversal Step by Step Example

© e-Learning Centre, UCSC 34


6.3.1 Depth first traversal (DFT) Contd.

Depth First Traversal Step by Step Example Contd.

© e-Learning Centre, UCSC 35


6.3.1 Depth first traversal (DFT) Contd.

Depth First Traversal Step by Step Example Contd.

© e-Learning Centre, UCSC 36


6.3.1 Depth first traversal (DFT) Contd.

Depth First Traversal Step by Step Example Contd.

© e-Learning Centre, UCSC 37


6.3.2 Breadth first traversal (BFT)

• Given a graph G=(V,E) and a source vertex s, BFT explores


the edges of G to “discover” (visit) each node of G
reachable from s.
• Idea - expand a frontier one step at a time.
• Frontier is a FIFO queue (O(1) time to update)
• Computes the shortest distance(dist) from s to any
reachable node.
• Computes a breadth first tree (of parents) with root s that
contains all the reachable vertices from s.
• To get O(|V|+|E|) we use an adjacency list representation. If
we used an adjacency matrix it would be O(|V|2)

© e-Learning Centre, UCSC 38


6.3.2 Breadth first traversal (BFT) contd.

• Example for Breadth First Traversal

© e-Learning Centre, UCSC 39


6.3.2 Breadth first traversal (BFT) contd

Coloring the nodes

• We use colors (white, gray and black) to denote the state of


the node during the search.

• A node is white if it has not been reached (discovered).

• Discovered nodes are gray or black. Gray nodes are at the


frontier of the search.

• Black nodes are fully explored nodes.

© e-Learning Centre, UCSC 40


6.3.1 Breath first traversal (BFT) Contd.

Pseudocode Algorithm for BFT


procedure BFT(G:graph; s:node; var color:carray;
dist:iarray; parent:parray);
for each vertex u do
color[u]:=white; dist[u]:=∞;
parent[u]:=null;
end for
color[s]:=gray; dist[s]:=0;
init(Q); enqueue(Q, s);
while not (empty(Q)) do
u:=head(Q);
for each v in adj[u] do
if color[v]=white then O(E)
color[v]:=gray; dist[v]:=dist[u]+1;
parent[v]:=u; enqueue(Q, v);
end if
end for
dequeue(Q); color[u]:=black;
end while
end BFT © e-Learning Centre, UCSC 41
6.3.2 Breadth first search (BFS) contd.

Breadth First Search Step by Step Example

© e-Learning Centre, UCSC 42


6.3.2 Breadth first search (BFS) contd.

Breadth First Search Step by Step Example Contd.

© e-Learning Centre, UCSC 43


6.4.2 Shortest path in weighted graph
(Dijkstra’s algorithm)

• The algorithm characterizes each node by its state


• The state of a node consists of two features:
• distance value and status label
• Distance value of a node is a scalar representing an estimate of
the its distance from node s.
• Status label is an attribute specifying whether the distance value
of a node is equal to the shortest distance to node s or not.
• The status label of a node is Permanent if its distance value
is equal to the shortest distance from node s
• Otherwise, the status label of a node is Temporary
• The algorithm maintains and step-by-step updates the states of
the nodes
• At each step one node is designated as current

© e-Learning Centre, UCSC 44


6.4.2 Shortest path in weighted graph
(Dijkstra’s algorithm) contd.

Notation

In what follows:
• dl denotes the distance value of a node l.

• p or t denotes the status label of a node, where p stand for


permanent, and t stands for temporary

• cij is the cost of traversing link (i, j) as given by the problem

The state of a node l is the ordered pair of its distance value dl and
its status label.

© e-Learning Centre, UCSC 45


6.4.2 Shortest path in weighted graph
(Dijkstra’s algorithm) contd.

Algorithm

• Step 1 : Initialization

• Step 2 : Distance Value Update and Current Node Designation


Update

• Step 3 : Termination Criterion

© e-Learning Centre, UCSC 46


6.4.2 Shortest path in weighted graph
(Dijkstra’s algorithm) contd.

Step 1 : Initialization

• Assign the zero-distance value to node s, and label it as


Permanent. [The state of node s is (0, p)]

• Assign to every node a distance value of ∞ and label them as


Temporary. [The state of every other node is (∞, t)]

• Designate the node s as the current node

© e-Learning Centre, UCSC 47


6.4.2 Shortest path in weighted graph
(Dijkstra’s algorithm) contd.

Step 2 : Distance Value Update and Current Node Designation


Update

Let i be the index of the current node.


• Find the set J of nodes with temporary labels that can be
reached from the current node i by a link (i, j). Update the
distance values of these nodes.

• Determine a node j that has the smallest distance value dj


among all nodes j ∈ J.

• Change the label of node j to permanent and designate this


node as the current node.

© e-Learning Centre, UCSC 48


6.4.2 Shortest path in weighted graph
(Dijkstra’s algorithm) contd.

Step 3 : Termination Criterion

• If all nodes that can be reached from node s have been


permanently labeled, then stop.

• If algorithm cannot reach any temporary labeled node from the


current node, then all the temporary labels become permanent,
then stop

• Otherwise, go to step 2.

© e-Learning Centre, UCSC 49


6.4.2 Shortest path in weighted graph
(Dijkstra’s algorithm) contd.

Example

© e-Learning Centre, UCSC 50


6.4.2 Shortest path in weighted graph
(Dijkstra’s algorithm) contd.

Example contd.
• The set sptSet is initially empty and distances assigned to
vertices are {0, INF, INF, INF, INF, INF, INF, INF} where INF
indicates infinite.

• Now pick the vertex with minimum distance value. The vertex 0
is picked, include it in sptSet. So sptSet becomes {0}. After
including 0 to sptSet, update distance values of its adjacent
vertices.

• Adjacent vertices of 0 are 1 and 7. The distance values of 1 and


7 are updated as 4 and 8.

• Following subgraph shows vertices and their distance values,


only the vertices with finite distance values are shown. The
vertices included in SPT are shown in green colour.

© e-Learning Centre, UCSC 51


6.4.2 Shortest path in weighted graph
(Dijkstra’s algorithm) contd.

Example contd.

0 1 2 3 4 5 6 7 8

0 ∞ ∞ ∞ ∞ ∞ ∞ ∞ ∞
4 8

• Pick the vertex with minimum distance value and not already
included in SPT (not in sptSET). The vertex 1 is picked and
added to sptSet. So sptSet now becomes {0, 1}. Update the
distance values of adjacent vertices of 1. The distance value of
vertex 2 becomes 12.

© e-Learning Centre, UCSC 52


6.4.2 Shortest path in weighted graph
(Dijkstra’s algorithm) contd.

Example contd.

0 1 2 3 4 5 6 7 8

0 ∞ ∞ ∞ ∞ ∞ ∞ ∞ ∞
4 8

12

• Pick the vertex with minimum distance value and not already
included in SPT (not in sptSET). Vertex 7 is picked. So sptSet
now becomes {0, 1, 7}. Update the distance values of adjacent
vertices of 7. The distance value of vertex 6 and 8 becomes
finite (15 and 9 respectively).

© e-Learning Centre, UCSC 53


6.4.2 Shortest path in weighted graph
(Dijkstra’s algorithm) contd.

Example contd.

0 1 2 3 4 5 6 7 8

0 ∞ ∞ ∞ ∞ ∞ ∞ ∞ ∞
4 ∞ ∞ ∞ ∞ ∞ 8 ∞
12 ∞ ∞ ∞ ∞ 8 ∞
12 ∞ ∞ ∞ 9 ∞ 15

• Pick the vertex with minimum distance value and not already
included in SPT (not in sptSET). Vertex 6 is picked. So sptSet
now becomes {0, 1, 7, 6}. Update the distance values of
adjacent vertices of 6. The distance value of vertex 5 and 8 are
updated.

© e-Learning Centre, UCSC 54


6.4.2 Shortest path in weighted graph
(Dijkstra’s algorithm) contd.

Example contd.
0 1 2 3 4 5 6 7 8

0 ∞ ∞ ∞ ∞ ∞ ∞ ∞ ∞
4 ∞ ∞ ∞ ∞ ∞ 8 ∞
12 ∞ ∞ ∞ ∞ 8 ∞
12 ∞ ∞ ∞ 9 ∞ 15

12 ∞ ∞ 11 ∞ 15

• We repeat the above steps until sptSet does include all vertices
of given graph. Finally, we get the following Shortest Path Tree
(SPT).

© e-Learning Centre, UCSC 55


6.4.2 Shortest path in weighted graph
(Dijkstra’s algorithm) contd.

Example contd.

0 1 2 3 4 5 6 7 8

0 ∞ ∞ ∞ ∞ ∞ ∞ ∞ ∞
4 ∞ ∞ ∞ ∞ ∞ 8 ∞
12 ∞ ∞ ∞ ∞ 8 ∞
12 ∞ ∞ ∞ 9 15

12 ∞ ∞ 11 15

12 25 21 15

19 21 14

19 21

21

© e-Learning Centre, UCSC 56


6.4.3 Shortest path weighted graph with negative
edges (Bellman-Ford Algorithm)

Algorithm

• Input: Graph and a source vertex src

• Output: Shortest distance to all vertices from src. If there is a


negative weight cycle, then shortest distances are not
calculated, negative weight cycle is reported.

Negative weight cycle is a cycle with weights that sum to a


negative number. If there is a negative weight cycle, algorithm
can go on relaxing its nodes indefinitely.

• Step 01: This step initializes distances from the source to all
vertices as infinite and distance to the source itself as 0. Create
an array dist[] of size |V| with all values as infinite except
dist[src] where src is source vertex.

© e-Learning Centre, UCSC 57


6.4.3 Shortest path weighted graph with negative
edges (Bellman-Ford Algorithm) contd.

Algorithm contd.

• Step 02: This step calculates shortest distances. Do following


|V|-1 times where |V| is the number of vertices in given graph.

• Do following for each edge u-v


• If dist[v] > dist[u] + weight of edge uv, then update dist[v]
• dist[v] = dist[u] + weight of edge uv

• Step 03: This step reports if there is a negative weight cycle in


graph. Do following for each edge u-v
• If dist[v] > dist[u] + weight of edge uv, then “Graph contains
negative weight cycle”

© e-Learning Centre, UCSC 58


6.4.3 Shortest path weighted graph with negative
edges (Bellman-Ford Algorithm) contd.

Example

• Let the given source vertex be 0. Initialize all distances as


infinite, except the distance to the source itself. Total number of
vertices in the graph is 5, so all edges must be processed 4
times.

© e-Learning Centre, UCSC 59


6.4.3 Shortest path weighted graph with negative
edges (Bellman-Ford Algorithm) contd.

Example contd.

• Let all edges are processed in the following order: (B, E), (D, B),
(B, D), (A, B), (A, C), (D, C), (B, C), (E, D).

• We get the following distances when all edges are processed


the first time. The first row shows initial distances. The second
row shows distances when edges (B, E), (D, B), (B, D) and (A,
B) are processed.

• The third row shows distances when (A, C) is processed. The


fourth row shows when (D, C), (B, C) and (E, D) are processed.

© e-Learning Centre, UCSC 60


6.4.3 Shortest path weighted graph with negative
edges (Bellman-Ford Algorithm) contd.

Example contd.

© e-Learning Centre, UCSC 61


6.4.3 Shortest path weighted graph with negative
edges (Bellman-Ford Algorithm) contd.

Example contd.

• The first iteration guarantees to give all shortest paths which are
at most 1 edge long. We get the following distances when all
edges are processed second time (The last row shows final
values).

© e-Learning Centre, UCSC 62


6.4.3 Shortest path weighted graph with negative
edges (Bellman-Ford Algorithm) contd.

Example contd.

• The second iteration guarantees to give all shortest paths which


are at most 2 edges long. The algorithm processes all edges 2
more times. The distances are minimized after the second
iteration, so third and fourth iterations don’t update the
distances.

© e-Learning Centre, UCSC 63


6.4.3 Shortest path weighted graph with negative
edges (Bellman-Ford Algorithm) contd.

void BellmanFord(Graph graph, int src) {


int V = graph.V, E = graph.E;
int dist[] = new int[V];

// Step 01
// Step 02
// Step 03

© e-Learning Centre, UCSC 64


6.4.3 Shortest path weighted graph with negative
edges (Bellman-Ford Algorithm) contd.

// Step 1: Initialize distances from src to all other


// vertices as INFINITE
for (int i = 0; i < V; ++i)
dist[i] = Integer.MAX_VALUE;
dist[src] = 0;

© e-Learning Centre, UCSC 65


6.4.3 Shortest path weighted graph with negative
edges (Bellman-Ford Algorithm) contd.

// Step 2: Relax all edges |V| - 1 times. A simple


// shortest path from src to any other vertex can
// have at-most |V| - 1 edges
for (int i = 1; i < V; ++i) {
for (int j = 0; j < E; ++j) {
int u = graph.edge[j].src;
int v = graph.edge[j].dest;
int weight = graph.edge[j].weight;
if (dist[u] != Integer.MAX_VALUE && dist[u] + weight < dist[v])
dist[v] = dist[u] + weight;
}
}
© e-Learning Centre, UCSC 66
6.4.3 Shortest path weighted graph with negative
edges (Bellman-Ford Algorithm) contd.

// Step 3: check for negative-weight cycles. The above


// step guarantees shortest distances if graph doesn't
// contain negative weight cycle. If we get a shorter
// path, then there is a cycle.
for (int j = 0; j < E; ++j) {
int u = graph.edge[j].src;
int v = graph.edge[j].dest;
int weight = graph.edge[j].weight;
if (dist[u] != Integer.MAX_VALUE && dist[u] + weight < dist[v]) {
System.out.println("Graph contains negative weight cycle");
return;
}
} © e-Learning Centre, UCSC 67
Summary

Introduction to Directed Graphs, Undirected Graphs and Weighted Graphs


Graphs

Different Types of
Graph Adjacency Matrix, Path Matrix and Adjacency list.
Representations

Graph Traversal Depth First Traversal and Breath First Traversal

Shortest Path
Algorithms in Dijkstra's Algorithm and Bellman-Ford Algorithm
Graphs

© e-Learning Centre, UCSC 68


7 : Analysis of Algorithms

IT3206– Data Structures and Algorithms

Level II - Semester 3

© e-Learning Centre, UCSC


Overview

• This section will introduce approaches to the analysis of


algorithms while emphasizing the requirement of an
algorithm analysis mechanism.

• The running time of an algorithm and the rate of growth of


algorithms are discussed further in this section.

• Moreover, this section will introduce the concept of


asymptotic analysis and explain the big-O notation in detail.

© e-Learning Centre, UCSC 2


Intended Learning Outcomes

• At the end of this lesson, you will be able to;

• Explain running time analysis and rate of growth

• Illustrate types of algorithm analysis and asymptotic notations

© e-Learning Centre, UCSC 3


List of subtopics

7.1 Introduction to analysis of algorithms

7.2 Types of analysis

7.3 Big-O notation

© e-Learning Centre, UCSC 4


7.1 Introduction to analysis of algorithms

What is an Algorithm?

An algorithm is the step-by-step unambiguous instructions to solve a


given problem.

• In the traditional study of algorithms, there are two main criteria


for judging the merits of algorithms:

• Correctness: does the algorithm give solution to the problem


in a finite number of steps?

• Efficiency: how much resources (in terms of memory and


computation time) does it take to execute

© e-Learning Centre, UCSC 5


7.1 Introduction to analysis of algorithms contd.

Analyzing an algorithm

Analyzing an algorithm has come to mean predicting the resources


that the algorithm requires.

• Occasionally, resources such as memory, communication


bandwidth, or computer hardware are of primary concern, but
most often it is computational time that we want to measure.

• Generally, by analyzing several candidate algorithms for a


problem, we can identify a most efficient one.

• Such analysis may indicate more than one viable candidate, but
we can often discard several inferior algorithms in the process.

© e-Learning Centre, UCSC 6


7.1 Introduction to analysis of algorithms contd.

Analyzing an algorithm cont.

• To go from city “A” to city “B”, there can be many ways of


accomplishing this: by flight, by bus, by train and also by bicycle.
Depending on the availability and convenience, we choose the
one that suits us.

• Similarly, in computer science, multiple algorithms are available


for solving the same problem (for example, a sorting problem
has many algorithms, like insertion sort, selection sort, quick
sort and many more).

• Algorithm analysis helps us to determine which algorithm is


most efficient in terms of time and space consumed.

• The goal of the analysis of algorithms is to compare algorithms


(or solutions) mainly in terms of running time but also in terms of
other factors (e.g., memory, developer effort, etc.)
© e-Learning Centre, UCSC 7
7.1 Introduction to analysis of algorithms contd.

Running Time Analysis


• It is the process of determining how processing time increases
as the size of the problem (input size) increases.

• Input size is the number of elements in the input, and depending


on the problem type, the input may be of different types.

• The following are the common types of inputs.


• Size of an array
• Polynomial degree
• Number of elements in a matrix
• Number of bits in the binary representation of the input
• Vertices and edges in a graph.

© e-Learning Centre, UCSC 8


7.1 Introduction to analysis of algorithms contd.

Comparing Algorithms?

1. Compare execution times?

Not recommended: execution times are specific to a particular


computer.

2. Count the number of statements executed?

Not recommended: Number of statements vary with the


programming language as well as the style of the individual
programmer.

© e-Learning Centre, UCSC 9


7.1 Introduction to analysis of algorithms contd.

Comparing Algorithms – Ideal Solution

• Uses a high-level description of the algorithm instead of an


implementation

• Express running time as a function of the input size n

• Compare different functions corresponding to running times.

• Such an analysis is independent of hardware, software


environment.

© e-Learning Centre, UCSC 10


7.1 Introduction to analysis of algorithms contd.

Comparing Algorithms – Example

• Associate a “cost” with each statement.


• Find the “total cost” by finding the total number of times each
statement is executed.

Cost

for (i=0; i>n ; i++) C2

arr[i] = 0; C1

(n+1)*C2 + n*C1 = (C1+C2)n + C2

© e-Learning Centre, UCSC 11


7.1 Introduction to analysis of algorithms contd.

Comparing Algorithms – Example

Cost

sum = 0; C1
for (i=0; i>n ; i++) C2
for (j=0; j<n; j++) C2
sum += arr[i][j] C3

C1 + C2(n+1) + C2(n+1)n + C3*n2

© e-Learning Centre, UCSC 12


7.1 Introduction to analysis of algorithms

Rate of Growth

• The rate at which the running time increases as a function of


input is called rate of growth.

• Let us assume that you go to a shop to buy a car and a bicycle.


If your friend sees you there and asks what you are buying, then
in general you say buying a car.

This is because the cost of the car is high compared to the cost
of the bicycle (approximating the cost of the bicycle to the cost
of the car).

© e-Learning Centre, UCSC 13


7.1 Introduction to analysis of algorithms

Rate of Growth Contd.

• or the above-mentioned example, we can represent the cost of


the car and the cost of the bicycle in terms of function, and for a
given function ignore the low order terms that are relatively
insignificant (for large value of input size, n).

• As an example, in the case below, n4, 2n2, 100n and 500 are the
individual costs of some function and approximate to n4 since n4
is the highest rate of growth.

© e-Learning Centre, UCSC 14


7.1 Introduction to analysis of algorithms

Rate of Growth Example

Assume that running time of an algorithm can be represented in f(n).

𝑓 𝑛 = 𝑛2 + 100𝑛 + 102

𝑛=1 → 𝟏𝟐 +100 + 102


n2 term dominates as
𝑛 = 102 → 𝟏𝟎𝟒 + 104 + 102 the number of inputs
𝑛 = 106 → 𝟏𝟎𝟏𝟐 + 108 + 102
increase

𝑛 = 1012 → 𝟏𝟎𝟐𝟒 + 1014 + 102

What is the term that dominates as the number of inputs increase?

© e-Learning Centre, UCSC 15


7.1 Introduction to analysis of algorithms

Commonly Used Rates of Growth

© e-Learning Centre, UCSC 16


7.2 Types of analysis

• For a given algorithm, we can represent the best, worst and


average cases in the form of expressions. As an example, let f(n)
be the function which represents the given algorithm.

f(n)=n2+500 for worst case


f(n)=n+100n+500 for best case

Similarly for the average case. The expression defines the inputs
with which the algorithm takes the average running time (or
memory).

© e-Learning Centre, UCSC 17


7.2 Types of analysis contd.

• Worst case
• Provides an upper bound on running time
• An absolute guarantee that the algorithm would not run
longer, no matter what the inputs are.

• Best case
• Provides a lower bound on running time
• Input is the one for which algorithm runs the fastest

𝐿𝑜𝑤𝑒𝑟 𝐵𝑜𝑢𝑛𝑑 ≤ 𝑅𝑢𝑛𝑛𝑖𝑛𝑔 𝑇𝑖𝑚𝑒 ≤ 𝑈𝑝𝑝𝑒𝑟 𝐵𝑜𝑢𝑛𝑑

• Average case
• Provides a prediction about the running time of the algorithm.
• Assumes that the input is random

© e-Learning Centre, UCSC 18


7.2 Types of analysis contd.

Asymptotic Analysis

• Complexity refers to the rate at which the storage or time


grows as a function of the problem size.

• Asymptotic Analysis is based on the idea that as the


problem size grows, the complexity can be described as a
simple proportionality to some known function.

Notations used.

• Big-O (O)
• Omega (Ω)
• Theta (ϴ)

© e-Learning Centre, UCSC 19


7.3 Big-O notation (O)

• Given functions f(n) and g(n),


we say that f(n) = O(g(n)) if
There exists positive constants c and n0 such that
f(n) ≤ cg(n) for all n ≥ n0

© e-Learning Centre, UCSC 20


7.3 Big-O notation contd.

Big-O and Growth Rate

• The big-O notation gives an upper bound on the growth rate of a


function.

• The statement “ f(n) = O(g(n))” means that the growth rate of f(n)
is no more than the growth rate of g(n).

• We can use big-O notation to rank functions according to their


growth rate.

© e-Learning Centre, UCSC 21


7.3 Big-O notation contd.

Properties of Big-O

• Big-O is inherently imprecise; hence the smallest possible g(n) is


selected.

• If f(n) = n2+200n+45

• For g(n) we can chose anything greater than n2


• Eg: O(n4) , O(n6)

• But O(n2) is used for the Big-O as it gives better representation.

© e-Learning Centre, UCSC 22


7.3 Big-O notation contd.

Properties of Big-O contd.

• Big-O is transitive.

If f(n) is O(g(n))
and

g(n) is O(h(n))
then

f(n) is O(h(n))

© e-Learning Centre, UCSC 23


7.3 Big-O notation contd.

Big-O and Growth Rate Contd.

© e-Learning Centre, UCSC 24


7.3 Big-O notation contd.

Big-O Summary

© e-Learning Centre, UCSC


25
Summary

The Running Time Analysis of The process of determining how processing time
an Algorithm increases with respect to the input time.

The Rate of Growth of an The rate at which the running time increases as a
Algorithm function of input size.

Big-O notation is a mathematical notation that gives the


Big-O Notation upper bound on the rate of growth of an algorithm.

© e-Learning Centre, UCSC 26


8 : Sorting and Searching Algorithms

IT3206 – Data Structures and Algorithms

Level II - Semester 3

© e-Learning Centre, UCSC


Overview

• This section will illustrate several sorting and searching


algorithms and will discuss the implementations for each
algorithm.

• This section also discusses the time complexities of each


sorting and searching algorithm.

© e-Learning Centre, UCSC 2


Intended Learning Outcomes

• At the end of this lesson, you will be able to;


• Explain selected searching and sorting Algorithms.
• Demonstrate implementations of selected searching and
sorting algorithms.
• Analyze the time complexities of selected searching and
sorting algorithms.

© e-Learning Centre, UCSC 3


List of subtopics
1. Introduction to iterative and, Divide and Conquer Methodology
2. Sorting
i. Iterative Method
a) Bubble sort
b) Selection sort
c) Insertion sort
ii. Divide and Conquer Method
a) Merge sort
b) Quick sort
c) Radix Sort
d) Heap Sort
3. Searching algorithms
i. Linear search
ii. Binary search
iii. Interpolation search

© e-Learning Centre, UCSC 4


8.1 Introduction to iterative and, Divide and Conquer
Methodology

Iterative Method
• An iterative algorithm executes steps in iterations.
• Repetitive structure is used in the iterative methodology.

Divide and Conquer Method


• In divide and conquer methodology, the problem is break
into several subproblems and solve the subproblems.
• Then combine these solutions to create the solution for the
original problem.

© e-Learning Centre, UCSC 5


8.2 Sorting

- The output is in a certain order (increasing or decreasing).


- The output is a permutation, or reordering, of the input

© e-Learning Centre, UCSC 6


8.2.1 Iterative Method

• The Iterative method uses repetition structure.


• Looping statements are used in the iterative method such
as :
• for loop
• while loop
• do while loop
• repeat until etc.
• The following basic algorithms are discussed in this section.
• Bubble sort (sorting by exchange)
• Selection sort (sorting by selecting)
• Insertion sort (sorting by insertion)

© e-Learning Centre, UCSC 7


8.2.1 Iterative Method - Sorting by Exchange

• Eg : Bubble sort
• One of the simplest sorting is algorithm is known
as bubble sort. The algorithm as follows.
• Beginning at the last element in the list
• Compare each element with the previous
element in the list. If an element is less than its
predecessor, swap these two element.
• To completely sort the list, you need to perform
this process n-1 times on a list of length n

© e-Learning Centre, UCSC 8


8.2.1.1 Bubble sort

• Bubble sort is an instance of a sorting by exchange


category.
© e-Learning Centre, UCSC 9
8.2.1.1 Bubble sort

• There are two main methods of exchanging the data


elements in the bubble sort algorithm
• from first data element to last data element
• from last data element to first data element

© e-Learning Centre, UCSC 10


8.2.1.1 Bubble sort

• Following is a demonstration of how bubble sorting works.


Example 01

https://commons.wikimedia.org/wiki/File:Bubble-sort.gif

© e-Learning Centre, UCSC 11


Example 02
• Let's consider an array with values (5, 1, 6, 2, 4, 3)
• Below, we have a pictorial representation of how bubble sort will
sort the given array.

© e-Learning Centre, UCSC 12


8.2.1.1 Bubble sort

• The pseudocode for the bubble sort algorithm is given


below:

begin BubbleSort(list)

for all elements of list (iterate through all the data elements)
if list[i] > list[i+1] (check whether the two data elements are in correct order)
swap(list[i], list[i+1]) (if the data elements are not in the correct order, swap
the two data elements)
end if
end for

return list

end BubbleSort

© e-Learning Centre, UCSC 13


8.2.1.1 Bubble sort
Let's consider an array with values (5 1 4 2 8).
First pass
• ( 5 1 4 2 8 ) –> ( 1 5 4 2 8 )
• The algorithm compares the first two elements (5 and 1).
• Elements are not in the correct order (5 > 1)
• Swaps element 5 with element 1
• ( 1 5 4 2 8 ) –> ( 1 4 5 2 8 )
• The algorithm compares the next two elements (5 and 1).
• Elements are not in the correct order (5 > 4)
• Swaps element 5 with element 4
• ( 1 4 5 2 8 ) –> ( 1 4 2 5 8 )
• The algorithm compares the next two elements (5 and 2).
• Elements are not in the correct order (5 > 2)
• Swaps element 5 with element 2
• ( 1 4 2 5 8 ) –> ( 1 4 2 5 8 )
• The algorithm compares the next two elements (5 and 8).
• Elements are in the correct order (5 < 8)

End of first pass (All data elements are iterated)


© e-Learning Centre, UCSC 14
8.2.1.1 Bubble sort

Second pass
• ( 1 4 2 5 8 ) –> ( 1 4 2 5 8 )
• ( 1 4 2 5 8 ) –> ( 1 2 4 5 8 ),
• Elements are not in the correct order (4 > 2)
• Swaps element 4 with element 2
• ( 1 2 4 5 8 ) –> ( 1 2 4 5 8 )
End of the second pass (All data elements are iterated)

• All data elements are in sorted order ( 1 2 4 5 8 ).

© e-Learning Centre, UCSC 15


8.2.1.1 Bubble sort

Eg :
• (a)Run through the bubble sort algorithm by hand on the
list :44,55,12,42,94,18,06,67
• (b) Write a Java program to implementing the bubble sort
algorithm on an array.
• The basic idea underlying the bubble sort is to pass
through the file sequentially several times.
• Each pass consists of comparing each element in the file
with its predecessor [x[i] and x[i-1] and interchanging the
two elements if they are not proper order.

© e-Learning Centre, UCSC 16


8.2.1.1 Bubble sort

• The following comparisons are made on the first pass


• 44,55,12,42,94,18,06,67
• Data[7] with Data[6] ( 67,06) No interchange
• Data[6] with Data[5] ( 06,18) interchange
• Data[5] with Data[4] ( 06,94) interchange
• Data[4] with Data[3] ( 06,42) interchange
• Data[3] with Data[2] ( 06,12 interchange
• Data[2] with Data[1] ( 06,55) interchange
• Data[1] with Data[0] ( 06,44) interchange
• after the first pass, the smallest element is in its
proper positions.
• 06,44,55,12,42,94,18,67
© e-Learning Centre, UCSC 17
8.2.1.1 Bubble sort

• Original -> 44,55,12,42,94,18,06,67


• Pass 1 -> 06,44,55,12,42,94,18,67
• Pass 2 -> 06,12,44,55,18,42,94,67
• Pass 3 -> 06,12,18,44,55,42,67,94
• Pass 4 -> 06,12,18,42,44,55,67,94
• Pass 5 -> 06,12,18,42,44,55,67,94
• Pass 6 -> 06,12,18,42,44,55,67,94
• Pass 7 -> 06,12,18,42,44,55,67,94
• Sorted file->06,12,18,42,44,55,67,94

© e-Learning Centre, UCSC 18


8.2.1.1 Bubble sort

• Java code for bubble sort algorithm

static void bubbleSort(int[] arr) {

int n = arr.length;
int temp = 0;

for(int i=0; i < n; i++){


for(int j=1; j < (n-i); j++){

if(arr[j-1] > arr[j]){


temp = arr[j-1];
arr[j-1] = arr[j];
arr[j] = temp;
}

}
} © e-Learning Centre, UCSC 19
8.2.1.1 Bubble sort

Time complexity analysis cont.


• Bubble sort employs two loops: an inner loop and an outer
loop. The inner loop performs O(N) comparisons
deterministically. In the worst-case scenario, the outer
loop runs O(N) times. As a result, the worst-case time
complexity of bubble sort is O(N x N) =
• We need to do N iterations. In each iteration, we do the
comparison, and we perform swapping if required. Given
an array of size N, the first iteration performs (N - 1)
comparisons. The second iteration performs (N - 2)
comparisons. In this way, the total number of comparison
will be:

• Time complexity of the bubble sort would be


© e-Learning Centre, UCSC 20
8.2.1.1 Bubble sort

• Analysis of time (nanoseconds) with respect to the


number of data elements (n)

© e-Learning Centre, UCSC 21


8.2.1.2 Selection sort

• In terms of an array A, the selection sort finds the


smallest element in the array and exchanges it
with A[0]. Then, ignoring A[0], the sort finds the
next smallest and swaps it with A[1] and so on.

© e-Learning Centre, UCSC 22


8.2.1.2 Selection sort

• Point 01

• Selection sort is an instance of a sorting by selection


category.

© e-Learning Centre, UCSC 23


8.2.1.2 Selection sort

• Following is a demonstration of how Selection sorting


works.
Example 01

© e-Learning Centre, UCSC 24


8.2.1.2 Selection sort
Example 02
• The following is an illustration of how Selection sorting
works.

84

© e-Learning Centre, UCSC 25


8.2.1.2 Selection sort

• Pseudocode for the selection sort algorithm

Begin SelectionSort(list, n)

for i = 1 to n - 1
min = i (take 1st element of the unsorted list as min)

for j = i+1 to n (iterate through all the elements of the list)


if list[j] < list[min] then (if j data item is less than min)
min = j (update min to j data item)
end if
end for

if indexMin != i then (if 1st element of the unsorted list and min is different)
swap list[min] and list[i] (swap 1st element of unsorted list with min)
end if

end for
end selectionSort © e-Learning Centre, UCSC 26
8.2.1.2 Selection sort
Let's consider an array with values (5 1 4 2 8).
• ( 5 1 4 2 8 ) –> ( 1 5 4 2 8 )
• take 1st element of the unsorted list as min = 5
• find and update the min of the unsorted list = 1
• swap 1st element of the unsorted list with min
• Swaps element 5 with element 1
• ( 1 5 4 2 8 ) –> ( 1 2 4 5 8 )
• take 1st element of the unsorted list as min = 5
• find and update the min of the unsorted list = 2
• swap 1st element of the unsorted list with min
• Swaps element 5 with element 2
• ( 1 2 4 5 8 ) –> ( 1 2 4 5 8 )
• take 1st element of the unsorted list as min = 4
• find and update the min of the unsorted list = 4
• 1st element and the min is the same
• ( 1 2 4 5 8 ) –> ( 1 2 4 5 8 )
• take 1st element of the unsorted list as min = 5
• find and update the min of the unsorted list = 5
• 1st element and the min is the same
End of the iteration © e-Learning Centre, UCSC 27
8.2.1.2 Selection sort
• Java code for selection sort algorithm

void selectionSort(int arr[], int n)


{
int i, j, min_idx;
for (i = 0; i < n; i++) {
min_idx = i;
for (j = i+1; j < n; j++) {
if (arr[j] < arr[min_idx] )
min_idx = j;
}
int temp = arr[min_dx];
arr[min_dx] = arr[i];
arr[i] = temp;
}
}
© e-Learning Centre, UCSC 28
8.2.1.2 Selection sort

Time complexity analysis


• The implementation has two loops.
• The outer loop which picks the values one by one from the
list is executed n times where n is the total number of
values in the list.
• The inner loop, which compares the value from the outer
loop with the rest of the values, is also executed n times
where n is the total number of elements in the list.
• Therefore, the number of executions is (n * n), which can
also be expressed as O(n2).

© e-Learning Centre, UCSC 29


8.2.1.2 Selection sort

Time complexity analysis cont.


void selectionSort(int arr[], int n)
{
Line 1 - int i, j, min_idx;
Line 2 - for (i = 0; i < n; i++) {
Line 3 - min_idx = i;
Line 4 - for (j = i+1; j < n; j++) {
Line 5 - if (arr[j] < arr[min_idx] )
Line 6 - min_idx = j;}
Line 7 - int temp = arr[min_dx];
Line 8 - arr[min_dx] = arr[i];
Line 9 - arr[i] = temp;
}
}

© e-Learning Centre, UCSC 30


8.2.1.2 Selection sort

Time complexity analysis cont.

Line 1: COST = C1, TIME = 1, where C1 is some constant


Line 2: COST = C2, TIME = n+1, where C2 is some constant
Line 3: COST = C3, TIME = n, where C3 is some constant
Line 4: COST = C4, TIME = (n²-n) / 2 + n, where C4 is some constant
Line 5: COST = C5, TIME = (n²-n) / 2, where C5 is some constant
Line 6: COST = C6, TIME = (n²-n) / 2, where C6 is some constant
Line 7: COST = C7, TIME = n, where C7 is some constant
Line 8: COST = C8, TIME = n, where C5 is some constant
Line 9: COST = C9, TIME = n, where C9 is some constant

Runtime = (C1 *1) + (C2 *(n+1)) + (C3 *n) + (C4 * ((n²-n)/2) + n) + (C5 * (n²-n) / 2) +
(C6 * (n²-n) / 2) + (C7 * n)+ (C8 * n)+ (C9 * n)
Where U,V, and W are constants
= U +Vn + Wn²
= O(n²) © e-Learning Centre, UCSC 31
8.2.1.3 Insertion sort

• Point 01

• Insertion sort is an instance of a sorting by insertion


category.
© e-Learning Centre, UCSC 32
8.2.1.3 Insertion sort

• Following is a demonstration of how Insertion sorting


works.
Example 01

© e-Learning Centre, UCSC 33


8.2.1.3 Insertion sort
Example 02
• Following is a illustration of how Insertion sorting works.

© e-Learning Centre, UCSC 34


8.2.1.3 Insertion sort
• Pseudocode for insertion sort algorithm

Begin insertionSort(A)

for i = 1 to n
key ← A [i]
j←i–1

while j > = 0 and A[j] > key (compare the adjacent elements and if not in the correct
order)
A[j+1] ← A[j] (replace j+1 indexed element with j indexed element)
j←j–1
End while

A[j+1] ← key (replace j+1 indexed element with ‘key’ element)

End for

End insertionSort © e-Learning Centre, UCSC 35


8.2.1.3 Insertion sort
Let's consider an array with values (5 1 4 2 8).
• ( 5 1 4 2 8 ) –> ( 1 5 4 2 8 )
• compare first two elements of the list (5>1)
• not in the correct order
• remove lower value element (1) and insert into the
correct order position (1, 5)
• ( 1 5 4 2 8 ) –> ( 1 4 5 2 8 )
• compare next two elements of the list (5>4)
• not in the correct order
• remove lower value element (4) and insert into the
correct order position (1, 4, 5)
• ( 1 4 5 2 8 ) –> ( 1 2 4 5 8 )
• compare next two elements of the list (5>2)
• not in the correct order
• remove lower value element (2) and insert into the
correct order position (1, 2, 4, 5)
• ( 1 2 4 5 8 ) –> ( 1 2 4 5 8 )
• compare next two elements of the list (8>5)
• elements are in correct order
End of the iteration © e-Learning Centre, UCSC 36
8.2.1.3 Insertion sort

• Java Code for insertion sort algorithm

public static void insertionSort(int array[]) {


int n = array.length;

for (int i = 1; i < n; i++) {


int key = array[i];
int j = i-1;

while ( (j > -1) && ( array [j] > key ) ) {


array [j+1] = array [j];
j--;
}

array[j+1] = key;
}
© e-Learning Centre, UCSC 37
8.2.1.3 Insertion sort

Time complexity analysis


• The two nested loops are an indication that we are dealing
with quadratic effort, meaning with time complexity of
O(n²).
• This is the case if both the outer and the inner loop count
up to a value that increases linearly with the number of
elements.

© e-Learning Centre, UCSC 38


8.2.2 Divide and Conquer Method

• In divide and conquer method, the original problem is


divided into smaller subproblems and find the solutions for
those subproblems.
• Then the solutions are combined to find the solution for the
original problem.
• The divide-and-conquer paradigm involves three steps at
each level of the recursion:
• Divide the problem into a number of subproblems that
are smaller instances of the same problem.
• Conquer the subproblems by solving them recursively.
If the subproblem sizes are small enough, however, just
solve the subproblems in a straightforward manner.
• Combine the solutions to the subproblems into the
solution for the original problem.

© e-Learning Centre, UCSC 39


8.2.2 Divide and Conquer Method

• Following is a demonstration of how divide and conquer


method works.

© e-Learning Centre, UCSC 40


8.2.2.1 Merge sort

• Point 01

© e-Learning Centre, UCSC 41


8.2.2.1 Merge sort

• Following is a demonstration of how merge sorting works.

Example 01

https://en.wikipedia.org/wiki/Merge_sort

© e-Learning Centre, UCSC 42


8.2.2.1 Merge sort

• Following is a illustration of how merge sorting works.


Example 02

© e-Learning Centre, UCSC 43


8.2.2.1 Merge sort
• Pseudocode for merge sort algorithm

function mergeSort( array[] data ):

// base case:
if len(data) < 2:
return data

// recursive case:

mid_index = floor( length(data)/2 )

left_half = data[:mid_index]
right_half = data[mid_index:]

left_half = mergeSort(left_half)
right_half = mergeSort(right_half)

merge(left_half, right_half, data)

return data
} © e-Learning Centre, UCSC 44
8.2.2.1 Merge sort
• Java code for merge sort algorithm

public static void mergeSort(int[] a, int n) {


if (n < 2) {
return;
}
int mid = n / 2;
int[] l = new int[mid];
int[] r = new int[n - mid];

for (int i = 0; i < mid; i++) {


l[i] = a[i];
}
for (int i = mid; i < n; i++) {
r[i - mid] = a[i];
}
mergeSort(l, mid);
mergeSort(r, n - mid);

merge(a, l, r, mid, n - mid);


} © e-Learning Centre, UCSC 45
8.2.2.1 Merge sort

Time complexity analysis


• To merge the subarrays, made by dividing the original array
of n elements, a running time of O(n) will be required.
• Hence the total time for merge sort will become n(log n + 1),
which gives us a time complexity of O(n*log n).

© e-Learning Centre, UCSC 46


8.2.2.2 Quick sort

• Point 01

© e-Learning Centre, UCSC 47


8.2.2.2 Quick sort

• Quick sort is one of the fastest sorting by exchange


algorithm.
• Given an array of n elements, in quick sort:
If array only contains one element,
• return array.
Else
• Pick one element to use as pivot.
• Partition elements into two sub-arrays:
• Elements less than or equal to pivot
• Elements greater than pivot
• Quicksort two sub-arrays
• Return results

© e-Learning Centre, UCSC 48


8.2.2.2 Quick sort

Partitioning - quick sort algorithm


• Choose any number from data elements to use it as a
pivot (p) to partition the elements of the array such that
the resulting array consists of:
• One sub-array that contains elements >= pivot
• Another sub-array that contains elements < pivot

© e-Learning Centre, UCSC 49


8.2.2.2 Quick sort

There are many ways to pick the pivot value:


• Always pick first element as pivot.
• Always pick last element as pivot.
• Pick a random element as pivot.
• Pick median as pivot.

© e-Learning Centre, UCSC 50


8.2.2.2 Quick sort

Following are the basic steps in quick sort algorithm


• Step 1 − Pick the pivot value
• Step 2 − partition the array using pivot value
• Step 3 − quicksort left partition recursively
• Step 4 − quicksort right partition recursively

© e-Learning Centre, UCSC 51


8.2.2.2 Quick sort

• Following is a demonstration of how quick sorting works.


Example 01

© e-Learning Centre, UCSC 52


8.2.2.2 Quick sort

• Following is a illustration of how quick sorting works.


Example 02

© e-Learning Centre, UCSC 53


8.2.2.2 Quick sort

• Following is a illustration of how quick sorting works.


Example 03

© e-Learning Centre, UCSC 54


8.2.2.2 Quick sort
• Pseudocode for quick sort algorithm - partitioning function

partition(arr, beg, end)


set end as pivotIndex
pIndex = beg - 1

for i = beg to end-1


if arr[i] < pivot
swap arr[i] and arr[pIndex]
pIndex++

swap pivot and arr[pIndex+1]


return pIndex +

© e-Learning Centre, UCSC 55


8.2.2.2 Quick sort

• Pseudocode for quick sort algorithm - sorting function

quickSort(arr, beg, end)


if (beg < end)
pivotIndex = partition(arr,beg, end)
quickSort(arr, beg, pivotIndex)
quickSort(arr, pivotIndex + 1, end)

© e-Learning Centre, UCSC 56


8.2.2.2 Quick sort

• Java code for quick sort algorithm - partitioning function

static int partition(int[] arr, int low, int high)


{
int pivot = arr[high];
int i = (low - 1);

for(int j = low; j <= high - 1; j++)


{
if (arr[j] < pivot)
{
i++;
swap(arr, i, j);
}
}
swap(arr, i + 1, high);
return (i + 1);
} © e-Learning Centre, UCSC 57
8.2.2.2 Quick sort

• Java code for quick sort algorithm - sorting function

static void quickSort(int[] arr, int low, int high)


{
if (low < high)
{
int pi = partition(arr, low, high);
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}

© e-Learning Centre, UCSC 58


8.2.2.2 Quick sort

Time complexity analysis


• For an array, in which partitioning leads to unbalanced
subarrays, to an extent where on the left side there are no
elements, with all the elements greater than the pivot, hence
on the right side.
• And if keep on getting unbalanced subarrays, then the
running time is the worst case, which is O(n2).
• Where as if partitioning leads to almost equal subarrays,
then the running time is the best, with time complexity as
O(n*log n).

© e-Learning Centre, UCSC 59


8.2.2.3 Radix Sort

• Point 01

© e-Learning Centre, UCSC 60


8.2.2.3 Radix Sort

• Suppose, there is an array of 6 elements.


• First, the algorithm sort the elements based on the value
of the unit place.
• Then, sort the elements based on the value of the tenth
place. Next, the hundred place.
• The comparisons are made among the digits of the
number from LSB to MSB.

© e-Learning Centre, UCSC 61


8.2.2.3 Radix sort

• Following is a demonstration of how radix sorting works


using binary numbers.
Example 01 - (2 0 5 1 7 3 4 6)

binary sort the elements based on LSB to MSB final element


input element
representation list - sorted
list
of elements

© e-Learning Centre, UCSC 62


8.2.2.3 Radix sort

• Following is a demonstration of how radix sorting works


using decimal numbers
Example 02 - (32 224 16 15 31 169 123 252)

input element sort the elements based on LSB to MSB


list

© e-Learning Centre, UCSC 63


8.2.2.3 Radix sort

• Following is a demonstration of how radix sorting works.


Example 03

© e-Learning Centre, UCSC 64


8.2.2.3 Radix sort
• Pseudocode for radix sort algorithm

function radixSort (L: list of unsorted items)


largest := max(L)
exponent := floor(log10(largest))
bucket := empty list
index := 0

for i to exponent+1 do:


bucket := empty list

for j to length(L) do:


number := L[j]
digit := i+1

while(digit--) do:
temp := number % 10 © e-Learning Centre, UCSC 65
8.2.2.3 Radix sort

• Pseudocode for radix sort algorithm cont.

number := floor(number-temp/10)
digit := temp
if bucket[digit] exists then
bucket[digit] := bucket[digit]
if bucket[digit] is undefined then
bucket[digit] := empty list
add L[j] to bucket[digit]
reset index to 0
for digit to length(bucket) do:
if bucket[digit] exists then
for j to length(bucket[digit])
L[index++] := bucket[digit][j]
return L
end-function © e-Learning Centre, UCSC 66
8.2.2.3 Radix sort

Time complexity analysis


• The complexity is O((n+b)* logb(maxx)) where b is the base
for representing numbers and maxx is the maximum element
of the input array.
• If maxx <= nc ,then the complexity can be written as
O(n*logb (n)).

© e-Learning Centre, UCSC 67


8.2.2.4 Heap Sort

• Point 01

© e-Learning Centre, UCSC 68


8.2.2.4 Heap Sort

• A heap is a complete binary tree.


• Heap sort processes the elements by creating the min-
heap or max-heap using the elements of the given array.
• Min-heap or max-heap represents the ordering of array in
which the root element represents the minimum or
maximum element of the array.
• Heap sort basically recursively performs two main
operations:
• Build a heap H, using the elements of array.
• Repeatedly delete the root element of the heap formed
in 1st phase.

© e-Learning Centre, UCSC 69


8.2.2.4 Heap sort

• Following is a demonstration of how heap sorting works.


Example 01

https://commons.wikimedia.org/wiki/File:Heap_sort_exa
mple.gif

© e-Learning Centre, UCSC 70


8.2.2.4 Heap sort
• Following is a illustration of how heap sorting works.
Example 02 - (4 3 7 1 8 5)

• Building max heap

© e-Learning Centre, UCSC 71


8.2.2.4 Heap sort
• Sorting the array

© e-Learning Centre, UCSC 72


8.2.2.4 Heap Sort

• Pseudocode for heap sort algorithm

def heap_sort(array):
length = len(array)
array = build_heap(array)

for i in range(length-1, 0, -1):


largest = array[0]
array[0] = array[i]
array[i] = largest

heapify(array[:i], 0)

return array

© e-Learning Centre, UCSC 73


8.2.2.4 Heap Sort
• Java code for heap sort algorithm

public void Heapsort(int arr[])


{
int n = arr.length;

for (int i = n / 2 - 1; i >= 0; i--)


heapify(arr, n, i);

for (int i = n - 1; i > 0; i--) {


int temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;

heapify(arr, i, 0);
}
}

© e-Learning Centre, UCSC 74


8.2.2.4 Heap sort

Time complexity analysis


• heapsort runs in O(N*logN) time. Although it may be slightly
slower than quicksort, an advantage over quicksort is that it
is less sensitive to the initial distribution of data.
• Certain arrangements of key values can reduce quicksort to
slow O(N2) time, whereas heapsort runs in O(N*logN) time
no matter how the data is distributed.

© e-Learning Centre, UCSC 75


8.3 Searching algorithms

• Point 01

© e-Learning Centre, UCSC 76


8.3.1 Linear search

• When the input array is not sorted, we have little choice


but to do a linear sequential search, which steps through
the array sequentially until a match is found.
• The complexity of the algorithm is analyzed in three ways.
• First, we provide the cost of an unsuccessful search.
• Then, we give the worst-case cost of a successful
search.
• Finally, we find the average cost of a successful
search.
• Analyzing successful and unsuccessful searches
separately is typical.
• Unsuccessful searches usually are more time consuming
than are successful searches.
• For sequential searching, the analysis is straightforward.

© e-Learning Centre, UCSC 77


8.3.1 Linear search

• An unsuccessful search requires the examination of every


item in the array, so the time will be O(N) (N is the number
of items in the array).
• In the worst case, a successful search, too, requires the
examination of every item in the array because we might
not find a match until the last item.
• Thus the worst-case running time for a successful search
is also linear.
• On average, however, we search only half of the array.
• That is, for every successful search in position i, there is a
corresponding successful search in position N-1-i
(assuming we start numbering from 0).
• However, N/2 is still O(N).

© e-Learning Centre, UCSC 78


8.3.1 Linear search

• Following is a demonstration of how linear search works.


Example 01

https://www.tutorialspoint.com/data_structures_algorithms/linear_search_algorithm.htm

© e-Learning Centre, UCSC 79


8.3.2 Binary search

• Search a sorted array by repeatedly dividing the search


interval in half. Begin with an interval covering the whole
array.
• If the value of the search key is less than the item in the
middle of the interval, narrow the interval to the lower half.
• Otherwise narrow it to the upper half. Repeatedly check
until the value is found or the interval is empty.

© e-Learning Centre, UCSC 80


8.3.2 Binary search
• Following is a demonstration of how binary search works.
Example 01

https://brilliant.org/wiki/binary-search/

© e-Learning Centre, UCSC 81


8.3.2 Binary search
• Following is a illustration of how binary search works.
Example 02

© e-Learning Centre, UCSC 82


8.3.2 Binary search

• Pseudocode for binary search - iterative approach

binarySearch(arr, size)
loop until beg is not equal to end
midIndex = (beg + end)/2
if (item == arr[midIndex] )
return midIndex
else if (item > arr[midIndex] )
beg = midIndex + 1
else
end = midIndex - 1

© e-Learning Centre, UCSC 83


8.3.2 Binary search

• Pseudocode for binary search - recursive approach

binarySearch(arr, item, beg, end)


if beg<=end
midIndex = (beg + end) / 2
if item == arr[midIndex]
return midIndex
else if item < arr[midIndex]
return binarySearch(arr, item, midIndex + 1, end)
else
return binarySearch(arr, item, beg, midIndex - 1)

return -1

© e-Learning Centre, UCSC 84


8.3.2 Binary search
• Java code for binary search - iterative approach

public static void binarySearch(int arr[], int first, int last, int key){
int mid = (first + last)/2;
while( first <= last ){
if ( arr[mid] < key ){
first = mid + 1;
}else if ( arr[mid] == key ){
System.out.println("Element is found at index: " + mid);
break;
}else{
last = mid - 1;
}
mid = (first + last)/2;
}
if ( first > last ){
System.out.println("Element is not found!");
}
}
© e-Learning Centre, UCSC 85
8.3.2 Binary search
• Java code for binary search - recursive approach

public static int binarySearch(int arr[], int first, int last, int key){
if (last>=first){
int mid = first + (last - first)/2;
if (arr[mid] == key){
return mid;
}
if (arr[mid] > key){
return binarySearch(arr, first, mid-1, key);//search in left subarray
}else{
return binarySearch(arr, mid+1, last, key);//search in right subarray
}
}
return -1;
}

© e-Learning Centre, UCSC 86


8.3.2 Binary search

Time complexity analysis


• The time complexity of the binary search algorithm is
O(log n).
• The best-case time complexity would be O(1) when the
central index would directly match the desired value.
• The worst-case scenario could be the values at either
extremity of the list or values not in the list.

© e-Learning Centre, UCSC 87


8.3.3 Interpolation search
• The Interpolation Search is an improvement over Binary
Search.
• Interpolation search finds a particular item by computing
the probe position. Initially, the probe position is the
position of the middle most item of the collection.
• If a match occurs, then the index of the item is returned.
To split the list into two parts, we use the following
method,

mid = Lo + ((Hi - Lo) / (A[Hi] - A[Lo])) * (X - A[Lo])

A = list
Lo = Lowest index of the list
Hi = Highest index of the list
A[n] = Value stored at index n in the list
© e-Learning Centre, UCSC 88
8.3.3 Interpolation search
• Following is a illustration of how interpolation search
works.

Example 01

Suppose we want search number 84 in the following array

© e-Learning Centre, UCSC 89


8.3.3 Interpolation search
• The array's length is 8, so initially Hi = 7 and Lo = 0
• In the first step, the probe position formula will result in
probe = 5:

© e-Learning Centre, UCSC 90


8.3.3 Interpolation search

• Because 84 is greater than 73 (current probe), the next step


will abandon the left side of the array by assigning
Lo= probe + 1.
• Now the search space consists of only 84 and 101. The
probe position formula will set probe = 6 which is exactly the
84's index:
• Since the target (84) is found, index 6 will return.

© e-Learning Centre, UCSC 91


8.3.3 Interpolation search
• Pseudocode for interpolation search

A → Array list
N → Size of A
X → Target Value

Procedure Interpolation_Search()

Set Lo → 0
Set Mid → -1
Set Hi → N-1

While X does not match

if Lo equals to Hi OR A[Lo] equals to A[Hi]


EXIT: Failure, Target not found
end if

© e-Learning Centre, UCSC 92


8.3.3 Interpolation search
• Pseudocode for interpolation search cont.

Set Mid = Lo + ((Hi - Lo) / (A[Hi] - A[Lo])) * (X - A[Lo])

if A[Mid] = X
EXIT: Success, Target found at Mid
else
if A[Mid] < X
Set Lo to Mid+1
else if A[Mid] > X
Set Hi to Mid-1
end if
end if
End While

End Procedure

© e-Learning Centre, UCSC 93


8.3.3 Interpolation search
• Java code for interpolation search

public static int interpolationSearch(int arr[], int lo,


int hi, int x)
{
int pos;

// Since array is sorted, an element


// present in array must be in range
// defined by corner
if (lo <= hi && x >= arr[lo] && x <= arr[hi]) {

// Probing the position with keeping


// uniform distribution in mind.
pos = lo
+ (((hi - lo) / (arr[hi] - arr[lo]))
* (x - arr[lo]));

© e-Learning Centre, UCSC 94


8.3.3 Interpolation search
• Java code for interpolation search cont.

// Condition of target found


if (arr[pos] == x)
return pos;

// If x is larger, x is in right sub array


if (arr[pos] < x)
return interpolationSearch(arr, pos + 1, hi, x);

// If x is smaller, x is in left sub array


if (arr[pos] > x)
return interpolationSearch(arr, lo, pos - 1, x);
}
return -1;
}

© e-Learning Centre, UCSC 95


8.3.3 Interpolation search
• A static searching method that is sometimes faster,
however, is an interpolation search, which has better Big-Oh
performance on average than binary search but has limited
practicality and a bad worst case.
• For an interpolation search to be practical, two assumptions
must be satisfied:
1. Each access must be very expensive compared to a
typical instruction.
For example, the array might be on a disk instead
of in memory, and each comparison requires a disk
access.
2. The data must not only be sorted, it must also be
fairly uniformly distributed.
For example, a phone book is fairly uniformly
distributed. If the input items are {1, 2, 4, 8, 16, ... },
the distribution is not uniform.

© e-Learning Centre, UCSC 96


8.3.3 Interpolation search

• The interpolation search requires that we spend more time


to make an accurate guess regarding where the item
might be. The binary search always uses the midpoint.
• Interpolation search has a better Big-Oh bound on
average than does binary search, but has limited
practicality and a bad worst case.

© e-Learning Centre, UCSC 97


Summary

The bubble sort is the least efficient, but


8.2.1 the simplest, sort.

The radix sort is about as fast as quicksort


8.2.2 but uses twice as much memory.

Running time of binary search algorithm is


8.3 O(log n)

© 2020 e-Learning Centre, UCSC

© e-Learning Centre, UCSC 98

You might also like