Trees-Datastructues and Algorithms-Solutions, Exercises of Data Structures and Algorithms

This is solution manual provided by Muhammad Uzair at University of Engineering and Technology Lahore. It related to Data Structures and Algorithms course. Its main points are: Disjoint, Set, Arbitrary, Unions, Node, Tree, Stack, Root, Path, Compression, Array

Typology: Exercises

2011/2012

Uploaded on 07/16/2012

sangodkar
sangodkar 🇵🇰

5

(2)

12 documents

1 / 14

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
Data Structures & Algorithm Analysis in C
(second edition)
MarkAllenWeiss
FloridaInternationalUniversity
SolutionsManual
By:
Muhammad Uzair
05-E-147
U.E.T. Lahore
Pakistan
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe

Partial preview of the text

Download Trees-Datastructues and Algorithms-Solutions and more Exercises Data Structures and Algorithms in PDF only on Docsity!

Data Structures & Algorithm Analysis in C

(second edition)

MarkAllenWeiss

FloridaInternationalUniversity

SolutionsManual

By:

Muhammad Uzair

05-E-

U.E.T. Lahore

Pakistan

[email protected]

Preface

Included in this manual are answers to most of the exercises in the textbook Data Structures and Algorithm Analysis in C, second edition, published by Addison-Wesley. These answers reflect the state of the book in the first printing.

Specifically omitted are likely programming assignments and any question whose solu- tion is pointed to by a reference at the end of the chapter. Solutions vary in degree of complete- ness; generally, minor details are left to the reader. For clarity, programs are meant to be pseudo-C rather than completely perfect code.

Errors can be reported to [email protected]. Thanks to Grigori Schwarz and Brian Harvey for pointing out errors in previous incarnations of this manual.

Chapter 4: Trees

4.1 (a) A O.

(b) G O, H O, I O, L O, M O, and K O.

4.2 For node B O:

(a) A O. (b) D O and E O. (c) C O. (d) 1. (e) 3.

4.3 4.

4.4 There are N O nodes. Each node has two pointers, so there are 2 N O pointers. Each node but the root has one incoming pointer from its parent, which accounts for N O−1 pointers. The rest are NULL. O

4.5 Proof is by induction. The theorem is trivially true for H O = 0. Assume true for H O = 1, 2, ..., k O. A tree of height k O+1 can have two subtrees of height at most k O. These can have at most 2 k O+^1 −1 nodes each by the induction hypothesis. These 2 k O+^2 −2 nodes plus the root prove the theorem for height k O+1 and hence for all heights.

4.6 This can be shown by induction. Alternatively, let N O = number of nodes, F O = number of full nodes, L O = number of leaves, and H O = number of half nodes (nodes with one child). Clearly, N O = F O + H O + L O. Further, 2 F O + H O = N O − 1 (see Exercise 4.4). Subtracting yields L O − F O = 1.

4.7 This can be shown by induction. In a tree with no nodes, the sum is zero, and in a one-node tree, the root is a leaf at depth zero, so the claim is true. Suppose the theorem is true for all trees with at most k O nodes. Consider any tree with k O+1 nodes. Such a tree consists of an i O node left subtree and a k O − i O node right subtree. By the inductive hypothesis, the sum for the left subtree leaves is at most one with respect to the left tree root. Because all leaves are one deeper with respect to the original tree than with respect to the subtree, the sum is at most 1 ⁄ 2 with respect to the root. Similar logic implies that the sum for leaves in the right subtree is at most 1 ⁄ 2 , proving the theorem. The equality is true if and only if there are no nodes with one child. If there is a node with one child, the equality cannot be true because adding the second child would increase the sum to higher than 1. If no nodes have one child, then we can find and remove two sibling leaves, creating a new tree. It is easy to see that this new tree has the same sum as the old. Applying this step repeatedly, we arrive at a single node, whose sum is 1. Thus the original tree had sum 1.

4.8 (a) - * * a b + c d e.

(b) ( ( a * b ) * ( c + d ) ) - e. (c) a b * c d + * e -.

4.11 This problem is not much different from the linked list cursor implementation. We maintain an array of records consisting of an element field, and two integers, left and right. The free list can be maintained by linking through the left field. It is easy to write the CursorNew O and CursorDispose O routines, and substitute them for malloc and free.

4.12 (a) Keep a bit array B O. If i O is in the tree, then B O[ i O] is true; otherwise, it is false. Repeatedly generate random integers until an unused one is found. If there are N O elements already in the tree, then M O − N O are not, and the probability of finding one of these is ( M O − N O) / M O. Thus the expected number of trials is M O / ( M O− N O) = α / (α − 1). (b) To find an element that is in the tree, repeatedly generate random integers until an already-used integer is found. The probability of finding one is N O / M O, so the expected number of trials is M O / N O = α. (c) The total cost for one insert and one delete is α / (α − 1) + α = 1 + α + 1 / (α − 1). Set- ting α = 2 minimizes this cost.

