Data Structures & Algorithms - NED University

64 downloads 2741 Views 1MB Size Report
Data Structures and Algorithms. ___ Lab Session 01. NED University of Engineering & Technology – Department of Computer & Information Systems ...
Practical Workbook DATA STRUCTURES AND ALGORITHMS

Name

: ________________________

Year

: ________________________

Batch

: ________________________

Roll No

: ________________________

Department: ________________________

1st edition: 2011

Department of Computer & Information Systems Engineering NED University of Engineering & Technology,

Karachi – 75270, Pakistan

INTRODUCTION Writing computer programs entails the study of how information is organized in a computer, how it can be manipulated, and how it can be utilized. Thus, it is exceedingly important for a student of computer engineering to understand the concepts of information organization and manipulation in order to pursue advanced courses in this discipline. This is what the field of data structures is all about.

Even with very large projects, difficulties usually arise not from the inability to find a solution but, rather, from the fact that there can be so many different methods and algorithms that might work that it can be hard to decide which is best, which may lead to programming difficulties, or which may be hopelessly inefficient. The greatest room for variability in algorithm design is generally in the way in which the data of the program are stored: how they are arranged in relation to each other.

The goal of this workbook, therefore, is to present elegant, yet fundamentally simple ideas for the organization and manipulation of data. It will supplement the concepts discussed in theory classes of the course Data Structures and Algorithms.

CONTENTS Lab Session No.

Object

Page No.

1.

Implementation of the following string processing functions: * length * concatenation * substring * index

1

2.

Implementation of the following word processing functions using the string processing functions length, index, substring and concatenation developed in lab session 1: * insert * delete

7

3.

Implementation of the algorithm for matrix multiplication using two dimensional arrays.

11

4.

Storage of a two-dimensional sparse matrix in a uni-dimensional array.

14

5.

Application of the binary search on a list of elements stored in an array.

18

6.

Application of insertion and shell sorting algorithms on a list of elements stored in an array.

21

7.

Implementation of stack operations.

26

8.

Usage of stack for processing arithmetic expressions.

31

9.

Understanding principles of recursive programming.

36

10.

Implementation of queue operations.

40

11.

Design and implementation of linked list algorithms.

45

12.

Understanding binary trees and development of algorithms to incorporate them in various applications.

50

13.

Implementation of search through a linked binary search tree.

57

14.

Analysis of methods of graph representations and construction of graph traversal algorithms.

63

15.

Development of an algorithm for the game of Life.

69

Data Structures and Algorithms

___

Lab Session 01

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

Lab Session 01 OBJECT Implementation of the following string processing functions: * length * concatenation * substring * index

THEORY 

length

The number of characters in a string is called its length. The function length(s) returns the length of string s. 

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, b) the position of the first character of the substring in the given string and c) the length of the substring or the position of the last character of the substring. 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.

ALGORITHMS Algorithm A1: length(s) 1. 2. 3. 4. 5.

Initialize len to 0. Set a variable to the beginning index of string s. Repeat the following step till the string terminator is encountered. len = len +1 Exit 1

Data Structures and Algorithms

___

Lab Session 01

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

Algorithm A2: concatenate (s1, s2) 1. 2. 3. 4. 5. 6. 7. 8.

Initialize i = strlen(s1) Initialize j = strlen(s2) Initialize count =0; / * This segment copies characters of s2 into array s1 * / Repeat steps 5 to 7 while count j, A[j][k] = 0 4. Else A[j][k] = U[½*j*(j+1)+k] 5. End for 6. End for

EXERCISES a) Implement the algorithms A1 and A2 in C.

15

Data Structures and Algorithms

___

Lab Session 04

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

b) Analyze the given algorithms and express your result in Big O notation.

c) Find the size of U for a tridiagonal matrix B. Find the formula for L if U[L] = B[J][K].

16

Data Structures and Algorithms

___

Lab Session 04

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

d) Develop an algorithm to store non-zero entries of B in U.

