Sei sulla pagina 1di 40

Faculty of Engineering, Science & Technology

INDUS UNIVERSITY

BE (EP)-III

(EP-212A) Data Structure and Algorithms (0+1)

Lab Manual
FALL 2018

Prepared By: Engr. Faizan-ur-Rehman

Student Name: .

Student ID: .

Instructor Name: Engr. Faizan-ur-Rehman .

Signature and Date: .


Department of Electrical Engineering, FEST, Indus University, Karachi

LIST OF EXPERIMENTS
(EP-212A) Data Structures and Algorithms (0+1)
OBE ATTAINMENT (Course): OBE ATTAINMENT(Taxonomy): OBE ATTAINMENT(Program):
COs (Course Outcomes):CO-1,2,3 Domain: Cognitive Program Outcome (PO)
Level: C3 PLOs: PO-2

S.
Lab Experiments CLO PLO Taxonomy Marks Signature
No
Study different operations (insertion, deletion
1 and traversal) to modify the arrays using C++. 1 2 C3

Apply different algorithms to create records and


2 arrays of records. 1 2 C3

Use different searching algorithms (linear search


3 and binary search) to search data in array 1 2 C3

Apply different sorting algorithms (insertion,


4 selection and merge) on arrays. 1 2 C3

To familiarize with strings apply different


operations on strings (concatenation and pattern
5 2 2 C3
matching).

Study different operations (insertion, deletion


and traversal) to modify the Linked List using
6 2 2 C3
C++.

Study different operations (insertion, deletion


and traversal) to modify the Double linked List
7 2 2 C3
using C++.

Demonstrate the function of Push, POP, En-


queue and De-queue on stacks and queues using
8 2 2 C3
arrays and linked lists.

Apply recursive and Iterative algorithms on


9 arrays 3 2 C3

To understand a tree, produce a binary search


10 tree to sorted doubly link list 3 2 C3

To analyze tree traversal (in-order, pre-order and


post-order), apply breadth-first search and
11 3 2 C3
depth-first search algorithm

To understand the graph by applying traversal


12 and shortest path algorithm 3 2 C3
Department of Electrical Engineering, FEST, Indus University, Karachi

EXPERIMENT #1
TO STUDY ARRAY AND ITS OPERATIONS (INSERTION, DELETION AND
TRAVERSAL)
Introduction An array is a series of elements of the same type placed in contiguous memory locations
that can be individually referenced by adding an index to a unique identifier. As discussed in the
class/lecture room, there are different algorithms related to an array (Traversing, Insertion, Deletion,
Modify, Sorting, Searching (Linear, Binary). Following algorithms helps you to understand and write
programs.
Traversing in Linear Array:
Description: It means processing or visiting each element in the array exactly for one operation. Let „A‟is
an array stored in the computer‟s memory and we want to display the contents of „A‟, then it has to be
traversed i.e. by accessing and processing each element of „A‟ exactly once. Linear array „A‟ with lower
boundary LB ( 0 in C++ ) and upper boundary ( UB =N - 1 in C++) where N is the number of values
stored in the array. If the array is empty then N will be equal 0. SIZE is the total locations /positions
available in array. This algorithm traverses „A‟ applying process to each element of „A‟.

Algorithm: (Traverse a Linear Array) Here A is an array has N elements stored


in it, with lower bound LB=0 and upper bound UB= N - 1.
1. K = LB and UB = N - 1
2. Repeat Steps 3 and 4 while K ≤ UB.
3. Apply PROCESS to A[K].
4. K = K+1.
[End of Step 2 loop.]
5. End.
Insert an Item into Linear Array:
Description: Inserting refers to the addition of a new element in an array, say „A‟. Inserting an element at
the end of the array can be easily done. On the other hand, if an element is to be inserted at the beginning
or in the middle of array „A‟, then the elements (from insertions point inclusively) must be moved
downward to new locations, to accommodate the new element. Assume, values inside the „A‟ are in
sorted order and it is needed to insert the new item at such location in „A‟ so that the sorted order of „A‟
should not be disturbed. See the algorithm:
The following set of algorithms inserts a data element ITEM at Kth position in a linear array.
Here A is a Linear Array with SIZE locations, N is the number of total values stored in A and K is a
positive integer (location where to insert) such that K<= N. This algorithm inserts an element ITEM into
the Kth position in A.

Data Structure and Algorithms (Lab Manual) Page 1


Department of Electrical Engineering, FEST, Indus University, Karachi
Algorithm:
1. if N = SIZE then write: “Overflow, Array is Full. “ and End
2. Get ITEM from user to be inserted in array
[ Find location in sorted array ]
3. Call Find_Location_To_Insert (A, N, K, ITEM)
[ Above algorithm finds the location K where to insert ]
4. Call INSERT (A, N, K, ITEM)
5. End
Algorithm: Find_Location_To_Insert(A, N, K, ITEM)
1. LB = 0 and UB = N – 1
2. Repeat Step-3 for K = LB to UB.
3. If A[K] = ITEM then Exit
Loop. [End of Step 2 loop.]
4. return K.
5. End.
Algorithm: INSERT (A, N, K, ITEM)
1. Set J = N - 1. [Initialize counter.]
2. Repeat Step-3 and 4 while J≥K.
3. Set A[J+1] = A[J]. [Move Jth element downward.]
4. Set J = J-1. [Decrease counter.]
[End of Step 2 loop.]
5. Set A[K] = ITEM. [Insert element.]
6. Set N = N+1. [Reset N.]
7. End.
Delete an Item from Linear Array:
Description: Deletion refers to the operation of removing one of the element m from the array „A‟.
Deleting an item at the end of the array presents no difficulties. But, deleting an item from beginning or
somewhere in the middle of array would require that each subsequent element be moved one location
upward in order to fill up the array.
The following algorithm deletes the Kth element from a linear array A with N values stored in it. Here A
is a Linear Array with SIZE locations, N is the number of total values stored in A and K is a positive
integer such that K<=N. This algorithm deletes the Kth element from A.
Algorithm:
1. If N = 0 then write: “Underflow. Array is Empty. “ and End
2. Get ITEM from user to be deleted from array
[ Find location in sorted array ]
3. Call Find_Location_To_Delete(A, N, K, ITEM)

Data Structure and Algorithms (Lab Manual) Page 2


Department of Electrical Engineering, FEST, Indus University, Karachi

4. If found Call DELETE (A, N, K, ITEM) [ if K = -1 then not found ]


Else write: “Not Found in array”
5. End
Algorithm: Find_Location_To_Delete(A, N, K, ITEM)
1. Repeat Step 2 for I = LB to UB.
2. If A[I] = ITEM then K = I and return K. [ Deletion from front or from middle]
[End of Step 2 loop.]
3. K = -1 and return K. [ITEM Not found in array ]
4. End.
Algorithm: DELETE (A, N, K, ITEM)
1. Set ITEM = A[K].
2. Repeat for J=K to N-1:
Set A[J] = A[J+1] [Move J + 1 element upward.].
[End of loop.]
3. Set N = N-1. [Reset the number “N” of element in A.]
4. End.
Lab Task:
Q1. Convert the above algorithms in C/C++
Q2. Write program for finding the maximum (largest) value in finite sequence of integers
using binary search algorithm.
Q3. Write a program to search any number from an array using linear search.

Data Structure and Algorithms (Lab Manual) Page 3


Department of Electrical Engineering, FEST, Indus University, Karachi

EXPERIMENT # 2
TO STUDY RECORDS, SET STRUCTURES AND ARRAYS OF RECORDS
Introduction: C/C++ arrays allow you to define variables that combine several data items of the same
kind but Records is another user defined data type which allows you to combine data items of different
kinds. Structures are used to represent a record, suppose you want to keep track of your books in a
library. You might want to track the following attributes about each book:
Title
Author
Subject
Book ID

Defining a Structure:
To define a structure, you must use the struct statement. The struct statement defines a new data type,
with more than one member, for your program. The format of the struct statement is this:
struct [structure tag]
{
member definition;
member definition;
...
member definition;
} [one or more structure variables];

The structure tag is optional and each member definition is a normal variable definition, such as int i;
or float f; or any other valid variable definition. At the end of the structure's definition, before the final
semicolon, you can specify one or more structure variables but it is optional. Here is the way you would
declare the Book structure:
struct Books
{
char title[50]; char
author[50]; char
subject[100]; int
book_id;
}book;
Accessing Structure Members:
To access any member of a structure, we use the member access operator (.). The member access
operator is coded as a period between the structure variable name and the structure member that we wish

Data Structure and Algorithms (Lab Manual) Page 4


Department of Electrical Engineering, FEST, Indus University, Karachi

to access. You would use struct keyword to define variables of structure type. Following is the example
to explain usage of structure:

#include <iostream>
#include <cstring>
using namespace std;
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
};
int main( )
{
struct Books Book1; // Declare Book1 of type Book
struct Books Book2; // Declare Book2 of type Book
// book 1 specification
strcpy( Book1.title, "Learn C++ Programming");
strcpy( Book1.author, "Chand Miyan");
strcpy( Book1.subject, "C++ Programming");
Book1.book_id = 6495407;
// book 2 specification
strcpy( Book2.title, "Telecom Billing");
strcpy( Book2.author, "Yakit Singha");
strcpy( Book2.subject, "Telecom");
Book2.book_id = 6495700;
// Print Book1 info
cout << "Book 1 title : " << Book1.title <<endl;
cout << "Book 1 author : " << Book1.author <<endl;
cout << "Book 1 subject : " << Book1.subject <<endl;
cout << "Book 1 id : " << Book1.book_id <<endl;
// Print Book2 info
cout << "Book 2 title : " << Book2.title <<endl;
cout << "Book 2 author : " << Book2.author <<endl;
cout << "Book 2 subject : " << Book2.subject <<endl;

Data Structure and Algorithms (Lab Manual) Page 5


Department of Electrical Engineering, FEST, Indus University, Karachi
cout << "Book 2 id : " << Book2.book_id <<endl;
return 0;
}