4.15 (a) N O(0) = 1, N O(1) = 2, N O( H O) = N O( H O−1) + N O( H O−2) + 1.

(b) The heights are one less than the Fibonacci numbers.

4.17 It is easy to verify by hand that the claim is true for 1 ≤ k O ≤ 3. Suppose it is true for k O = 1, 2, 3, ... H O. Then after the first 2 H O^ − 1 insertions, 2 H O−^1 is at the root, and the right subtree is a balanced tree containing 2 H O−^1 + 1 through 2 H O^ − 1. Each of the next 2 H O−^1 insertions, namely, 2 H O^ through 2 H O^ + 2 H O−^1 − 1, insert a new maximum and get placed in the right

4.23 After accessing 3,

After accessing 9,

After accessing 1,

After accessing 5,

______________________________________________________________________________________________________________________________________________________________

/* An alternative method is to use the results of Exercise 4.6. */

int CountFull( BinaryTree T ) { if( T == NULL ) return 0; return ( T->Left != NULL && T->Right != NULL ) + CountFull(T->Left) + CountFull(T->Right); }


4.29 We assume the existence of a function RandInt(Lower,Upper), O which generates a uniform random integer in the appropriate closed interval. MakeRandomTree O returns NULL if N O is not positive, or if N O is so large that memory is exhausted.


SearchTree MakeRandomTree1( int Lower, int Upper ) { SearchTree T; int RandomValue;

T = NULL; if( Lower <= Upper ) { T = malloc( sizeof( struct TreeNode ) ); if( T != NULL ) { T->Element = RandomValue = RandInt( Lower, Upper ); T->Left = MakeRandomTree1( Lower, RandomValue - 1 ); T->Right = MakeRandomTree1( RandomValue + 1, Upper ); } else FatalError( "Out of space!" ); } return T; }

SearchTree MakeRandomTree( int N ) { return MakeRandomTree1( 1, N ); }


______________________________________________________________________________________________________________________________________________________________

/* LastNode is the address containing last value that was assigned to a node */

SearchTree GenTree( int Height, int *LastNode ) { SearchTree T;

if( Height >= 0 ) { T = malloc( sizeof( T ) ); / Error checks omitted; see Exercise 4.29. / T->Left = GenTree( Height - 1, LastNode ); T->Element = ++LastNode; T->Right = GenTree( Height - 2, LastNode ); return T; } else return NULL; }

SearchTree MinAvlTree( int H ) { int LastNodeAssigned = 0; return GenTree( H, &LastNodeAssigned ); }


4.31 There are two obvious ways of solving this problem. One way mimics Exercise 4.29 by replacing RandInt(Lower,Upper) with (Lower+Upper) / 2. This requires computing 2 H O+^1 −1, which is not that difficult. The other mimics the previous exercise by noting that the heights of the subtrees are both H O−1. The solution follows:

4.33 This exercise and Exercise 4.34 are likely programming assignments, so we do not provide code here.

4.35 Put the root on an empty queue. Then repeatedly Dequeue O a node and Enqueue O its left and right children (if any) until the queue is empty. This is O O( N O) because each queue operation is constant time and there are N O Enqueue O and N O Dequeue O operations.

4.36 (a)

(b)

A

B

D

H I

E

J

C

F

L

O

K M

P Q R

G

N

4.41 The function shown here is clearly a linear time routine because in the worst case it does a traversal on both T O1 and T O2.


int Similar( BinaryTree T1, BinaryTree T2 ) { if( T1 == NULL || T2 == NULL ) return T1 == NULL && T2 == NULL; return Similar( T1->Left, T2->Left ) && Similar( T1->Right, T2->Right ); }


4.43 The easiest solution is to compute, in linear time, the inorder numbers of the nodes in both trees. If the inorder number of the root of T2 is x O, then find x O in T1 and rotate it to the root. Recursively apply this strategy to the left and right subtrees of T1 (by looking at the values in the root of T2’s left and right subtrees). If dN O is the depth of x O, then the running time satisfies T O( N O) = T O( i O) + T O( N O− i O−1) + dN O, where i O is the size of the left subtree. In the worst case, dN O is always O O( N O), and i O is always 0, so the worst-case running time is quadratic. Under the plausible assumption that all values of i O are equally likely, then even if d (^) N O is always O O( N O), the average value of T O( N O) is O O( N Olog N O). This is a common recurrence that was already formulated in the chapter and is solved in Chapter 7. Under the more reason- able assumption that d (^) N O is typically logarithmic, then the running time is O O( N O).

4.44 Add a field to each node indicating the size of the tree it roots. This allows computation of its inorder traversal number.

4.45 (a) You need an extra bit for each thread.

(c) You can do tree traversals somewhat easier and without recursion. The disadvantage is that it reeks of old-style hacking.