e)

Develop an algorithm to retrieve B from U.

17

Data Structures and Algorithms

___

Lab Session 05

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

Lab Session 05 OBJECT Application of the binary search on a list of elements stored in an array. THEORY 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 our 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[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 Algorithm: BINSEARCH(DATA, ITEM) 1. Set BEG = 0, END = N-1 and MID = INT((BEG + END) / 2) 2. Repeat steps 3 and 4 while BEG 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 welldefined. 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. 36

Data Structures and Algorithms

___

Lab Session 09

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

Algorithm: FACTORIAL(FACT, n) 1. if (n = = 0) then set FACT = 1 and return. 2. FACT = n x FACTORIAL(FACT, n –1 ) 3. Return.

EXERCISES 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)= { (

)

(

)

a) Find C (4, 3).

b) Find C (6, 4) and record your observations.

37

Data Structures and Algorithms

___

Lab Session 09

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

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.

38

Data Structures and Algorithms

___

Lab Session 09

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

f) Implement the Ackermann Function in C. (

)

{

( (

) (

39

)

Data Structures and Algorithms

___

Lab Session 10

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

Lab Session 10 OBJECT Implementation of queue operations.

THEORY A queue is a linear list of elements in which deletions can take place only at one end, called the front, and insertions can take place only at the other end, called the rear. Queues are also called first-in first-out (FIFO) lists, since the first element in a queue will be the first element out of the queue. In other words, the order in which elements enter a queue is the order in which they leave. This contrasts with stacks, which are last-in first-out (LIFO) lists. An important example of a queue in computer science occurs in a timesharing system, in which programs with the same priority form a queue while waiting to be executed. In general, queues are used in situations where a fairness criterion is to be adopted by rendering services on the basis of order of request. Array implementation of queues requires a linear array elements for containing queue elements, and two integer variables: front, to hold the array index of the front element of queue; and rear, to hold the array index of the rear element of queue. Adding an element to a queue is called ENQUEUE operation and removing an element from a queue is called DEQUEUE operation.

ALGORITHMS Algorithm A1: ADDONE (i) This algorithm increments a number i using modulo arithmetic, so the number returned is always greater than -1 and less than the total size of the array used to hold the queue. 1. i=(i+1) mod maxlength 2. Return i Algorithm A2: MAKENULL (Q) This algorithm initializes the queue structure, so that it holds nothing. This structure has two integer memebers, front and rear, and an array member, elements. 1. Q.front = 0 2. Q.rear = maxlength-1 Algorithm A3: EMPTY (Q) This returns TRUE iff Q does not contain any element. 40

Data Structures and Algorithms

___

Lab Session 10

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

1. If ADDONE (Q.rear) = Q.front return TRUE 2. Return FALSE Algorithm A4: FRONT (Q) This algorithm is a function that returns the first element on queue Q. 1. If EMPTY (Q) then write „queue is empty‟ 2. Else return Q.elements[Q.front] Algorithm A5: ENQUEUE (x, Q) This algorithm inserts element x at the end of queue Q. 1. If ADDONE(ADDONE(Q.rear)) = Q.front then write „queue is full‟ 2. Else: a. Q.rear = ADDONE (Q.rear) b. Q.elements [Q.rear] = x Algorithm A6: DEQUEUE (var Q: QUEUE); This algorithm deletes the first element of queue Q. 1. If EMPTY (Q) then write „queue is empty‟ 2. Else Q.front = ADDONE (Q.front)

EXERCISES a) For the array implementation of a queue, write down the necessary declaration in C.

b) Briefly elaborate the purpose of algorithm ADDONE. (Hint: Consider the case i = maxlength).

41

Data Structures and Algorithms

___

Lab Session 10

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

c) In the light of your answer to exercise (b), is it just to call Q.elements a circular array? Explain.

d) Implement all above algorithms in C.

42

Data Structures and Algorithms

___

Lab Session 10

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

43

Data Structures and Algorithms