When the above code is compiled and executed, it produces the following result:
Book 1 title : Learn C++ Programming
Book 1 author : Chand Miyan
Book 1 subject : C++ Programming
Book 1 id : 6495407
Book 2 title : Telecom Billing
Book 2 author : Yakit Singha
Book 2 subject : Telecom
Book 2 id : 6495700

Structures as Function Arguments:


You can pass a structure as a function argument in very similar way as you pass any other variable or
pointer. You would access structure variables in the similar way as you have accessed in the above
example:
#include <iostream>
#include <cstring>
using namespace std;
void printBook( struct Books book );
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
};
int main( )
{
struct Books Book1; // Declare Book1 of type Book
struct Books Book2; // Declare Book2 of type Book
// book 1 specification
strcpy( Book1.title, "Learn C++ Programming");
strcpy( Book1.author, "Chand Miyan");

Data Structure and Algorithms (Lab Manual) Page 6


Department of Electrical Engineering, FEST, Indus University, Karachi
strcpy( Book1.subject, "C++ Programming");
Book1.book_id = 6495407;
// book 2 specification
strcpy( Book2.title, "Telecom Billing");
strcpy( Book2.author, "Yakit Singha");
strcpy( Book2.subject, "Telecom");
Book2.book_id = 6495700;
// Print Book1 info
printBook( Book1 );
// Print Book2 info
printBook( Book2 );
return 0;
}
void printBook( struct Books book )
{
cout << "Book title : " << book.title <<endl; cout
<< "Book author : " << book.author <<endl;
cout << "Book subject : " << book.subject <<endl;
cout << "Book id : " << book.book_id <<endl;
}

When the above code is compiled and executed, it produces the following result:
Book title : Learn C++ Programming
Book author : Chand Miyan
Book subject : C++ Programming
Book id : 6495407
Book title : Telecom Billing
Book author : Yakit Singha
Book subject : Telecom
Book id : 6495700

Lab Task:

Q1. Write a C++ program to store and display the information of Student (Name, ID, Contact,
Email, and Gender) in Structure.
Q2. Write a C++ program to add to distances in (inch-feet) system using structures. Distances
D1 and D2 should be defined by user at run time.

Data Structure and Algorithms (Lab Manual) Page 7


Department of Electrical Engineering, FEST, Indus University, Karachi

EXPERIMENT # 3
TO STUDY SEARCHING IN ARRAY ALGORITHMS (LINEAR SEARCH,
BINARY SEARCH)
Introduction: The linear search compares each element of the Linear Array „A‟ which has N values in it
with the search key until the search key is found. To determine that a value is not in the array, the
program must compare the search key to every element in the array „A‟. It is also called “Sequential
Search” because it traverses the data sequentially to locate the element.
Algorithm: (Linear Search)
LINEAR_SEARCH (A, N, SKEY)
Here A is a Linear Array with N elements and SKEY is a given item of information to search. This
algorithm finds the location of SKEY in A and if successful, it returns its location otherwise it returns -1
for unsuccessful. T is a variable that we use temporary.
1. Repeat step-2 for K = 0 to N-1
2. if(A [K] = SKEY)
T=K
K= N
1. If (k<N)
return K [Successful Search]
else
return -1 [Un-Successful]
4. End.
Binary Search.
Suppose DATA is an array that is sorted in increasing (or decreasing) numerical order or, equivalently,
alphabetically. Then there is an extremely efficient searching algorithm, called binary search, which can
be used to find the location LOC of a given ITEM of information in DATA.
The binary search algorithm applied to our array DATA works as follows:
During each stage of algorithm, our search for ITEM is reduced to a segment of elements of
DATA: DATA [BEG], DATA [BEG+1], DATA [BEG+2]. . . DATA [END]
Note that the variables BEG and END denote, respectively, the beginning and end locations of the
segment under consideration. The algorithm compares ITEM with the middle element DATA [MID] of
the segment, where MID is computed as
MID = INT ((BEG + END) / 2) (INT (A) refers to the integer value of A.)
If DATA [MID] = = ITEM, then the search is successful and we set LOC = MID.
Otherwise a new segment of DATA is obtained as follows:
a) If ITEM < DATA[MID], then ITEM can appear only in the left half of the segment:
DATA[BEG], DATA[BEG+1], . . . , DATA[MID-1]
So we reset END = MID –1 and begin searching again.
b) If ITEM > DATA[MID], then ITEM can appear only in the right half of the segment:

Data Structure and Algorithms (Lab Manual) Page 8


Department of Electrical Engineering, FEST, Indus University, Karachi

DATA[MID+1], DATA[MID+2], . . . , DATA[END] So


we reset BEG = MID +1 and begin searching again.
Initially, we begin with the entire array DATA; i.e., we begin with
BEG = 0 and END = N-1.
If ITEM is not in DATA, then eventually we obtain BEG > END.
This condition signals that the search is unsuccessful, and in such a case we assign LOC = NULL. Here
NULL is a value that lies outside the set of indices of DATA.
Algorithm: BINARY SEARCH(DATA, ITEM)
1. Set BEG = 0, END = N-1 and MID = INT((BEG + END) / 2)
2. Repeat steps 3 and 4 while BEG <= END AND DATA[MID] ≠ ITEM
3. If ITEM < DATA[MID], then Set END = MID – 1, Else Set BEG = MID + 1
4. MID = INT((BEG + END) / 2)
5. If DATA[MID] = ITEM, then Set LOC = MID Else Set LOC = NULL
6. Exit
Lab Task:
Q1. Write a C program that makes use of the above algorithms as a function. Your
program should input the array from the user.
Q2. Which of the above twoalgorithms is more complex. Use complexity of algorithm
technique to support your comments.

Data Structure and Algorithms (Lab Manual) Page 9


Department of Electrical Engineering, FEST, Indus University, Karachi

EXPERIMENT # 4
TO STUDY AND ANALYZE SORTING IN ARRAY (BUBBLE, INSERTION,
SELECTION)
Introduction: Sorting and searching are fundamental operations in computer science. Sorting refers to
the operation of arranging data in some given order. Such as increasing/ascending or decreasing
/descending order, with numeric data or alphabetically. There are so many ways / techniques to do
sorting. Following are some techniques:
Description: Sorting refers to the operation of re-arrangements of values in
Ascending or Descending order of the Linear Array „A‟. Here „A‟ is Linear Array
and N is the number of values stored in A.
Algorithm: (Bubble Sort) BUBBLE (A, N) Here A is an Array with N elements stored in it. This
algorithm sorts the elements in A.
Step 1. Repeat Steps 2,3 for Pass = 1 to N – 1
Step 2. Set Swapped = 0 and K = 0
Step 3. Repeat while K < (N – Pass)
(a) if A[ K ] > A[ K + 1] then
Interchange A[ K ] and A[ K + 1 ] and
Set Swapped = 1
[ End of if structure. ]
(b) Set K = K + 1
[ End of inner loop of step-3. ]
[ End of outer loop of step-1. ]
Step 4. End
Insertion Sort
Description: Here „A‟ is Linear Array and N is the number of values stored in A
Algorithm: (INSERTION SORT) INSERTION (A, N)
[ Where A is an array and N is the number of values in the array ]
Step 1. Repeat steps 2 to 4 for K=1,2,3, . . . . . N-1:
Step 2. Set TEMP = A[K] and i =K-1.
Step 3. Repeat while i >= 0 and TEMP < A[i]
a) Set A[i+1] = A[i]. [Moves element forward.]
b) Set i = i -1.
[End of loop.]
Step 4. Set A[i+1] =TEMP. [Insert element in proper place.]
[End of Step 2 loop.]
Step 5. Return.

Data Structure and Algorithms (Lab Manual) Page 10


Department of Electrical Engineering, FEST, Indus University, Karachi

Selection Sort:
Description: Here „A‟ is Linear Array and N is the number of values stored in A.
Algorithm: SELECTION (A, N)
Step 1. Repeat steps 2, 3and 5 for K=0 to. N-2:
Step 2. Set MIN = A[K] and LOC = K. [Initializes pointers.]
Step 3. Repeat Step 4 for J=K+1, K+2, . . . . . N:
Step 4. If MIN > A[J], then: MIN = A[J] and LOC = J.
Step 5. Set TEMP = A[K], A[K] = A[LOC] and A[LOC] = TEMP.
[End of step 1 loop.]
Step 6. Exit
Lab Task:
Q1. Convert all algorithms into C++ programming.
Q2. Write a program to Sort values in Ascending / Increasing Order using
Quick Sort Technique in Linear Array

Q3. Which of the sorting algorithms is more complex as compared to other? Use complexity of
algorithm technique to support your comments.

Data Structure and Algorithms (Lab Manual) Page 11


Department of Electrical Engineering, FEST, Indus University, Karachi

EXPERIMENT # 5
TO FAMILIARIZE WITH THE STRING OPERATION AND FUNCTIONS,
SORTING AN ARRAY OF STRINGS (RADIX SORT)
Introduction
Length: The number of characters in a string is called its length. The function length(s) returns the length
of strings.
Concatenation: Concatenation combines the characters of two strings. For example, concatenation of
string s1 with string s2 results in a string containing characters of s1 followed by those of s2. Note that
string terminator of s1 is replaced by the first character of s2, but string terminator of s2 is retained.
Substring: Accessing a substring from a given string requires three pieces of information:
a) The name of the string itself, (s)
b) the position of the first character of the substring in the given string (ip)
c) the length of the substring or the position of the last character of the substring. (len)
The function substring (s, ip, len) denotes the substring of a string s beginning in a position ip and having
a length len.
Index: The function index(T, P) is used to find the position where a string pattern P first appears in a
given string text T. This is called pattern matching.
Algorithm A1: length(s)
1. Initialize len to 0.
2. Set a variable to the beginning index of string s.
3. Repeat the following step till the string terminator is encountered.
4. len = len +1
5. Exit
Algorithm A2: concatenate (s1, s2)
1. Initialize i = strlen(s1)
2. Initialize j = strlen(s2)
3. Initialize count =0;
/ * This segment copies characters of s2 into array s1 * /
4. Repeat steps 5 to 7 while count <= j
5. s1[i] = s2[count]
6. i = i + 1
7. count = count + 1
8. Exit
Algorithm A3: substring (s, ip, len)
1. Initialize i = ip and count = 0
2. Use an array “dest‟ to hold the required substring

Data Structure and Algorithms (Lab Manual) Page 12


Department of Electrical Engineering, FEST, Indus University, Karachi

3. Repeat steps 4 ,5 and 6 while count < len


4. dest[count] = s[i]
5. count = count +1
6. i = i + 1
7. Insert string terminator at end of dest
8. Exit
Algorithm A4: index(t, p) / * t and p are respectively lengths of strings T and P * /
1. Initialize i = 0 and max = t – p + 1
2. Repeat steps 3 to 6 while i < max
3. Repeat for j = 0 to p – 1
4. If P[j] ≠ T[i+j] then goto step 6
5. Return index i and exit
6. i = i + 1
7. Return –1 for no match
8. Exit
Radix Sort is a clever and intuitive little sorting algorithm. Radix Sort puts the elements in order by
comparing the digits of the numbers
Radix Sort: Following is a simple C++ implementation of Radix Sort.

