Sie sind auf Seite 1von 13

C program for BFS and DFS algorithm

#include<stdio.h> int q[ 20 ], top = -1, front = -1, rear = -1, a[ 20 ][ 20 ], vis[ 20 ], stack[ 20 ]; int delete(); void add ( int item ); void bfs( int s, int n ); void dfs( int s, int n ); void push( int item ); int pop(); main() { int n, i, s, ch, j; char c, dummy; printf( "ENTER THE NUMBER VERTICES " ); scanf( "%d", &n ); for ( i = 1;i <= n;i++ ) { for ( j = 1;j <= n;j++ ) { printf( "ENTER 1 IF %d HAS A NODE WITH %d ELSE 0 ", i, j ); scanf( "%d", &a[ i ][ j ] ); } } printf( "THE ADJACENCY MATRIX IS\n" ); for ( i = 1;i <= n;i++ ) { for ( j = 1;j <= n;j++ ) { printf( " %d", a[ i ][ j ] ); } printf( "\n" ); } do { for ( i = 1;i <= n;i++ )

vis[ i ] = 0; printf( "\nMENU" ); printf( "\n1.B.F.S" ); printf( "\n2.D.F.S" ); printf( "\nENTER YOUR CHOICE" ); scanf( "%d", &ch ); printf( "ENTER THE SOURCE VERTEX :" ); scanf( "%d", &s ); switch ( ch ) { case 1: bfs( s, n ); break; case 2: dfs( s, n ); break; } printf( "DO U WANT TO CONTINUE(Y/N) ? " ); scanf( "%c", &dummy ); scanf( "%c", &c ); } while ( ( c == 'y' ) || ( c == 'Y' ) ); } void bfs( int s, int n ) { int p, i; add ( s ); vis[ s ] = 1; p = delete(); if ( p != 0 ) printf( " %d", p );

while ( p != 0 ) { for ( i = 1;i <= n;i++ ) if ( ( a[ p ][ i ] != 0 ) && ( vis[ i ] == 0 ) ) { add ( i ); vis[ i ] = 1; } p = delete(); if ( p != 0 ) printf( " %d ", p ); } for ( i = 1;i <= n;i++ ) if ( vis[ i ] == 0 ) bfs( i, n ); } void add ( int item ) { if ( rear == 19 ) printf( "QUEUE FULL" ); else { if ( rear == -1 ) { q[ ++rear ] = item; front++; } else q[ ++rear ] = item; } } int delete() { int k; if ( ( front > return ( 0 else { k = q[ return rear ) || ( front == -1 ) ) ); front++ ]; ( k );

} } void dfs( int s, int n ) { int i, k; push( s ); vis[ s ] = 1; k = pop(); if ( k != 0 ) printf( " %d ", k ); while ( k != 0 ) { for ( i = 1;i <= n;i++ ) if ( ( a[ k ][ i ] != 0 ) && ( vis[ i ] == 0 ) ) { push( i ); vis[ i ] = 1; } k = pop(); if ( k != 0 ) printf( " %d ", k ); } for ( i = 1;i <= n;i++ ) if ( vis[ i ] == 0 ) dfs( i, n ); } void push( int item ) { if ( top == 19 ) printf( "Stack overflow " ); else stack[ ++top ] = item; } int pop() { int k; if ( top == -1 ) return ( 0 ); else {

k = stack[ top-- ]; return ( k ); } }

B-Tree is a self-balancing search tree. In most of the other self-balancing search trees (like AVL and Red Black Trees), it is assumed that everything is in main memory. To understand use of B-Trees, we must think of huge amount of data that cannot fit in main memory. When the number of keys is high, the data is read from disk in the form of blocks. Disk access time is very high compared to main memory access time. The main idea of using B-Trees is to reduce the number of disk accesses. Most of the tree operations (search, insert, delete, max, min, ..etc ) require O(h) disk accesses where h is height of the tree. B-tree is a fat tree. Height of B-Trees is kept low by putting maximum possible keys in a B-Tree node. Generally, a B-Tree node size is kept equal to the disk block size. Since h is low for B-Tree, total disk accesses for most of the operations are reduced significantly compared to balanced Binary Search Trees like AVL Tree, Red Black Tree, ..etc. Properties of B-Tree 1) All leaves are at same level. 2) A B-Tree is defined by the term minimum degree t. The value of t depends upon disk block size. 3) Every node except root must contain at least t-1 keys. Root may contain minimum 1 key. 4) All nodes (including root) may contain at most 2t 1 keys. 5) Number of children of a node is equal to the number of keys in it plus 1. 6) All keys of a node are sorted in increasing order. The child between two keys k1 and k2 contains all keys in range from k1 and k2. 7) B-Tree grows and shrinks from root which is unlike Binary Search Tree. Binary Search Trees grow downward and also shrink from downward. 8) Like other balanced Binary Search Trees, time complexity to search, insert and delete is O(Logn). Following is an example B-Tree of minimum degree 3. Note that in practical B-Trees, the value of minimum degree is much more than 3.

