Daa Unit-2
Daa Unit-2
Search functions are also evaluated on the basis of their complexity, or maximum theoretical run time. Binary
search functions, for example, have a maximum complexity of O(log(n)), or logarithmic time. This means that the
maximum number of operations needed to find the search target is a logarithmic function of the size of the search
space.
In computer science, graph traversal (also known as graph search) refers to the process of visiting (checking and/or
updating) each vertex in a graph. Such traversals are classified by the order in which the vertices are visited. Tree
traversal is a special case of graph traversal.
Let us learn in detail about these very important topics in the following pages…
Binary tree :
Definition: A binary tree is a tree data structure in which each node has atmost two children,which are referred
to as the left child and the right child. (Or) Binary tree is a finite set of nodes which is either empty or consists of
root and two disjoint binary trees called as left sub tree and right sub tree
Example:
In the case of inorder traversal, the root of each subtree is visited after its left subtree has been traversed but before the traversal of its
right subtree begins. The steps for traversing a binary tree in inorder traversal are:
1. Visit the left subtree, using inorder.
2. Visit the root.
3. Visit the right subtree, using inorder.
Algorithm:
treenode = record
{
Type data; //Type is the data type of data. Treenode *lchild; treenode *rchild;
}
algorithm inorder (t)
// t is a binary tree. Each node of t has three fields: lchild, data, and rchild.
{
if t 0 then
{
inorder (t lchild); visit (t);
inorder (t rchild);
}
}
Example:
B C
D E F G
H I J K L M
LN A RN
B A RN
LN B RN A RN
LN D RN B RN A RN
DHBLNERN A RN
DHBIEJ A LNCRN
DHBIEJ A LNFRNCRN
DHBIEJ A FKCLNGRN
DHBIEJ A FKCLGM
DHBIEJAFKCLGM
2 Preorder Traversal:
In a preorder traversal, each node is visited before its left and right subtrees are traversed. Preorder search is also called
backtracking. The steps for traversing a binary tree in preorder traversal are:
Algorithm:
B C
D E F G
H I J K L M
ROOT NODE LEFTNODE RIGHT NODE
A LN RN
A B RN
A BLNRN RN
A B(DLNRN )RN RN
A BDH(ELNRN ) RN
A BDHEIJ CLNRN
A BDHEIJ C(FLNRN )RN
A BDHEIJ CFK(GLNRN)
A BDHEIJ CFKGLM
A BDHEIJCFKGLM
3 Postorder Traversal:
In a postorder traversal, each root is visited after its left and right subtrees have been traversed. The steps for traversing a binary tree in
postorder traversal are:
B C
D E F G
H I J K L M
LN RN A
B RN A
LNRNB RN A
LNRNDRNB RN A
HDLNRNEB C A
HDIJEB LNRNC A
HDIJEB LNRNFRNC A
HDIJEB KFLNRNGC A
HDIJEB KFLMGC A
HDIJEB KFLMGCA
2.)Non-Recursive binary tree traversal algorithms:
At first glance, it appears we would always want to use the flat traversal functions since the use less stack space. But the flat versions
are not necessarily better. For instance, some overhead is associated with the use of an explicit stack, which may negate the savings
we gain from storing only node pointers. Use of the implicit function call stack may actually be faster due to special machine
instructions that can be used.
Inorder Traversal:
Initially push zero onto stack and then set root as vertex. Then repeat the following steps until the stack is empty:
1. Proceed down the left most path rooted at vertex, pushing each vertex onto the stack and stop when there is no left son of
vertex.
2. Pop and process the nodes on stack if zero is popped then exit. If a vertex with right son exists, then set right son of vertex as
current vertex and return to step one.
he algorithm for inorder Non Recursive traversal is as follows:
Algorithm inorder()
{
stack[1] = 0 vertex = root
top: while(vertex ≠ 0)
{
push the vertex into the stack vertex = leftson(vertex)
}
while(vertex ≠ 0)
{
print the vertex node if(rightson(vertex) ≠ 0)
{
vertex = rightson(vertex) goto top
}
pop the element from the stack and made it as vertex
}
}
2 Preorder Traversal:
Initially push zero onto stack and then set root as vertex. Then repeat the following steps until the stack is empty:
1. Proceed down the left most path by pushing the right son of vertex onto stack, if any and process each vertex. The traversing
ends after a vertex with no left child exists.
2. Pop the vertex from stack, if vertex ≠ 0 then return to step one otherwise exit.
Algorithm preorder( )
{
stack[1]: = 0 vertex := root. while(vertex ≠ 0)
{
print vertex node if(rightson(vertex) ≠ 0)
push the right son of vertex into the stack. if(leftson(vertex) ≠ 0)
vertex := leftson(vertex) else
}
3 Post order Traversal:
Initially push zero onto stack and then set root as vertex. Then repeat the following steps until the stack is empty:
1. Proceed down the left most path rooted at vertex. At each vertex of path push vertex on to stack and if vertex has a right son push
–(right son of vertex) onto stack.
2. Pop and process the positive nodes (left nodes). If zero is popped then exit. If a negative node is popped, then ignore the sign and
return to step one.
Algorithm :
Algorithm postorder( )
{
stack[1] := 0 vertex := root
top: while(vertex ≠ 0)
{
push vertex onto stack if(rightson(vertex) ≠ 0)
push -(vertex) onto stack vertex := leftson(vertex)
}
pop from stack and make it as vertex while(vertex > 0)
{
print the vertex node
pop from stack and make it as vertex
}
if(vertex < 0)
{
vertex := -(vertex) goto top
}
}
2 Disjoint Set Operations:
Set:
A set is a collection of distinct elements. The Set can be represented, for examples, S1={1,2,5,10}.
Operations on sets:
1. Member(a,S):
There is a possibility that a∈S (or) a∉S.
If a∈S print „Yes‟ otherwise print „No‟.
Example: S={1,2,3,4}
Member(2,s) means 2∈S , print Yes.
Member(2,s) means 6∉S, print No.
2. Insert(a,S):
It means to add the element to the set.
Here „a‟ is element , S is set.
Example: S={1,2,3}
Insert 4 means S={1,2,3}U{4}
={1,2,3,4}
3. Delete(a,S):
It means to remove the element from set.
Example: S={1,2,3,4}
Delete(4,S) {1,2,3,4}-{4}
={1,2,3}
4. Union(S1,S2,S3):
The union of two sets is the set containing all elements belonging to either one of
the sets or to both, denoted by the symbol ∪.
If we conclude that S3=S1US2, we assume that S1 and 2 are disjoint sets.
Example: S1={1,2}
S2={3,4}
S3=S1US2={1,2}U{3,4}={1,2,3,4}
5. Find(a):
Print the name of the set in which „a‟ is currently member.
Example: S1={1,2}
S2={3,4}
Find(4) return S2 because 4∈S2 ie. Name of the set.
6. Split(a,S):
This operation can partition the set „S‟ into 2 sets ie. S1 and S2.
Example: S={1,2,3,4,5,6}
Split(3,S) then S1={1,2,3}
S2={4,5,6}
7. Min(S):
It prints the smallest element of the set „S‟.
Example: S={2,4,6}
Min(S)=2.
8. Max(S):
It prints the largest element of the set „S‟.
Example: S={2,4,6,8}
Max(S)=8.
Disjoint Sets:
The disjoints sets are those do not have any common element. For example S1= {1,7,8,9} and
S2={2,5,10}, then we can say that S1 and S2 are two disjoint sets.
Example:
S1={1,7,8,9} S2={2,5,10}
S1 U S2={1,2,5,7,8,9,10}
Set Representation:
The set will be represented as the tree structure where all children will store the address of parent / root
node. The root node will store null at the place of parent address. In the given set of elements any element can be
selected as the root node, generally we select the first node as the root node.
Example:
S1={1,7,8,9} S2={2,5,10} s3={3,4,6}
Then these sets can be represented as
Disjoint Union:
To perform disjoint set union between two sets Si and Sj can take any one root and make it sub-tree of the
other. Consider the above example sets S1 and S2 then the union of S1 and S2 can be represented as any one of the
following.
Find:
To perform find operation, along with the tree structure we need to maintain
the name of each set. So, we require one more data structure to store the set names. The data structure contains two
fields. One is the set name and the other one is the pointer to root.
3 Union and Find Algorithms:
In presenting Union and Find algorithms, we ignore the set names and identify sets just by the roots of
trees representing them. To represent the sets, we use an array of 1 to n elements where n is the maximum value
among the elements of all sets. The index values represent the nodes (elements of set) and the entries represent the
parent node. For the root value the entry will be „-1‟.
Example:
For the following sets the array representation is as shown below.
i [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]
p -1 -1 -1 3 2 3 1 1 1 2
1 Union Algorithm:
To perform union the SimpleUnion(i,j) function takes the inputs as the set roots i and j . And make the
parent of i as j i.e, make the second root as the parent of first root.
Algorithm SimpleUnion(i,j)
{
P[i]:=j;
}
For example, let us consider an array. Initially parent array contains zero‟s.
0 0 0 0 0 0 0
Child← 1 2 3 4 5 6 7 ↖parent
0 0 1 0 0 0 0
1 2 3 4 5 6 7
2) Union (2,5) → ①←③
②←⑤
0 0 1 0 2 0 0
1 2 3 4 5 6 7
3) Union (1,2) → ①←③
↑
②←⑤
0 0 1 0 2 0 0
1 2 3 4 5 6 7
①→②→③→④→……………………………
Since the time taken for a union is constant, the n-1 union s can be processed in time O(n).
2 Find Algorithm:
The SimpleFind(i) algorithm takes the element i and finds the root node of i. It starts at I until it reaches a
node with parent value -1.
Find (i) implies that if finds the root node of ith node, in other words it returns the name of the set.
Algorithm:-
Algorithm find(i)
integer I,j;
while(parent (j)>0 )
do j←parent(j)
repeat
return j;
EXAMPLE:
3 2
0 1 1 0 2 0
1 2 3 4 5 6
2>0 (true)
There fore j=2
return j;
that is 1.
1 2 3 4 ...... n
n-1
n-2
Since, the time taken for a Union is constant, the n-1 sequence of union can be processed in time O(n). And for the
sequence of Find operations it will take time
n
complexity of O ( i ) = O(n ).
i1
2
We can improve the performance of union and find by avoiding the creation of degenerate tree by applying
weighting rule for Union.
Algorithm WeightedUnion(i,j)
//Union sets with roots i and j , i≠j using the weighted rule
temp:= P[i]+P[j];
if (P[i]>P[j]) then
{
// i has fewer nodes P[i]:=j;
P[j]:=temp;
}
else
{
// j has fewer nodes P[j]:=i;
P[i]:=temp;
}
Find(8)………………………Find(8)
If SimpleFind() is used each Find(8) requires going up three parent link fields for a total of 24 moves .
When Collapsing find is used the first Find(8) requires going up three links and resetting three links. Each
of remaining seven finds require going up only one link field. Then the total cost is now only 13 moves.( 3
going up + 3 resets + 7 remaining finds).
Algorithm CollapsingFind(i)
// Find the root of the tree containing element i
r:=i;
while(P[r]>0) do r:=P[r]; //Find root while(i≠r)
{
//reset the parent node from element i to the root s:=P[i];
P[i]:=r;
i:=s;
}
}
4 Spanning Tree : A spanning tree is a subset of Graph G, which has all the vertices
covered with minimum possible number of edges. Hence, a spanning tree does not have
cycles and it cannot be disconnected..
By this definition, we can draw a conclusion that every connected and undirected Graph G
has at least one spanning tree. A disconnected graph does not have any spanning tree, as it
cannot be spanned to all its vertices.
We found three spanning trees off one complete graph. A complete undirected graph can
have maximum nn-2 number of spanning trees, where n is the number of nodes. In the above
addressed example, 33−2 = 3 spanning trees are possible.
1 General Properties of Spanning Tree :
We now understand that one graph can have more than one spanning tree. Following are a
few properties of the spanning tree connected to graph G −
All possible spanning trees of graph G, have the same number of edges and vertices.
Removing one edge from the spanning tree will make the graph disconnected, i.e. the spanning
tree is minimally connected.
Adding one edge to the spanning tree will create a circuit or loop, i.e. the spanning tree
is maximally acyclic.
From a complete graph, by removing maximum e - n + 1 edges, we can construct a spanning tree.
Thus, we can conclude that spanning trees are a subset of connected Graph G and
disconnected graphs do not have spanning tree.
Cluster Analysis
Let us understand this through a small example. Consider, city network as a huge graph and
now plans to deploy telephone lines in such a way that in minimum lines we can connect to
all city nodes. This is where the spanning tree comes into picture.
4.Minimum Spanning Tree (MST)
In a weighted graph, a minimum spanning tree is a spanning tree that has minimum weight
than all other spanning trees of the same graph. In real-world situations, this weight can be
measured as distance, congestion, traffic load or any arbitrary value denoted to the edges.
Kruskal's Algorithm
Prim's Algorithm
Example:
1
2
4 3
5 6
Queue is
Find out adjacent vertices of 1 and insert into queue here 2 and 4
are adjacent vertices of 1.After inserting 2 and 4 into queue we get
queue
Apply delete operation on queue. After applying deletion operation
1 will be deleted so BFS searching order is 1.
Now find out adjacent vertices of 2 and insert into queue here 3 is
adjacent vertex of 2.After inserting 3 in queue, we get
Now find out adjacent vertices of 3 and insert into the queue here 5
and 6 are adjacent vertices of 5.
Example:-
Push starting node into stack.
Stack = 1
Pop node 1 from the stack, traverse it push all the unvisited
adjacent nodes 5, 4, 2 of the Pop element on stack.
Pop the element node 4 from the stack, traverse it and push its
unvisited adjacent node 7 on the stack.
Stack=5, 7 traversal=1, 2, 3, 6, 5, 8, 9, 4
top=1
Pop the element node 7 from stack, traverse it its unvisited adjacent
node 8 has been visited so it is not pushed.
Stack=5 traversal=1, 2, 3, 6, 5, 8, 9, 4, 7
Top=0
AND/OR GRAPH:
And/or graph is a specialization of hypergraph which connects nodes by sets of arcs
rather than by a single arcs. A hypergraph is defined as follows:
A hypergraph consists of:
N, a set of nodes,
H, a set of hyperarcs defined by ordered pairs, in which the first implement of
the pair is a node of N and the second implement is the subset of N.
An ordinary graph is a special case of hypergraph in which all the sets of decendent
nodes have a cardinality of 1.
Hyperarcs also known as K-connectors, where K is the cardinality of the set of decendent nodes. If K
= 1, the descendent may be thought of as an OR nodes. If K > 1, the elements of the set of
decendents may be thought of as AND nodes. In this case the connector is drawn with
individual edges from the parent node to each of the decendent nodes; these individual
edges are then joined with a curved link.
And/or graph for the expression P and Q -> R is follows:
or The K-connector is represented as a fan of arrows with a single tie is shown above. The and/or
graphs consists of nodes labelled by global databases. Nodes labelled by compound
databases have sets of successor nodes. These successor nodes are called AND nodes, to
process the compound database to termination, all the compound databases must be
processed to terminatioexample consider, consider a boy who collects stamps (M). He has
for the purpose of exchange a winning conker (C), a bat (B) and a small toy animal (A).
In his class there are friends who are also keen collectors of different items and will make
the following exchanges.
1. 1 winning conker (C) for a comic (D) and a bag of sweets (S).
3. 1 bat (B) for two stamps (M, M). 4. 1 small toy animal (A) for two bats (B, B) and a stamp (M).
The problem is how to carry out the exchanges so that all his exchangable items are converted into
stamps (M). This task can be expressed more briefly as:
2. Transformation rules:
a. If C then (D, S)
b. If C then (B, M)
c. If B then (M, M)
d. If A then (B, B, M)
The figure shows that, a lot of extra work is done by redoing many of the transformations. This
repetition can be avoided by decomposing the problem into subproblems. There are two
major ways to order the components:
1. The components can either be arranged in some fixed order at the time they are generated (or).
The more flexible system is to reorder dynamically as the processing unfolds. It can be represented
by and/or graph. The solution to the exchange problem will be: Swap conker for a bat and
a stamp, then exchange this bat for two stamps. Swap his own bat for two more stamps,
and finally swap the small toy animal for two bats and a stamp. The two bats can be
exchanged for two stamps.
The previous exchange problem, when implemented as an and/or graph looks as follows:
Game Trees
In this chapter we look at using trees for game playing, in particular the problems of
searching game trees. We will classify all games into the folowing three groups
Each game consists of a problem space, an initial state, and a single (or a set of) goal
states. A problem space is a mathematical abstraction in a form of a tree:
The branching factor - the average number of children of the nodes in the
space.
The solution depth - the length of the shortest path from the initial node to a
goal node.
Tic-Tac-Toe is 9! = 362,880
8-puzzle - 9!/2
Checkers - 10^40
Chess - 10^120 (40 moves, 35 branch factor - 35^(2*40))
Brute-Force Searches
Breadth-First Search (BFS)
DFS generate the same set of nodes as BFS - Time Complexity is O(b^d)
The first solution DFS found may not be the optimal one.
Depth-First Iterative-Deepening
First performs a DFS to depth one. Than starts over executing DFS to depth
two and so on
Minimax
We consider games with two players in which one person's gains are the result of
another person's losses (so called zero-sum games). The minimax algorithm is a
specialized search algorithm which returns the optimal sequence of moves for a player
in an zero-sum game. In the game tree that results from the algorithm, each level
represents a move by either of two players, say A- and B-player. Below is a game tree
for the tic-tac-toe game
The minimax algorithm explores the entire game tree using a depth-first search. At
each node in the tree where A-player has to move, A-player would like to play the
move that maximizes the payoff. Thus, A-player will assign the maximum score
amongst the children to the node where Max makes a move. Similarly, B-player will
minimize the payoff to A-player. The maximum and minimum scores are taken at
alternating levels of the tree, since A and B alternate turns.
The minimax algorithm computes the minimax decision for the leaves of the game
tree and than backs up through the tree to give the final value to the current state.
Heuristic Search
So far we have looked at search algorithms that can in principle be used to
systematically search the whole search space. Sometimes however it is not feasible to
search the whole search space - it's just too big. In this case we need to use heuristic
search. The basic idea of heuristic search is that, rather than trying all possible search
paths, we focus on paths that seem to be getting us closer to the goal state. Of course,
we generally can't be sure that we are really near the goal state, but we might be able
to have a good guess. Heuristics are used to help us make that guess.
To use heuristic search we need an evaluation function that rankes nodes in the search
tree according to some criteria (for example, how close we are to the target). This
function provides a quick way of guessing.
A* algorithm
Best first search doesn't take into account the cost of the path from a start state to the
current state. So, we may find a solution but it may be not a very good solution. There
is a variant of best first search known as A* which attempts to find a solution which
minimizes the total cost of the solution path. This algorithm combines advantages of
breadth first search with advantages of best first search.
In the A* algorithm the score assigned to a node is a combination of the cost of the
path so far A(S) and the estimated cost E(S) to solution.
H(S) = A(S) + E(S)
The A* algorithm looks the same as the best first algorithm, but we use this slightly
more complex evaluation function.
.
Connected component: If G is connected undirected graph, then we can visit all the vertices of the
graph in the first call to BFS. The sub graph which we obtain after traversing the graph using BFS represents the
connected component of the graph.
Thus BFS can be used to determine whether G is connected. All the newly visited vertices on call to BFS
represent the vertices in connected component of graph G. The sub graph formed by theses vertices make the
connected component.
Spanning tree of a graph: Consider the set of all edges (u, w) where all vertices w are adjacent to u and are not
visited. According to BFS algorithm it is established that this set of edges give the spanning tree of G, if G is
connected. We obtain depth first search spanning tree similarly
These are the BFS and DFS spanning trees of the graph G
Bi-connected Components
A connected undirected graph is said to be bi-connected if it remains connected after removal of any one vertex
and the edges that are incident upon that vertex.
In this we have two components.
i. Articulation point: Let G= (V, E) be a connected undirected graph. Then an articulation
point of graph „G‟ is a vertex whose articulation point of graph is a vertex whose removal
disconnects the graph „G‟. It is also known as “cut point”.
ii. Bi-connected graph: A graph „G‟ is said to be bi-connected if it contains no-articulation
point.
i) After deleting vertex B and incident edges of B, the given graph is divided into two
components
ii) After deleting the vertex E and incident edges of E, the resulting components are
iii) After deleting vertex F and incident edges of F, the given graph is divided into teo
components.
Note: If there exists any articulation point, it is an undesirable feature in communication network where joint
point between two networks failure in case of joint node fails.
G. Vi-vertex belong Bi
Bi-Bi-connected component
i- Vertex number 1 to k
a- articulation point
Exercise