// C++ implementation of Radix Sort


#include<iostream>
using namespace std;
// A utility function to get maximum value in arr[]
int getMax(int arr[], int n)
{
int mx = arr[0];
for (int i = 1; i < n; i++)
if (arr[i] > mx)
mx = arr[i];
return mx;
}
// A function to do counting sort of arr[] according to
// the digit represented by exp.
void countSort(int arr[], int n, int exp)
{

Data Structure and Algorithms (Lab Manual) Page 13


Department of Electrical Engineering, FEST, Indus University, Karachi

int output[n]; // output array


int i, count[10] = {0};
// Store count of occurrences in count[]
for (i = 0; i < n; i++)
count[ (arr[i]/exp)%10 ]++;
// Change count[i] so that count[i] now contains actual position of
// this digit in output[]
for (i = 1; i < 10; i++)
count[i] += count[i - 1];
// Build the output array
for (i = n - 1; i >= 0; i--)
{
output[count[ (arr[i]/exp)%10 ] - 1] = arr[i];
count[ (arr[i]/exp)%10 ]--;
}
// Copy the output array to arr[], so that arr[] now
// contains sorted numbers according to curent digit
for (i = 0; i < n; i++)
arr[i] = output[i];
}
// The main function to that sorts arr[] of size n using Radix Sort
void radixsort(int arr[], int n)
{
// Find the maximum number to know number of
digits int m = getMax(arr, n);
// Do counting sort for every digit. Note that instead of passing digit
// number, exp is passed. exp is 10^i where i is current digit number
for (int exp = 1; m/exp > 0; exp *= 10)
countSort(arr, n, exp);
}
// A utility function to print an array
void print(int arr[], int n)

Data Structure and Algorithms (Lab Manual) Page 14


Department of Electrical Engineering, FEST, Indus University, Karachi

{
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
}
// Driver program to test above functions
int main()
{
int arr[] = {170, 45, 75, 90, 802, 24, 2, 66};
int n = sizeof(arr)/sizeof(arr[0]);
radixsort(arr, n);
print(arr, n);
return 0;
}

Lab Tasks
Q1. Implement the above algorithms in C/C++.
Q2. Design an algorithm that takes a string S and a char ‘a’ as input. It then displays the all
occurrences of a in S.

Data Structure and Algorithms (Lab Manual) Page 15


Department of Electrical Engineering, FEST, Indus University, Karachi

EXPERIMENT # 6
TO STUDY THE CONCEPT OF LINK LIST AND OPERATIONS (TRAVERSAL,
INSERTION, DELETION)
Introduction: A linked list or one way list is a linear collection of data elements, called nodes, where the
linear order is given by means of “pointers”. Each node is divided into two parts.
The first part contains the information of the element / node.
The second part called the link field contains the address of the next node in the list.

Example:

Description: Here LIST is a structure has two members (Info and Next), where Info is used to store the
data and Next is a pointer used to hold the address of next node. HEAD is a pointer to LIST, points to the
beginning/first element of the LIST. ITEM is the value needed to insert or delete in/from the LIST. The
initial value of the HEAD is NULL, it means that initially LIST is empty. New Node is pointer variable
which holds the address of newly created LIST node.
Operations on Linked List:
a) Creation of Link List
b) Traversing Linked List.
c) Searching in Linked List.
d) Insertion in Linked List
e) Deletion from Linked List
Algorithm to Linked List Creation
Algorithm: (ITEM), [ Here the initial value of FRONT & REAR are NULL ]
Step 1. Create dynamic NODE to store (Info and Next) for next node and store its address into NewNode
pointer [Insert ITEM in newly created Node for QUEUE.]
Step 2. Set NewNode -> Info = ITEM and NewNode -> Next = NULL
Step 3. If REAR = NULL then:
Set REAR and FRONT both = NewNode [ First Node Enqueued ]
Else
Set REAR -> Next = NewNode
Set REAR = NewNode
[ End of If Structure ]
Step 4. End.

Data Structure and Algorithms (Lab Manual) Page 16


Department of Electrical Engineering, FEST, Indus University, Karachi
Algorithm: (Traversing a Linked List) Let LIST be a linked list in memory. This
algorithm traverses LIST, applying an operation PROCESS to each Node / element of the LIST. HEAD
points to the first node of the LIST. Pointer variable CURR point to the node currently being processed.
Step 1. Set CURR = HEAD. [Initializes pointer CURR.]
Step 2. Repeat Steps 3 and 4 while CURR ≠ NULL.
Step 3. Apply PROCESS to CURR -> INFO.
Step 4. Set CURR = CURR -> NEXT [CURR now points to the next node.]
[End of Step-2 loop.]
Step 5. End
Algorithm: INSERT( ITEM)
NOTE: Here it is needed that all the time, LIST should remains in the sorted order using Info part of the
Node. To Insert / Enqueue a new node in the LIST, first LIST will be searched (using Info of Nodes) to
find its LOCATION ( where to insert new Node). This exercise makes it possible that every new node
has the probability to insert at the beginning, in the middle or at the end of LIST. CURR is a pointer
points to the node currently being processed and PREV is a pointer pointing to previous node of the
current node. [This algorithm adds NewNodes at any position (Top, in Middle OR at End) in the List ]
Step 1. Create NewNode node for LIST in memory
Step 2. Set NewNode -> Info =ITEM. [Copies new data into INFO of new node.]
Step 3. NewNode -> Next = NULL. [Copies NULL in NEXT of new node.].
Step 4. If HEAD = NULL then: [ Condition to create the Linked List. ]
HEAD=NewNode and return. [Add first node in
list] [Add on top of existing list]
Step 6. If NewNode-> Info < HEAD ->Info then:
Set NewNode->NEXT = HEAD and HEAD = NewNode and return
[Search the LOCATION in Middle or at end. ] [ Here CURR is the position where to insert and PREV
points to previous node of the CURR node ]
Step 7. Set Prev = NULL and Set Curr = NULL;
Step 8. Repeat for CURR =HEAD until CURR ≠ NULL after iteration CURR = CURR ->Next
if(NewNode->Info <= CURR ->Info) then: break the loop
Set PREV = CURR;
[ end of loop of step-7 ]
[Insert after PREV node (in middle or at end) of the list]
Step 9. Set NewNode->NEXT = PREV ->NEXT and
Step 10. Set PREV ->NEXT= NewNode.
Step 11. Exit.

Data Structure and Algorithms (Lab Manual) Page 17


Department of Electrical Engineering, FEST, Indus University, Karachi

Lab Task
Q1. Convert all above algorithm in C++ programming language.
Q2. Write an algorithm that creates a Link List in sorted manner.
Q3. Describe the key differences between arrays and linked list.

Data Structure and Algorithms (Lab Manual) Page 18


Department of Electrical Engineering, FEST, Indus University, Karachi
\