Search Search is similar to search in Binary Search Tree. Let the key to be searched be k. We start from root and recursively traverse down. For every visited non-leaf node, if the node has key, we simply return the

node. Otherwise we recur down to the appropriate child (The child which is just before the first greater key) of the node. If we reach a leaf node and dont find k in the leaf node, we return NULL. Traverse Traversal is also similar to Inorder traversal of Binary Tree. We start from the leftmost child, recursively print the leftmost child, then repeat the same process for remaining children and keys. In the end, recursively print the rightmost child. // C++ implemntation of search() and traverse() methods #include<iostream> using namespace std; // A BTree node class BTreeNode { int *keys; // An array of keys int t; // Minimum degree (defines the range for number of keys) BTreeNode **C; // An array of child pointers int n; // Current number of keys bool leaf; // Is true when node is leaf. Otherwise false public: BTreeNode(int _t, bool _leaf); // Constructor // A function to traverse all nodes in a subtree rooted with this node void traverse(); // A function to search a key in subtree rooted with this node. BTreeNode *search(int k); // returns NULL if k is not present. // Make BTree friend of this so that we can access private members of this // class in BTree functions friend class BTree; }; // A BTree class BTree { BTreeNode *root; // Pointer to root node int t; // Minimum degree public: // Constructor (Initializes tree as empty) BTree(int _t) { root = NULL; t = _t; } // function to traverse the tree void traverse() { if (root != NULL) root->traverse(); } // function to search a key in this tree BTreeNode* search(int k) { return (root == NULL)? NULL : root->search(k); } };

// Constructor for BTreeNode class BTreeNode::BTreeNode(int _t, bool _leaf) { // Copy the given minimum degree and leaf property t = _t; leaf = _leaf; // Allocate memory for maximum number of possible keys // and child pointers keys = new int[2*t-1]; C = new BTreeNode *[2*t]; // Initialize the number of keys as 0 n = 0; } // Function to traverse all nodes in a subtree rooted with this node void BTreeNode::traverse() { // There are n keys and n+1 children, travers through n keys // and first n children int i; for (i = 0; i < n; i++) { // If this is not leaf, then before printing key[i], // traverse the subtree rooted with child C[i]. if (leaf == false) C[i]->traverse(); cout << " " << keys[i]; } // Print the subtree rooted with last child if (leaf == false) C[i]->traverse(); } // Function to search key k in subtree rooted with this node BTreeNode *BTreeNode::search(int k) { // Find the first key greater than or equal to k int i = 0; while (i < n && k > keys[i]) i++; // If the found key is equal to k, return this node if (keys[i] == k) return this; // If key is not found here and this is a leaf node if (leaf == true) return NULL; // Go to the appropriate child return C[i]->search(k); }

The above code doesnt contain driver program. We will be covering the complete program in our next post on B-Tree Insertion. There are two conventions to define a B-Tree, one is to define by minimum degree (followed in Cormen book), second is define by order. We have followed the minimum degree convention and will be following same in coming posts on B-Tree. The variable names used in the above program are also kept same as Cormen book for better readability.

Check if a binary tree is subtree of another binary tree


August 15, 2011

Given two binary trees, check if the first tree is subtree of the second one. A subtree of a tree T is a tree S consisting of a node in T and all of its descendants in T. The subtree corresponding to the root node is the entire tree; the subtree corresponding to any other node is called a proper subtree. For example, in the following case, tree S is a subtree of tree T.

Tree S 10 / \ 4 6 \ 30 Tree T 26 / 10 / 4 \ 30
Solution: Traverse the tree T in preorder fashion. For every visited node in the traversal, see if the subtree rooted with this node is identical to S.

\ 3 \ 6 \ 3

Following is C implementation for this.


#include <stdio.h> #include <stdlib.h>

/* A binary tree node has data, left child and right child */ struct node { int data; struct node* left; struct node* right; };