___

Lab Session 10

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

e) Implement EMPTY, ENQUEUE, DEQUEUE algorithms in C using linked list.

44

Data Structures and Algorithms

___

Lab Session 11

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

Lab Session 11 OBJECT Design and implementation of linked list algorithms.

THEORY A linked list consists of a set of nodes, each of which has two fields: an information field and a pointer to the next node in the list. S

Info next

Info next

Info next

Info

X

The diagram depicts the logical picture of a linked list. S is a pointer to the first node in the list and S = NULL obviously denotes an empty list. X denotes NULL indicating end of list. The successive elements in the list need not occupy contiguous locations in memory. This contrasts with arrays where elements must be sequentially placed in memory. Linked lists have a close relation with dynamic memory allocation that emphasizes the allocation of memory space at run time as the need arises. This is again in contrary to static memory allocation in which memory space is reserved at compile time as is done with array declaration. For the same reason, arrays are called static data structures as the size of array can‟t be changed during program execution. This leads to inefficient use of memory space. Linked lists obviously use memory more economically. Linked lists are regarded as dynamic data structures. In addition, the dynamic nature of memory allocation results in efficient insertions and deletions of elements in linked lists as opposed to arrays. Linked lists are of key importance in computer science. They prove to be very useful in implementing other important data structures. Several skills are vital in relation to them: (1) knowing how to declare pointer data types for list nodes; (2) knowing how to create and delete list nodes, and how to link them together; and (3) knowing how to perform various important list operations such as insertion and deletion of nodes, searching for items, printing lists, and joining lists together.

ALGORITHMS Declarations We shall use a structure variable for representing node of a linked list. The variable comprises two fields: an integer variable info (this may be of any other type as desired) and a pointer variable next for holding the address of next node in the list. Algotithm A1: Inserting a new second node 1. Declare a pointer variable, N that points to node of type in conformance with the type of nodes in linked list. 45

Data Structures and Algorithms

___

Lab Session 11

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

2. Allocate a new node and let the pointer variable N point to it. N

?

info

?

next

3. Load the desired integer value „val‟ in the info field of newly allocated node. 4. Change the link field of the N‟s referent to point to the second of node the linked list.

N

val

info

S

next

val2

val1

X

5. Change the link field of the first node of the linked list to point to the N‟s referent. (Now pointer variable N remains of no significance)

val info

S

next

val2

val1

X

Algotithm A2: Searching for an item 1. Declare a pointer variable, N that points to node of type in conformance with the type of nodes in linked list. 2. Initially set N to point to the first node in the list. 3. While (N points to a non-null node of the list) If value in the info field of N‟s referent equals the item to be searched, return the pointer node in N Else advance the pointer N to point to the next node in the list 4. Return N‟s value, NULL, as the result of list search. Algotithm A3: Deleting the last node 1. Let Pnode (P for previous) and Cnode (C for current) contain pointers to list nodes. 2. If the list is not empty{ If the list has exactly one node 46

Data Structures and Algorithms

___

Lab Session 11

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

free the node‟s storage, load NULL in the pointer to first node and return. Else { Initialize Pnode, Cnode to point to the first and second nodes. //Advance the Pnode, Cnode until Cnode points to the last node. While Cnode doesn‟t point to the last node, Advance Pnode, Cnode to the next pair of nodes. } //Now Pnode points to the next-to-last node and Cnode points to the last node on the list. Change the next-to-last node into the last node and free the space for the discarded last node. }

EXERCISES a) Implement the declaration (as described under the head of algorithm) in C.

b) Implement all the algorithms as separate procedures and demonstrate their use in a program.

47

Data Structures and Algorithms

___

Lab Session 11

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

48

Data Structures and Algorithms

___

Lab Session 11

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

c) A doubly linked list is one in which there are two pointers in a node, one pointing to the next node and the other pointing to the previous node. Design all above algorithms for a doubly linked list and use them in a program.

49

Data Structures and Algorithms