EXPERIMENT # 7
TO STUDY AND ANALYZE DOUBLE LINKED LIST (TRAVERSAL,
INSERTION AND DELETION)
Introduction: Different from a singly linked list, a doubly linked list allows us to go in both directions --
forward and reverse. Such lists allow for a great variety of quick update operations, including insertion
and removal at both ends, and in the middle. A node in a doubly linked list stores two references -- a next
link, which points to the next node in the list, and a prev link, which points to the previous node in the
list.

It is usually convenient to add special nodes at both ends of a doubly linked list, a header node just
before the head of the list, and a trailer node just after the tail of the list. These dummy or sentinel nodes
do not store any elements. The header has a valid next reference by a null prev reference, while the trailer
has a valid prev reference by a null next reference. A linked list object would simply need to store
references to these two sentinels and a size counter that keeps track of the number of elements (not
counting sentinels) in the list
Insertion and Deletion Methods

Algorithm: INSERT( ITEM)


NOTE: Here it is needed that all the time, LIST should remains in the sorted order using Info part of the
Node. To Insert / Enqueue a new node in the LIST, first LIST will be searched (using Info of Nodes) to
find its LOCATION ( where to insert new Node). This exercise makes it possible that every new node
has the probability to insert at the beginning, in the middle or at the end of LIST.
CURR is a pointer points to the node currently being processed and PREV is a pointer pointing to
previous node of the current node.
[This algorithm adds NewNodes at any position (Top, in Middle OR at End) in the List ]

Data Structure and Algorithms (Lab Manual) Page 19


Department of Electrical Engineering, FEST, Indus University, Karachi
Step 1. Create a NewNode node for LIST in memory
Step 2. Set NewNode -> Info =ITEM. [Copies new data into INFO of new node.]
Step 3. Set NewNode -> Next = NULL. [Copies NULL in NEXT of new node.].
Step 4. If HEAD = NULL then: [ Condition to create the Linked List. ]
Step 5 HEAD=NewNode and return. [Add first node in list]
[Add on top of existing list]
Step 6. If NewNode-> Info < HEAD ->Info then:
Set NewNode->NEXT = HEAD and HEAD = NewNode and return
[Search the LOCATION in Middle or at end. ]
[ Here CURR is the position where to insert and PREV points to previous node of the CURR node ]
Step 7. Set Prev = NULL and Set Curr = NULL;
Step 8. Repeat for CURR =HEAD until CURR ≠ NULL after iteration CURR = CURR ->Next
c) if(NewNode->Info <= CURR ->Info) then: break the loop
d) Set PREV = CURR;
[ end of loop of step-7 ]
[Insert after PREV node (in middle or at end) of the list]
Step 9. Set NewNode->NEXT = PREV ->NEXT and
Step 10. Set PREV ->NEXT= NewNode.
Step 11. Exit.

Lab Task:
Q1. Convert all above algorithm in C/ C++ programming language.
Q2. Write an algorithm for searching, sorting and traversing in circular linked list.

Data Structure and Algorithms (Lab Manual) Page 20


Department of Electrical Engineering, FEST, Indus University, Karachi

EXPERIMENT # 8
TO UNDERSTAND THE CONCEPTS OF STACKS & QUEUES, ASSOCIATED
OPERATIONS, IMPLEMENTATION OF STACKS AND QUEUES
Introduction: Stack is an abstract data type with a bounded(predefined) capacity. It is a simple data
structure that allows adding and removing elements in a particular order. Every time an element is added,
it goes on the top of the stack; the only element that can be removed is the element that was at the top of
the stack, just like a pile of objects.

Basic features of Stack

1. Stack is an ordered list of similar data type.


2. Stack is a LIFO structure. (Last in First out).
3. push() function is used to insert new elements into the Stack and pop() is used to delete an element
from the stack. Both insertion and deletion are allowed at only one end of Stack called Top.
4. Stack is said to be in Overflow state when it is completely full and is said to be in Underflow state
if it is completely empty.

Applications of Stack
The simplest application of a stack is to reverse a word. You push a given word to stack - letter by letter -
and then pop letters from the stack.

There are other uses also like : Parsing, Expression Conversion(Infix to Postfix, Postfix to Prefix etc)
and many more.

Data Structure and Algorithms (Lab Manual) Page 21


Department of Electrical Engineering, FEST, Indus University, Karachi

Implementation of Stack
Stack can be easily implemented using an Array or a Linked List. Arrays are quick, but are limited in size
and Linked List requires overhead to allocate, link, unlink, and de allocate, but is not limited in size. Here
we will implement Stack using array.

Queue is also an abstract data type or a linear data structure, in which the first element is inserted from
one end called REAR(also called tail), and the deletion of exisiting element takes place from the other
end called as FRONT(also called head). This makes queue as FIFO data structure, which means that
element inserted first will also be removed first.
The process to add an element into queue is called Enqueue and the process of removal of an element
from queue is called Dequeue
Basic features of Queue
1. Like Stack, Queue is also an ordered list of elements of similar data types.
2. Queue is a FIFO( First in First Out ) structure.
3. Once a new element is inserted into the Queue, all the elements inserted before the new element in the
queue must be removed, to remove the new element.
4. peek( ) function is oftenly used to return the value of first element without dequeuing it.

Applications of Queue
Queue, as the name suggests is used whenever we need to have any group of objects in an order in which
the first one coming in, also gets out first while the others wait for there turn, like in the following
scenarios :

Data Structure and Algorithms (Lab Manual) Page 22


Department of Electrical Engineering, FEST, Indus University, Karachi
1. Serving requests on a single shared resource, like a printer, CPU task scheduling etc.
2. In real life, Call Center phone systems will use Queues, to hold people calling them in an order, until a
service representative is free.
3. Handling of interrupts in real-time systems. The interrupts are handled in the same order as
they arrive, First come first served.

Implementation of Queue
Queue can be implemented using an Array, Stack or Linked List. The easiest way of implementing a
queue is by using an Array. Initially the head (FRONT) and the tail(REAR) of the queue points at the
first index of the array (starting the index of array from 0). As we add elements to the queue, the tail
keeps on moving ahead, always pointing to the position where the next element will be inserted, while the
head remains at the first index.
When we remove element from Queue, we can follow two possible approaches we remove the element
at head position, and then one by one move all the other elements on position forward we remove the
element from head position and then move head to the next position.
there is an overhead of shifting the elements one position forward every time we remove the first element
there is no such overhead, but when we move head one position ahead, after removal of first element, the
size on Queue is reduced by one space each time.

Lab Task:
Q1. Implement the Queue and Stack using Array and Link list.
Q2. What are the major differences between Stack and Queue?

Data Structure and Algorithms (Lab Manual) Page 23


Department of Electrical Engineering, FEST, Indus University, Karachi

EXPERIMENT # 9
TO STUDY THE RECURSIVE ALGORITHMS AND APPLICATIONS