/* A utility function to check whether trees with roots as root1 and root2 are identical or not */ bool areIdentical(struct node * root1, struct node *root2) { /* base cases */ if(root1 == NULL && root2 == NULL) return true; if(root1 == NULL || root2 == NULL) return false; /* Check if the data of both roots is same and data of left and right subtrees are also same */ return (root1->data == root2->data &&

areIdentical(root1->left, root2->left) && areIdentical(root1->right, root2->right) ); }

/* This function returns true if S is a subtree of T, otherwise false */ bool isSubtree(struct node *T, struct node *S) { /* base cases */ if (S == NULL) return true;

if (T == NULL) return false;

/* Check the tree with root as current node */ if (areIdentical(T, S)) return true;

/* If the tree with root as current node doesn't match then try left and right subtrees one by one */ return isSubtree(T->left, S) || isSubtree(T->right, S); }

if( isSubtree(T, S) ) printf("Tree S is subtree of tree T"); else printf("Tree S is not a subtree of tree T");

getchar(); return 0; }

C++ smart pointers[edit source]


In C++, smart pointers may be implemented as a template class that mimics, by means of operator overloading, the behaviour of traditional (raw) pointers, (e.g. dereferencing, assignment) while providing additional memory management algorithms. Smart pointers can facilitate intentional programming by expressing the use of a pointer in the type itself. For example, if a C++ function returns a pointer, there is no way to know whether the caller should delete the memory pointed to when the caller is finished with the information. some_type* ambiguous_function(); // What should be done with the result? Traditionally, this has been solved with comments, but this can be error-prone. The potential problems associated with this use can be mitigated by instead returning aunique_ptr, unique_ptr<some_type> obvious_function1(); The function makes explicit that the caller will take ownership of the result. Furthermore, no memory will be leaked if the caller does nothing. Prior to C++11, unique_ptr can be replaced with auto_ptr.

unique_ptr[edit source]
C++11 provides std::unique_ptr, defined in the header <memory>.
[1]

The copy constructor and assignment operators of std::auto_ptr do not actually copy the stored pointer. Instead, they transfer it, leaving the previous std::auto_ptr object empty. This was one way to implement strict ownership, so that only one auto_ptr object could own the pointer at any given time. [2] This means that auto_ptr should not be used where copy semantics are needed. C++11 provides support for move semantics; it allows for the explicit support of transferring values as a different operation from copying them. C++11 also provides support for explicitly preventing an object from being copied. Since std::auto_ptr already existed with its copy semantics, it could not be upgraded to be a move-only pointer without breaking backwards compatibility with existing code. Therefore, C++11 introduced a new pointer type: std::unique_ptr. This pointer type has its copy constructor and assignment operator explicitly deleted; it cannot be copied. It can be moved using std::move, which allows one unique_ptrobject to transfer ownership to another.

std::unique_ptr<int> std::unique_ptr<int> std::unique_ptr<int> the memory and p1 is

p1(new int(5)); p2 = p1; //Compile error. p3 = std::move(p1); //Transfers ownership. p3 now owns rendered invalid.

p3.reset(); //Deletes the memory. p1.reset(); //Does nothing. std::auto_ptr is still available, but it is deprecated under C++11.

shared_ptr and weak_ptr[edit source]


C++11 incorporates shared_ptr and weak_ptr, based on versions used by the Boost libraries. TR1 first introduced them to the standard, but C++11 gives them additional functionality in line with the Boost version. std::shared_ptr represents reference-counted ownership of a pointer. Each copy of the same shared_ptr owns the same pointer. That pointer will only be freed if all instances of the shared_ptr in the program are destroyed. std::shared_ptr<int> p1(new int(5)); std::shared_ptr<int> p2 = p1; //Both now own the memory. p1.reset(); //Memory still exists, due to p2. p2.reset(); //Deletes the memory, since no one else owns the memory. A std::shared_ptr uses reference counting, so circular references are potentially a problem. To break up cycles, std::weak_ptr can be used to access the stored object. The stored object will be deleted if the only references to the object are weak_ptr references. weak_ptr therefore does not ensure that the object will continue to exist, but it can ask for the resource. std::shared_ptr<int> p1(new int(5)); std::weak_ptr<int> wp1 = p1; //p1 owns the memory. { std::shared_ptr<int> p2 = wp1.lock(); //Now p1 and p2 own the memory. if(p2) //Always check to see if the memory still exists { //Do something with p2 } } //p2 is destroyed. Memory is owned by p1. p1.reset(); //Memory is deleted. std::shared_ptr<int> p3 = wp1.lock(); //Memory is gone, so we get an empty shared_ptr. if(p3) { //Will not execute this.

Das könnte Ihnen auch gefallen