___

Lab Session 12

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

Lab Session 12 OBJECT Understanding binary trees and development of algorithms to incorporate them in various applications.

THEORY 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

G

E

H

F

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. 1. PREorder: 2. INorder:

V L R L V R 50

Data Structures and Algorithms

___

Lab Session 12

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

3. POSTorder:

L R V

These three names are chosen according to the step at which the given node is visited. With PREorder traversal, the root is visited before the subtrees; with INorder traversal, root is visited between them; and with POSTorder traversal, the root is visited after both of the subtrees. As an example, consider the following binary tree: 1

2

3

4 PREorder: INorder: POSTorder:

1 4 4

2 3 5

3 5 3

5 4 2 2

5 1 1

The choice of the names PREorder, INorder, and POSTorder for the three most important traversal methods is not accidental, but relates closely to a motivating example of considerable interest, that of expression trees. An expression tree is built from simple operators of an (arithmetic or logical) expression by placing operands as the leaves of a binary tree and the operators as the interior nodes. For example, a – (b x c) __

a

x b

c

(a < b) or (c < d) or

< a

< b

c 51

d

Data Structures and Algorithms

___

Lab Session 12

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

ALGORITHMS Declarations typedef struct treenode{ TreeEntry entry; TreeNode *left; TreeNode *right; }TreeNode; The type TreeEntry depends on the application. Algorithm A1: Create-Tree Operation This function has no precondition and results in an empty binary tree to which root points. void CreateTree (TreeNode *root) { *root = NULL; } Algorithm A2: Tree-Empty Operation It accepts root and returns TRUE or FALSE according as the tree is empty or not. boolean TreeEmpty (TreeNode *root) { return (root = = NULL); } Algorithm A3: PREorder Traversal In each of the traversal algorithms we assume existence of a function Visit that does the desired task for each node. void PREorder (TreeNode *root, void (* Visit) (TreeEntry x)) { if (root) { Visit (root  entry); PREorder (root  left, Visit); PREorder (root  right, Visit); } } Algorithm A4: INorder Traversal void INorder (TreeNode *root, void (* Visit) (TreeEntry x)) { 52

Data Structures and Algorithms

___

Lab Session 12

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

if (root) { INorder (root  left, Visit); Visit (root  entry); INorder (root  right, Visit); } } Algorithm A5: POSTorder Traversal void POSTorder (TreeNode *root, void (* Visit) (TreeEntry x)) { if (root) { POSTorder (root  left, Visit); POSTorder (root  right, Visit); Visit (root  entry); } }

EXERCISES a) Draw expression tree for the following infix expressions and then give their postfix and prefix expressions. i) log n! ii) (A+B) * (C + log (D+E!) – sin (G/H)) iii) x=(-b ± √ (b2 - 4ac) ) / 2a

53

Data Structures and Algorithms

___

Lab Session 12

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

b) Write a function int TreeSize (Tree *root) that will count all the nodes of a linked binary tree.

54

Data Structures and Algorithms

___

Lab Session 12

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

c) Write a function void ClearTree (Tree *root) that will traverse a binary tree (in whatever order you find works best) and dispose of all of its nodes.

55

Data Structures and Algorithms

___

Lab Session 12

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

d) Design an algorithm to perform a double-order traversal of a binary tree, meaning that each node of the tree, the algorithm first visits the node, then traverses the left subtree (in double order), then visits the node again, then traverses its right subtree (in double order).

56

Data Structures and Algorithms

___

Lab Session 13

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

Lab Session 13 OBJECT Implementation of search through a linked binary search tree.

THEORY We have discussed two advantages of using linked lists: (1) efficiency of insertions and deletions, and (2) efficient use of memory space. One of the drawbacks of using a linked list is the time it takes to search a long list. A sequential search of all the nodes in the whole list is an O (N) operation. We already know that binary search algorithm applied on an array is an O (log2 N) operation. It would be nice if we could binary search a linked list, but there is no practical way to find the midpoint of a linked list. We can, however reorganize the list‟s elements into a linked structure that is just perfect for binary searching: the binary search tree. The binary search tree provides us with a structure that retains the flexibility of a linked list while allowing quicker O (log2 N) access to any node in the list. 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. A