Introduction Recursion is an important concept in computer science. Many algorithms can be best
described in terms of recursion. Recursion is the name for the case when a procedure P invokes itself or
invokes a series of other procedures that eventually invokes the procedure P again. Then P is called a
recursive procedure. In order to make sure that program will not continue to run indefinitely, a recursive
procedure must have the following two properties:
1. There must be certain criteria, called „base criteria‟, for which the procedure does not call itself.
2. Each time the procedure does call itself (directly or indirectly), it must be closer to the baser
criteria. A recursive procedure with these two properties is said to be „well-defined‟.
Factorial Function The product of the positive integers from 1 to n, inclusive, is called n factorial and
is usually denoted by n!
n! = 1 x 2 x 3 x . . . (n – 2) x (n – 1) x n
We know that 0! = 1.For every positive integer n; n! = n x (n – 1)!
Accordingly, the factorial function may also be defined as follows:
a) If n = 0, then n! = 1.
b) If n > 0, then n! = n x (n – 1)!
Obviously this definition is recursive, since it refers to itself when it uses (n –1)!. However, (a) the value
of n! is explicitly given when n = 0 (thus 0 is the base value); and (b) the value of n! for arbitrary n is
defined in terms of a smaller value of n which is closer to the base value 0. Accordingly, the definition is
not circular, or in other words, the procedure is well defined.
Suppose P is a recursive procedure. During the running of an algorithm or a program that contains P, we
associate a level number with each given execution of procedure P as follows. The original execution of
procedure P is assigned level 1; and each time procedure P is executed because of a recursive call, its
level is 1 more than the level of the execution that has made the recursive call. The depth of recursion of a
recursive procedure P with a given set of arguments refers to the maximum level number of P during its
execution.
Algorithm
This algorithm calculates n! and returns the value in the variable FACT.
Algorithm: FACTORIAL(FACT, n)
1. if (n = = 0) then set FACT = 1 and return.
2. FACT = n x FACTORIAL(FACT, n –1 )
3. Return.
Lab Task
a) This exercise will demonstrate how recursion can simplify solution of some complicated problems. It
addresses the problem of making combinations of a certain size out of a total group of elements. For
example, if we have twenty different books to pass out to four students, we can easily see that - to be
equitable - we should give each student five books. But how many combinations of five books can be
made out of a group of twenty books?There is a mathematical formula to solve this problem. Given that C
is the total number of combinations, Group is the total size of the group to pick from, Members is the size
of each subgroup, and Group > = Members,
C(Group,Members)=

Data Structure and Algorithms (Lab Manual) Page 24


Department of Electrical Engineering, FEST, Indus University, Karachi
Lab Task:
a) Find C (4, 3).
b) Find C (6, 4) and record your observations.
c) Implement in C, the recursive solution for factorial. Demonstrate its use in a program.
d) Design the iterative solution for factorial
e) Design an algorithm for the problem Towers of Hanoi and implement the recursive solution
in C++.

Data Structure and Algorithms (Lab Manual) Page 25


Department of Electrical Engineering, FEST, Indus University, Karachi

EXPERIMENT # 10
TO UNDERSTAND A TREE, CONVERTING A BINARY SEARCH TREE TO
SORTED DOUBLY LINK LIST
Introduction: Trees are one of the most important data structures in computer science. They come in
many forms. They provide natural representations for many kinds of data that occur in applications, and
they are useful for solving a wide variety of algorithmic problems.
A tree is a collection of elements called nodes, one of which is distinguished as a root, with a relation
(“parenthood”) that places a hierarchical structure on the nodes. A node, like an element of a list, can be
of whatever type we wish.
A structure with a unique starting node (the root), in which each node is capable of having at most two
child nodes, and in which a unique path exists from the root to every other node is called a binary tree.
A root

B C

D E F

G H I J

A binary tree has a natural implementation in linked storage. In the implementation to follow, the pointer
variable root points to the root of the tree. With this pointer variable, it is easy to recognize an empty
binary tree as precisely the condition root = NULL, and to create a new, empty binary tree we need only
assign its root pointer to NULL.
One of the most important operations on a binary tree is traversal, moving through all the nodes of the
binary tree, visiting each one in turn. As for traversal of other data structures, the action we shall take
when we visit each node will depend on the application. For lists, the nodes come in a natural order from
first to last, and traversal follows the same order. For trees, however, there are many different orders in
which we can traverse all the nodes. Let V, L and R respectively represent visiting root, traversing left
subtree, and traversing right subtree. There are three standard traversal orders.
One of the most important operations on a binary tree is traversal, moving through all the nodes of the
binary tree, visiting each one in turn. As for traversal of other data structures, the action we shall take
when we visit each node will depend on the application. For lists, the nodes come in a natural order from
first to last, and traversal follows the same order. For trees, however, there are many different orders in
which we can traverse all the nodes. Let V, L and R respectively represent visiting root, traversing left
subtree, and traversing right subtree.
There are three standard traversal orders.

Data Structure and Algorithms (Lab Manual) Page 26


Department of Electrical Engineering, FEST, Indus University, Karachi
Given a Binary Tree (BT), convert it to a Doubly Linked List(DLL). The left and right pointers in nodes
are to be used as previous and next pointers respectively in converted DLL. The order of nodes in DLL
must be same as In order of the given Binary Tree. The first node of In order traversal (left most node in
BT) must be head node of the DLL.

A solution to this problem is discussed in this post.


In this post, another simple and efficient solution is discussed. The solution discussed here has two
simple steps.
1) Fix Left Pointers: In this step, we change left pointers to point to previous nodes in DLL. The idea is
simple, we do inorder traversal of tree. In inorder traversal, we keep track of previous visited node and
change left pointer to the previous node. See fixPrevPtr() in below implementation.
2) Fix Right Pointers: The above is intuitive and simple. How to change right pointers to point to next
node in DLL? The idea is to use left pointers fixed in step 1. We start from the rightmost node in Binary
Tree (BT). The rightmost node is the last node in DLL. Since left pointers are changed to point to
previous node in DLL, we can linearly traverse the complete DLL using these pointers. The traversal
would be from last to first node. While traversing the DLL, we keep track of the previously visited node
and change the right pointer to the previous node. See fixNextPtr() in below implementation.
Lab Task:
Q1. Implement the code of converting Binary search tree to sorted doubly linked list.

Data Structure and Algorithms (Lab Manual) Page 27


Department of Electrical Engineering, FEST, Indus University, Karachi

EXPERIMENT # 11
TO ANALYZE TREE TRAVERSAL (IN-ORDER, PRE-ORDER AND POST-ORDER), BREADTH-
FIRST SEARCH AND DEPTH-FIRST SEARCH ALGORITHM