root

B

C

D

G

E

H

level 0

F

I

level 1

level 2

J

level 3

The level of a node refers to its distance from the root. If we designate the level of the root as 0, every other node is assigned a level number that is 1 more than the level of its parent. The height (or depth) of a tree is the maximum number of nodes in a branch of tree. This turns out to be 1 more than the largest level number. A binary search tree is a binary tree in which the value in any node is greater than the value in any children in its left subtree and less than the value in any children in its right subtree. For example,

57

Data Structures and Algorithms

___

Lab Session 13

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

E

C

A

H

D F

B

I

G

J

It is important to note that no two entries in a binary search tree may have equal values. 

ANALYZING PERFORMANCE CHARACTERISTICS

Binary search trees are interesting, in part, because they yield performance advantages. However, without going into mathematical details, we mention here the shape that a binary search tree takes in the best, worst, and average cases. Case Best Case Worst Case Average Case 

Tree Shape Leaves on at most two adjacent levels Exactly one internal node on each level Reasonably balanced, only occasionally deep

TREE SEARCH

The most important operation for binary search trees is the one from which their name comes: a function to search through a linked binary search tree for an entry with a particular target key. To search for the target, we first compare it with the key at the root of the tree. If it is the same, then our job is done. If it is less than the root, we go to the left subtree; and if it is greater than the root, then we go to the right subtree and continue the search.

ALGORITHMS Recursive Version TreeNode *TreeSearch (TreeNode *root, KeyType target) { if (root) if (LT (target, root  entry.key)) /* LT checks whether target key is < that of node being visited */ root = TreeSearch (root  left, target); else if (GT (target, root  entry.key)) /* GT checks whether target key is > that of node being visited */ root = TreeSearch (root  right, target); return root;} 58

Data Structures and Algorithms

___

Lab Session 13

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

Recursion Removal The above function has tail recursion, that is, as the last statement executed in the function. By using a loop, it is always possible to change tail recursion into iteration. Here, we write a loop in place of the cascaded if statements, and we use the variable position to move through the tree. while (position && NE (target, position  entry.key)) /* NE to check for not equal */ if (LT (target, position  entry.key)) position = position  left; else position = position  right;

EXERCISES a) What are the maximum and minimum numbers of levels that a binary search tree with 100 nodes can have? Justify your answer.

b) Write a non-recursive algorithm Ancestors that prints the ancestors of a given node whose info field contains a value Num. Num only occurs once in the tree.

59

Data Structures and Algorithms

___

Lab Session 13

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

c) Your CR wrote the following program to perform search for AirportCodes in the binary search tree. Comment on it with regard to correctness. If correct, explain. typedef char AirportCode [4]; typedef

struct

TreeNodeTag { AirportCode Struct TreeNodeTag Struct TreeNodeTag } TreeNode;

Airport; *LeftLink; *RightLink;

TreeNode *BinaryTreeSearch (AirportCode A, TreeNode *T) { TreeNode *N, int result; N =T; while (N != NULL) { if ( (result = strcmp (A, N  Airport)) = = 0) return (N); /* N points to the node containing A */ else if (result < 0) N = N  Leftlink; /* Let N point to the left subtree’s root */ else N = N  Rightlink; /* Let N point to the right subtree’s root */ } return (N); }

60

Data Structures and Algorithms

___

Lab Session 13

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

d) Write a recursive version of the program in exercise (c) that works correctly.

61

Data Structures and Algorithms

___

Lab Session 13

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

e) Write a function TreeInsert to insert a new entry into a binary search tree whose root node is referenced by the tree node pointer *T.

62

Data Structures and Algorithms

___

Lab Session 14

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

Lab Session 14 OBJECT Analysis of methods of graph representations and construction of graph traversal algorithms.

THEORY If we are to write programs for solving problems concerning graphs, then we must find ways to represent the mathematical structure of a graph as some kind of data structure. There are several methods in common use, which differ fundamentally in the choice of abstract data type used to represent graphs, and there are several variations depending on the implementation of abstract data type. In other words, we begin with one mathematical system (a graph), then we study how it can be described in terms of abstract data types (sets, tables, and lists can all be used, as it turns out), and finally we choose implementations for the abstract data type that we select. 

ADJACENCY LIST

The adjacency list of a given vertex V is the list of all adjacent vertices of V. 

LINKED IMPLEMENTATION

Greatest flexibility is obtained by using linked lists for both the vertices and the adjacency lists. This implementation has the following declaration. typedef struct vertex Vertex; typedef struct edge Edge; struct vertex{ Edge *firstedge; Vertex *nextvertex; };

/* start of the adjacency list */ /* next vertex on the linked list */

struct edge{ Vertex *endpoint; Edge *nextedge; };

/* vertex to which the edge points */ /* next edge on the adjacency list */

typedef Vertex *Graph;

/* Header for the list of vertices */



CONTIGUOUS IMPLEMENTATION

Although the linked implementation is very flexible, it is sometimes awkward to navigate through the linked lists, and many algorithms require random access to vertices. Therefore the following contiguous implementation is often better. For a contiguous adjacency list, we must keep a counter, and for this we use standard notation from graph theory: The valence of a 63

Data Structures and Algorithms

___

Lab Session 14

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

vertex is defined as the number of edges on which it lies, and therefore it is also the number of vertices adjacent to it. This contiguous implementation is given below. typedef

int AdjacencyList [MAXVERTEX];

typedef struct graph{ int n; /* number of vertices in the graph */ int valence [MAXVERTEX]; AdjacencyList A [MAXVERTEX]; }Graph; 

MIXED IMPLEMENTATION

The final implementation uses a contiguous list for the vertices and linked storage for the adjacency lists. typedef struct edge{ Vertex endpoint; struct edge *nextedge; }Edge; typedef struct graph{ int n; /* number of vertices in the graph */ Edge *firstedge [MAXVERTEX]; }Graph;

ALGORITHMS In many problems, we wish to investigate all the vertices in a graph in some systematic order, just as with binary trees. In tree traversal, we had a root vertex with which we generally started; in graph, we do not have any one vertex singled out as special, and therefore the traversal may start at an arbitrary vertex. Although there are many possible orders for visiting the vertices of a graph, two methods are of particular importance. Algorithm A1: Depth-First Traversal Suppose that the traversal has just visited a vertex v, and let w1, w2, . . . , wk be the vertices adjacent to v. Then we shall next visit w1 and keep w2, . . . , wk waiting. After visiting w1, we traverse all the vertices to which it is adjacent before returning to traverse w2, . . . , wk. void DepthFirst (Graph G, void (* Visit) (Vertex)) /* (Post-Condition) The function Visit has been performed at each vertex of G in depth-first order. The function Traverse produces the recursive depth-first order. */ { Boolean visited [MAXVERTEX]; Vertex v; for (all v in G) visited [v] = FALSE; for (all v in G) if (!visited [v]) 64

Data Structures and Algorithms

___

Lab Session 14

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

Traverse (v, Visit); } The recursion is performed in the following function, to be declared along with the previous one. void Traverse (Vertex v, void(* Visit) (Vertex)) { Vertex w; visited [v] = TRUE; visit (v) ; for (all w adjacent to v) if (! visited [w] ) Traverse (w, Visit); } Algorithm A2: Breadth-First Traversal void BreadthFirst (Graph G, void (* Visit) (Vertex)) /* (Post-Condition) The function Visit has been performed at each vertex of G in breadth-first order. */ { Queue Q; Boolean visited [MAXVERTEX]; Vertex v, w; for (all v in G) visited [v] = FALSE; CreateQueue (Q); for (all v in G) if (!visited [v] ) { Enqueue (v, Q); do { Dequeue (v, Q); if (!visited [v] ) { visited [v] = TRUE; Visit (v); } for (all w adjacent to v) if (!visited [w]) Enqueue (w, Q); } while (!Empty(Q)); } }