Introduction: Traverse means to visit the vertices in some systematic order. You should be familiar with
various traversal methods for trees:
Preorder: visit each node before its children.
Post order: visit each node after its children.
In order (for binary trees only): visit left sub tree, node, right sub tree.
Code for Tree Traversal (In-order, Pre-order ,Post-order )
#include <iostream>
using namespace std;
// Node class
class Node {
int key;
Node* left;
Node* right;
public:
Node() { key=-1; left=NULL; right=NULL;
}; void setKey(int aKey) { key = aKey; };
void setLeft(Node* aLeft) { left = aLeft; };
void setRight(Node* aRight) { right = aRight; };
int Key() { return key; };
Node* Left() { return left; };
Node* Right() { return right; };
};
// Tree class
class Tree {
Node* root;
public:
Tree();
~Tree();

Data Structure and Algorithms (Lab Manual) Page 28


Department of Electrical Engineering, FEST, Indus University, Karachi

Node* Root() { return root; };


void addNode(int key);
void inOrder(Node* n);
void preOrder(Node* n);
void postOrder(Node* n);
private:
void addNode(int key, Node* leaf);
void freeNode(Node* leaf);
};
// Constructor
Tree::Tree() {
root = NULL;
}
// Destructor
Tree::~Tree() {
freeNode(root);
}
// Free the node
void Tree::freeNode(Node* leaf)
{
if ( leaf != NULL )
{
freeNode(leaf->Left());
freeNode(leaf->Right());
delete leaf;
}
}
// Add a node
void Tree::addNode(int key) {
// No elements. Add the root
if ( root == NULL ) {
cout << "add root node ... " << key << endl;
Node* n = new Node();
n->setKey(key);
root = n;

Data Structure and Algorithms (Lab Manual) Page 29


Department of Electrical Engineering, FEST, Indus University, Karachi

}
else {
cout << "add other node ... " << key << endl;
addNode(key, root);
}
}
// Add a node (private)
void Tree::addNode(int key, Node* leaf)
{ if ( key <= leaf->Key() ) {
if ( leaf->Left() != NULL )
addNode(key, leaf->Left());
else {
Node* n = new Node();
n->setKey(key); leaf-
>setLeft(n);
}
}
else {
if ( leaf->Right() != NULL )
addNode(key, leaf->Right());
else {
Node* n = new Node();
n->setKey(key); leaf-
>setRight(n);
}
}
}
// Print the tree in-order
// Traverse the left sub-tree, root, right sub-tree
void Tree::inOrder(Node* n) {
if ( n ) { inOrder(n-
>Left());
cout << n->Key() << " ";
inOrder(n->Right());
}

Data Structure and Algorithms (Lab Manual) Page 30


Department of Electrical Engineering, FEST, Indus University, Karachi

}
// Print the tree pre-order
// Traverse the root, left sub-tree, right sub-tree
void Tree::preOrder(Node* n) {
if ( n ) {
cout << n->Key() << " ";
preOrder(n->Left());
preOrder(n->Right());
}
}
// Print the tree post-order
// Traverse left sub-tree, right sub-tree, root
void Tree::postOrder(Node* n) {
if ( n ) { postOrder(n-
>Left()); postOrder(n-
>Right()); cout << n-
>Key() << " ";
}
}
// Test main program
int main() {
Tree* tree = new Tree();
tree->addNode(30);
tree->addNode(10);
tree->addNode(20);
tree->addNode(40);
tree->addNode(50);
cout << "In order traversal" <<
endl; tree->inOrder(tree->Root());
cout << endl;
cout << "Pre order traversal" << endl;
tree->preOrder(tree->Root());
cout << endl;
cout << "Post order traversal" << endl;
tree->postOrder(tree->Root());

Data Structure and Algorithms (Lab Manual) Page 31


Department of Electrical Engineering, FEST, Indus University, Karachi

cout << endl;


delete tree;
return 0;
}