EXERCISES a) A graph is regular if every vertex has the valence (that is, if it is adjacent to the same number of other vertices). For a regular graph, a good implementation is to keep the vertices in a linked list and the adjacency lists contiguous. The length of all the adjacency lists is called the degree of the graph. Write C declarations for this implementation of regular graphs. 65

Data Structures and Algorithms

___

Lab Session 14

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

b) Write C function ReadGraph that will read from the terminal the vertices in an undirected graph and lists of adjacent vertices.

c) Write C function WriteGraph that will write pertinent information specifying a graph to the terminal.

66

Data Structures and Algorithms

___

Lab Session 14

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

d) Use the functions ReadGraph and WriteGraph to implement and test the breadth-first traversal algorithm.

67

Data Structures and Algorithms

___

Lab Session 14

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

e) Use the functions ReadGraph and WriteGraph to implement and test the depth-first traversal algorithm.

68

Data Structures and Algorithms

___

Lab Session 15

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

Lab Session 15 OBJECT Development of an algorithm for the game of Life.

THEORY The game of Life is really a simulation, not a game with players. It takes place on an unbounded rectangular grid in which each cell can either be occupied by an organism or not. Occupied cells are called alive; unoccupied cells are called dead. Which cells are alive changes from generation to generation according to the number of neighboring cells that are alive, as follows: 1. The neighbors of a given cell are the eight cells that touch it vertically, horizontally, or diagonally. 2. If a cell is alive but either has no neighboring cells alive or only one alive, then in the next generation the cell dies of loneliness. 3. If a cell is alive and has four or more neighboring cells also alive, then in the next generation the cell dies of overcrowding. 4. A living cell with either two or three living neighbors remains alive in the next generation. 5. If a cell is dead, then in the next generation it will become alive if it has exactly three neighboring cells, no more or fewer, that are already alive. All other dead cells remain dead in the next generation. 6. All births and deaths take place at exactly the same time, so that dying cells can help to give birth to another, but cannot prevent the death of others by reducing overcrowding, nor can cells being born either preserve or kill cells living in the previous generation. As a first example consider the community:

0 0 0 0 0

0 1 1 1 0

0 1 1 1 0

0 1 1 1 0

0 1 1 1 0

0 0 0 0 0

By rule 2 both cells will die in the next generation. Rule 5 shows that no cells will become alive, so the community dies out.

69

Data Structures and Algorithms

___

Lab Session 15

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

On the other hand, consider the community:

0 0 0 0 0 0

0 1 2 2 1 0

0 2 3 3 2 0

0 2 3 3 2 0

0 1 2 2 1 0

0 0 0 0 0 0

Each of the living cells has a neighbor count of three and hence remains alive, but the dead cells all have neighbor counts of two or less and hence none of them becomes alive. The two communities:

0 1 1 1 0

0 2 1 2 0

0 3 2 3 0

0 2 1 2 0

0 1 1 1 0

0 0 0 0 0

1 2 3 2 1

1 1 2 1 1

1 2 3 2 1

0 0 0 0 0

and

continue to alternate from generation to generation, as indicated by the neighbor counts shown.

EXERCISES a) Determine by hand calculations what will happen to each of the communities shown, over the course of four generations.

a

b

c 70

d

Data Structures and Algorithms

___

Lab Session 15

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

71

Data Structures and Algorithms

___

Lab Session 15

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

b) Write a program that will show how an initial community will change from generation to generation.

72

Data Structures and Algorithms

___

Lab Session 15

NED University of Engineering & Technology – Department of Computer & Information Systems Engineering

73