We also saw another kind of traversal, topological ordering,. we'll see two other traversals: breadth first
search (BFS) and depth first search (DFS). Both of these construct spanning trees with certain properties
useful in other graph algorithms. We'll start by describing them in undirected graphs, but they are both also
very useful for directed graphs.
Breadth First Search
This can be throught of as being like Dijkstra's algorithm for shortest paths, but with every edge having the
same length. However it is a lot simpler and doesn't need any data structures. We just keep a tree (the
breadth first search tree), a list of nodes to be added to the tree, and markings (Boolean variables) on the
vertices to tell whether they are in the tree or list.
breadth first search:
unmark all vertices
choose some starting vertex x
mark x
list L = x
tree T = x
while L nonempty
choose some vertex v from front of list
visit v
for each unmarked neighbor w
mark w
add it to end of list
add edge vw to T
It's very important that you remove vertices from the other end of the list than the one you add them to, so
that the list acts as a queue (fifo storage) rather than a stack (lifo). The "visit v" step would be filled out later
depending on what you are using BFS for, just like the tree traversals usually involve doing something at
each vertex that is not specified as part of the basic algorithm. If a vertex has several unmarked neighbors, it
would be equally correct to visit them in any order. Probably the easiest method to implement would be
simply to visit them in the order the adjacency list for v is stored in.
Let's prove some basic facts about this algorithm. First, each vertex is clearly marked at most once,
added to the list at most once (since that happens only when it's marked), and therefore removed from the
list at most once. Since the time to process a vertex is proportional to the length of its adjacency list, the total
time for the whole algorithm is O(m).
Next, let's look at the tree T constructed by the algorithm. Why is it a tree? If you think of each
edge vw as pointing "upward" from w to v, then each edge points from a vertex visited later to one visited
earlier. Following successive edges upwards can only get stopped at x (which has no edge going upward

Data Structure and Algorithms (Lab Manual) Page 32


Department of Electrical Engineering, FEST, Indus University, Karachi

from it) so every vertex in T has a path to x. This means that T is at least a connected subgraph of G. Now
let's prove that it's a tree. A tree is just a connected and acyclic graph, so we need only to show that T has
no cycles. In any cycle, no matter how you orient the edges so that one direction is "upward" and the other
"downward", there is always a "bottom" vertex having two upward edges out of it. But in T, each vertex has
at most one upward edge, so T can have no cycles. Therefore T really is a tree. It is known as a breadth first
search tree.
We also want to know that T is a spanning tree, i.e. that if the graph is connected (every vertex has some path
to the root x) then every vertex will occur somewhere in T. We can prove this by induction on the length of
the shortest path to x. If v has a path of length k, starting v-w-...-x, then w has a path of length k-1, and by
induction would be included in T. But then when we visited w we would have seen edge vw, and if v were
not already in the tree it would have been added.
Breadth first traversal of G corresponds to some kind of tree traversal on T. But it isn't preorder, postorder, or
even inorder traversal. Instead, the traversal goes a level at a time, left to right within a level (where a level is
defined simply in terms of distance from the root of the tree). For instance, the following tree is drawn with
vertices numbered in an order that might be followed by breadth first search:

1
/|\
234/\
|
567|/|\
8 9 10 11

The proof that vertices are in this order by breadth first search goes by induction on the level number. By the
induction hypothesis, BFS lists all vertices at level k-1 before those at level k. Therefore it will place into L
all vertices at level k before all those of level k+1, and therefore so list those of level k before those of level
k+1. (This really is a proof even though it sounds like circular reasoning.)
Breadth first search trees have a nice property: Every edge of G can be classified into one of three groups.
Some edges are in T themselves. Some connect two vertices at the same level of T. And the remaining ones
connect two vertices on two adjacent levels. It is not possible for an edge to skip a level.
Therefore, the breadth first search tree really is a shortest path tree starting from its root. Every vertex has a
path to the root, with path length equal to its level (just follow the tree itself), and no path can skip a level
so this really is a shortest path.
Breadth first search has several uses in other graph algorithms, but most are too complicated to explain in
detail here. One is as part of an algorithm for matching, which is a problem in which you want to pair up the
n vertices of a graph by n/2 edges. If you have a partial matching, pairing up only some of the vertices, you
can extend it by finding an alternating path connecting two unmatched vertices; this is a path in which every
other edge is part of the partial matching. If you remove those edges in the path from the matching, and add
the other path edges back into the matching, you get a matching with one more edge. Alternating paths can
be found using a version of breadth first search.
A second use of breadth first search arises in certain pattern matching problems. For instance, if you're
looking for a small subgraph such as a triangle as part of a larger graph, you know that every vertex in the
triangle has to be connected by an edge to every other vertex. Since no edge can skip levels in the BFS tree,
you can divide the problem into subproblems, in which you look for the triangle in pairs of adjacent levels of
the tree. This sort of problem, in which you look for a small graph as part of a larger one, is known as sub

Data Structure and Algorithms (Lab Manual) Page 33


Department of Electrical Engineering, FEST, Indus University, Karachi

graph isomorphism. In a recent paper, I used this idea to solve many similar pattern-matching problems in
linear time.
Depth first search
Depth first search is another way of traversing graphs, which is closely related to preorder traversal of a tree.
Recall that preorder traversal simply visits each node before its children. It is most easy to program as a
recursive routine:
preorder(node v)
{
visit(v);
for each child w of v
preorder(w);
}
To turn this into a graph traversal algorithm, we basically replace "child" by "neighbor". But to prevent
infinite loops, we only want to visit each vertex once. Just like in BFS we can use marks to keep track of the
vertices that have already been visited, and not visit them again. Also, just like in BFS, we can use this search
to build a spanning tree with certain useful properties.
dfs(vertex v)
{
visit(v);
for each neighbor w of v
if w is unvisited
{
dfs(w);
add edge vw to tree T
}
}
The overall depth first search algorithm then simply initializes a set of markers so we can tell which vertices
are visited, chooses a starting vertex x, initializes tree T to x, and calls dfs(x). Just like in breadth first
search, if a vertex has several neighbors it would be equally correct to go through them in any order. I didn't
simply say "for each unvisited neighbor of v" because it is very important to delay the test for whether a
vertex is visited until the recursive calls for previous neighbors are finished.
The proof that this produces a spanning tree (the depth first search tree) is essentially the same as that for
BFS, so I won't repeat it. However while the BFS tree is typically "short and bushy", the DFS tree is typically
"long and stringy".
Just like we did for BFS, we can use DFS to classify the edges of G into types. Either an edge vw is in the
DFS tree itself, v is an ancestor of w, or w is an ancestor of v. (These last two cases should be thought of as a
single type, since they only differ by what order we look at the vertices in.) What this means is that if v and w
are in different subtrees of v, we can't have an edge from v to w. This is because if such an edge existed and
(say) v were visited first, then the only way we would avoid adding vw to the DFS tree would be if w were
visited during one of the recursive calls from v, but then v would be an ancestor of w.

Data Structure and Algorithms (Lab Manual) Page 34


Department of Electrical Engineering, FEST, Indus University, Karachi

As an example of why this property might be useful, let's prove the following fact: in any graph G, either
G has some path of length at least k. or G has O(kn) edges.
Proof: look at the longest path in the DFS tree. If it has length at least k, we're done. Otherwise, since each
edge connects an ancestor and a descendant, we can bound the number of edges by counting the total number
of ancestors of each descendant, but if the longest path is shorter than k, each descendant has at most k-1
ancestors. So there can be at most (k-1)n edges.

Lab Task:
Q1. Write a C++ program for Breadth search algorithm and Depth Search algorithm for tree.

Data Structure and Algorithms (Lab Manual) Page 35


Department of Electrical Engineering, FEST, Indus University, Karachi

EXPERIMENT # 12
TO UNDERSTAND THE GRAPH (IMPLEMENTATION, TRAVERSAL AND
SHORTEST PATH ALGORITHM)
Introduction: A set of items connected by edges. Each item is called a vertex or node. Formally, a
graph is a set of vertices and a binary relation between vertices, adjacency.
A graph is a structure consisting of a set of arrays (also called dimensions) \{v_1, v_2,\dots,v_n\} and a
set of edges \{e_1, e_2,\dots,e_m\}. An edge is a pair of vertices \{v_i, v_j\}\ i,j \in \{1..n\}. The two
vertices are called the edge endpoints. Graphs are ubiquitous in computer science. They are used to model
real-world systems such as the Internet (each node represents a router and each edge represents a
connection between routers); airline connections (each node is an airport and each edge is a flight); or a
city road network (each node represents an intersection and each edge represents a block). The wireframe
drawings in computer graphics are another example of graphs.
A graph may be either undirected or directed. Intuitively, an undirected edge models a "two-way" or
"duplex" connection between its endpoints, while a directed edge is a one-way connection, and is
typically drawn as an arrow. A directed edge is often called an arc. Mathematically, an undirected edge is
an unordered pair of vertices, and an arc is an ordered pair. For example, a road network might be
modeled as a directed graph, with one-way streets indicated by an arrow between endpoints in the
appropriate direction, and two-way streets shown by a pair of parallel directed edges going both
directions between the endpoints. You might ask, why not use a single undirected edge for a two-way
street. There's no theoretical problem with this, but from a practical programming standpoint, it's
generally simpler and less error-prone to stick with all directed or all undirected edges.
Shortest path algorithm
Dijkstra's algorithm, named after its discoverer, Dutch computer scientist Edsger Dijkstra, is a greedy
algorithm that solves the single-source shortest path problem for a directed graph with non negative edge
weights. For example, if the vertices (nodes) of the graph represent cities and edge weights represent
driving distances between pairs of cities connected by a direct road, Dijkstra's algorithm can be used to
find the shortest route between two cities. Also, this algorithm can be used for shortest path to destination
in traffic network.

Dijkstra‟s algorithm
Step 1 Label the start vertex as 0.
Step 2 Box this number (permanent label).
Step 3 Label each vertex that is connected to the start vertex with its distance (temporary label).
Step 4 Box the smallest number.
Step 5 From this vertex, consider the distance to each connected vertex.
Step 6 If a distance is less than a distance already at this vertex, cross out this distance and write in the
new distance. If there was no distance at the vertex, write down the new distance.
Step 7 Repeat from step 4 until the destination vertex is
boxed.

Data Structure and Algorithms (Lab Manual) Page 36


Department of Electrical Engineering, FEST, Indus University, Karachi

Note: When a vertex is boxed you do not reconsider it. You need
to show all temporary labels together with their crossings out.
Lab Task:
1. Implement the Dijkstra's algorithm using C or C++.

Data Structure and Algorithms (Lab Manual) Page 37

Potrebbero piacerti anche