Summary of common Binary Tree problems during interviews with Microsoft, Google, and other famous Enterprises

Source: Internet
Author: User

Sequence: a binary tree is an important data structure. Common Binary Trees include:
Full Binary Tree: Except for leaf nodes, all nodes have two nodes. left and right of the leaf node are null.
The best binary number is a tree with the shortest weight path. The Application of The Harman tree can be used for encoding and compression. for the construction of the Harman tree, see the construction of the Harman tree.
Full Binary Tree: Except for the bottom-layer leaf nodes, all the other layers are full, and the leaf layer is concentrated on the left end. The heap is a special full binary tree (full or full when one node is different)
Balanced Binary Tree: the so-called balanced binary tree refers to that the absolute value of the height difference between the left and right Subtrees cannot exceed 1. Including aVL and red/black trees.
Red/black tree: For details, see red/black tree.
Below are some common Binary Tree problems I have seen over the past few days.

1. the iterative construction of the binary search tree is an ordered tree. When a new node is inserted, it is less than the current root node left, greater than the current root node right until it reaches the null point, is the location of the node.

Void iterativeinsert (TREE * t, node * z) // insert node {node * Y = NULL; node * x = T-> root; // manage two pointers, parent pointer y, child tree pointer X while (X! = NULL) // always traverse down to the position where Z should be inserted {Y = x; If (X-> value <z-> value) x = x-> right; else x = x-> left;} Z-> P = y; // first point the parent pointer P of Z to Y if (y = NULL) // if the tree is empty, the root is z t-> root = z; else if (Z-> value <Y-> value) // otherwise, insert y-> left = Z on the left or right; else y-> right = z ;}

2. Recursive construction of the Binary Search Tree 1. If it is an empty tree, it is inserted to the root node Location 2. If it is more than the current root point, insert to the left. 3. Otherwise insert to the right

node* TreeInsert(node* root,node* z){if(!root)root=z;else if(root->value < z->value)root->right=TreeInsert(root->right,z);else root->left=TreeInsert(root->left,z);return root;}

3. Three recursive traversal methods of Binary Trees.

void InorderTreeWalk(node* root){if(!root ) return ;InorderTreeWalk(root->left);cout<<root->value<<' ';InorderTreeWalk(root->right);}void PriorTreeWalk(node* root){if(!root ) return ;cout<<root->value<<' ';PriorTreeWalk(root->left);PriorTreeWalk(root->right);}void PostTreeWalk(node* root){if(!root ) return ;PostTreeWalk(root->left);PostTreeWalk(root->right);cout<<root->value<<' ';}

4. Three iterative traversal methods of Binary Trees. The depth priority principle, and the output order is 'left subtree precedence'

Void iterativeinorderwalk (node * root) // iteratively traverse the {node * P = root; stack <node *> st; // use the stack if (! P) // If (! P) = If (P = NULL) return; while (p |! St. Empty () // when P is not empty or St is not empty {While (p) // go to the Left Bottom of the left child direction. Simultaneously press the stack {St. push (p); P = p-> left;} p = ST. top (); // get the cout element of the top stack <p-> value <""; ST. pop (); P = p-> right ;}} void iterativepriortreewalk (node * root) // iterate first order traversal {node * P = root; stack <node *> st; if (! P) return; while (p |! St. empty () {While (p) {cout <p-> value <""; ST. push (p); P = p-> left;} p = ST. top (); ST. pop (); P = p-> right ;}} void iterativepostwalk (node * root) {node * P = root; stack <node *> st; node * pre = NULL; // pre indicates the last accessed node if (! P) return; while (p |! St. empty () {While (p) // follow the left child direction to the leftmost bottom {St. push (p); P = p-> left;} p = ST. top (); // get the top element of the stack if (! P-> right | p-> right = pre) // If P does not have the right child or its right child has just been accessed. tips if (! P) indicates that if p is null {St. pop (); cout <p-> value <''; Pre = P; // The Last accessed node is p = NULL; // make the next cycle stop executing the stack operation below P nodes} else P = p-> right ;}}

5. how to print Binary Tree node data layer by layer from the root node. the breadth-first principle requires a queue. When a current node currentnode is accessed, the node is queued and the left and right child nodes of the currentnode are queued. Repeat this operation, the queue is empty. step: 1 initialize the queue. 2. Repeat the operations until the queue is empty.

// Print the Binary Tree node data layer by layer from the top, that is, traverse the binary tree in breadth. You need to use the queue void printhori (node * root) {If (! Root) return; queue <node *> q; q. Push (Root); While (! Q. empty () {node * front = Q. front (); q. pop (); cout <front-> value <''; If (front-> left) Q. push (front-> left); If (front-> right) Q. push (front-> right );}}

6. Obtain the depth of the tree = max (left subtree depth, right subtree depth) + 1

// Get the depth of the tree int gettreedepth (node * root) {If (! Root) return 0; int left = gettreedepth (root-> left); int right = gettreedepth (root-> right); return 1 + (left> right? Left: right); // max (left subtree, right subtree) + 1 is the height of the entire tree}

7. determine whether a binary tree is a balanced binary tree. method 1: the most direct method is to obtain the depth of the Left subtree, obtain the depth of the left and right subtree, and determine whether the difference is within 1. If yes, the current root node is a balance. otherwise, you can determine false. continue to use the same method to determine whether the left and right subtree of root is also balanced. now let's analyze the efficiency of this method: The gettreedepth () function is similar to the post-order traversal of the tree, T (n) = 2 * t (n/2) + 1, by the main theorem: T (n) = O (n ). that is, to locate the depth of the tree, you need to scan all nodes. similarly, you also need to scan the left and right subtree again for istreebalance (left) and istreebalance (right. what is the efficiency of this method for repeatedly scanning trees? T (n) = 2 * t (n/2) + N, that is, T (n) = nlgn. method 2: in order to overcome the defects of the method of scanning nodes multiple times, we try to change the space for time or adopt a bottom-up approach. the method is to first determine whether the root is balanced, and then determine whether the left and right subtree is balanced. now, I can change the angle to determine whether the Left and Right Subtrees are balanced. If the left and right Subtrees are balanced, the root node is considered. Otherwise, false is returned directly. this method saves the depth of the tree when the left and right subtree returns the root. that is, space change time. the complexity of this method is: T (n) = 2 * t (n/2) + 1.t( n) = n.

// Determine whether the tree balance bool istreebalance (node * root) {If (! Root) return true; int left = gettreedepth (root-> left); int right = gettreedepth (root-> right); If (left-right)> 1 | (right-left)> 1) return false; return istreebalance (root-> left) & istreebalance (root-> right );} // determine whether the tree balance bool isbalancetree (node * root, Int & depth) {If (! Root) {depth = 0; return true;} int left, right; if (isbalancetree (root-> left, left) & isbalancetree (root-> right, right )) {If (left-right <= 1 & right-left <= 1) {depth = 1 + (left> right? Left: right); Return true;} return false ;}

8. evaluate the minimum common ancestor LCA property of a binary tree: if the two chains have common ancestor, the nodes of the common ancestor are overlapped. because if x = x', then X-> next = x'-> next must be true. possibility 1: A Binary Search Tree. 1. If X and Y are less than root, 2 on the left. If X and Y are greater than root, 3 on the right. If X and Y are between root, root is LCA. Likelihood 2: it is not a binary search tree or even a binary tree. However, if each node has a parent pointer, the solution is 2: 1: space change time: from X, the Y-root linked list can be saved in the stack to find the last same node. 2. there is no need to change the space time, multi-scan method, and the two links from X, Y to root may be long and short, and the difference is n nodes. Then, the long chain table first advances n steps, and then the two are synchronized forward, find the first same node
You can. (This method is effective if the tree does not contain loops .) probability 3: This is an ordinary binary tree with only left and right. so we need auxiliary space. For the time method, call 16 first. getnodepath () in to get two linked list paths from root-> X and root-> Y. then compare the two linked lists and find the last same node.
// If the binary search tree is used, the lcanode * lowestcommonancestor1 (node * root, node * X, node * Y) {If (! Root |! X |! Y) return NULL; If (X-> value <root-> Value & Y-> value <root-> value) return lowestcommonancestor1 (root-> left, X, y); else if (X-> value> root-> Value & Y-> value> root-> value) return lowestcommonancestor1 (root-> right, x, y ); else return root;} // If the binary tree is not searched, but each node has a parent node, the space is changed to the time method. Otherwise, the node * lowestcommonancestor2 (node * X, node * Y) {stack <node *> ST1, st2; while (x) {st1.push (x); X = x-> P;} while (y) {st2.push (y); y = Y-> P ;} Node * plca = NULL; while (! St1.empty ()&&! St2.empty () & () = () {plca = (); st1.pop (); st2.pop ();} return plca ;} // no space for the time method int getlistlength (node * X) {int COUNT = 0; while (x) {++ count; X = x-> P ;} return count;} int myabs (INT Val) {return Val> 0? VAL:-val;} node * lowestcommonancestor3 (node * X, node * Y) {int lengthx = getlistlength (x); int lengthy = getlistlength (y ); node * plong = x, * Pshort = y; If (lengthx <lengthy) {plong = y; Pshort = x ;}for (INT I = 0; I <myabs (lengthx-lengthy); ++ I) plong = plong-> P; while (plong & Pshort & plong! = Pshort) {plong = plong-> P; Pshort = Pshort-> P;} If (plong = Pshort) return plong; return NULL;} // neither a binary search tree nor, there is no parent pointer, but an ordinary Binary Tree bool getnodepath (node * root, node * pnode, list <node *> & Path); node * lowestcommonancestor4 (node * root, node * X, node * Y) {list <node *> path1; List <node *> path2; getnodepath (root, X, path1); getnodepath (root, y, path2); node * plca = NULL; List <node *>: const_iterator it1 = path1.begin (); List <node *> :: Const_iterator it2 = path2.begin (); While (it1! = Path1.end () & it2! = Path2.end () & * it1 = * it2) {plca = * it1; ++ it1; ++ it2;} return plca ;}
9. finding all paths for a specific value in a binary tree requires all paths. The path is the set of nodes from root to a specific node. this is a search with a deep priority principle. we can easily think of sequential traversal. in order to track the path and, we need an additional auxiliary stack to track the operation process of recursive call stack. when we enter the next call to findpath (left) and findpath (right), the recursive stack will press root into the stack, so we also imitate the stack. when findpath (left) and findpath (right) are returned, after the findpath (Root) run cycle ends, the local function variable root will be parsed and the root will pop up from the recursive stack. Therefore, we also pop up the root from the auxiliary stack. We only need to add judgment conditions in the middle to output the results that meet the conditions. changing to an iterative version is also easy.

Void findpath (node * root, int expectedsum, vector <int> & Path, int currentsum); // first traverse the modified void findpath (node * root, int expectedsum) {int currentsum = 0; vector <int> path; findpath (root, expectedsum, path, currentsum);} void findpath (node * root, int expectedsum, vector <int> & Path, int currentsum) // first traverse the modified version {If (! Root) return; // access the root node and add root-> value to the auxiliary stack currentsum + = root-> value; Path. push_back (root-> value); If (root-> left = NULL & root-> right = NULL & currentsum = expectedsum) {for (vector <int >:: size_type I = 0; I <path. size (); ++ I) cout <path [I] <''; cout <Endl;} findpath (root-> left, expectedsum, path, currentsum ); findpath (root-> right, expectedsum, path, currentsum); // In the recursive stack, the parent node is destroyed when the returned result is returned, because the lifecycle of a partial function has reached. // Therefore, the secondary Stack also needs to be synchronized with the recursive stack, so that the top element of the stack is pushed to the stack, and the current path is subtracted from the top element path of the stack. pop_back (); currentsum-= root-> value ;}

10. write a program and put an ordered integer array in a binary tree. This practice is quite strange. Therefore, I chose to insert the breadth first and use the queue to implement it, in fact, you can insert it into a linked list or insert it without knowing it? There are no other things to be truthful and I don't know how to do it.

node* HorizInsert(node* root,node* z){    if(!root)    {        root=z;        return root;    }    queue<node*> q;    q.push(root);    while(!q.empty())    {        node* Front=q.front();        q.pop();        if(Front->left==NULL)        {            Front->left=z;            return root;        }        if(Front->right==NULL)        {            Front->right=z;            return root;        }        if(Front->left)            q.push(Front->left);        if(Front->right)            q.push(Front->right);    }    return root;}

11. it is a typical recursive thinking to judge whether an integer sequence is a result of post-sequential traversal of the Binary Search Tree. The post-sequential traversal is at the end of the tree. Therefore, the binary search tree can be divided into left and right Subtrees by the root, then recursively process the left and right subtree.

// Determine whether the integer sequence is the result of post-order traversal of the Binary Search Tree bool isposttreewalk (int * Last, int Len) {If (! Last | Len <= 0) return false; int root = last [len-1]; int I = 0; while (I <len-1 & last [I] <root) // search for left subtree points + + I; for (Int J = I; j <len-1; ++ J) {If (last [J] <root) // If node <root exists in the right subtree, return false cannot be returned;} bool islasttree = true; if (I> 0) // determine whether the left side is the back sequence tree islasttree = isposttreewalk (last, I); // If the left side is the back sequence tree, continue to judge the right side. If the left side is not, then there is no need to judge if (islasttree & I <len-1) islasttree = isposttreewalk (last + I, len-i-1); Return islasttree ;}

12. the binary tree image is used to draw a special case. We find that we only need to swap the Left and Right pointers of each node (Note: it is not a numerical value. therefore, you can change the pointer when traversing in the first order. There is no order requirement.

// Obtain the image void required rotate (node * root) {If (! Root) return; swap (root-> left, root-> right); then rotate (root-> left );}
13. A binary sorting tree (that is, the binary search tree BST), so that f = (maximum value + minimum value)/2, design an algorithm to find the node closest to the F value and greater than the F value. The complexity should be as low as possible. In BST, the maximum value is the rightmost value, and the minimum value is the leftmost value. In this way, it is easy to find F. can I find the f parent pointer or the right pointer? (I think so). Find the parent pointer here.
// Locate the node closest to and greater than the value of F. Node * finclearf (node * root) {If (! Root) return NULL; node * max, * min; max = min = root; while (min-> left) min = min-> left; while (max-> right) max = max-> right; int F = (min-> value + max-> value)> 1; while (1) {If (root-> value <= f) root = root-> right; else {return root ;}}}
14. converting the binary search tree into a sorted two-way linked list is actually an iterative version of the central traversal, but the code of the Access Node in the middle is changed to the adjustment pointer. this method returns the last pointer of the linked list, lastvist. This is acceptable because it is a double-stranded table.
// Iteration method node * itreetolist (node * root) {node * P = root; stack <node *> st; node * lastvist = NULL; while (p |! St. empty () {While (p) {St. push (p); P = p-> left;} p = ST. top (); ST. pop (); // cout <p-> value <''; If (lastvist) {lastvist-> right = P; P-> left = lastvist ;} lastvist = P; P = p-> right;} return lastvist ;}
15. Print all the paths in the binary tree. Similar to the idea of the front edge, use the auxiliary stack to record the running process of the recursive stack. During the first sequential traversal (Deep Search) process, the leaf node (! Left &&! Right node) to output the content of the secondary stack.

// Output the void outputtreepath (node * root, list <node *> & Path) {If (! Root) return; Path. push_back (Root); If (! Root-> left &&! Root-> right) {for (list <node *>: const_iterator it = path. Begin (); it! = Path. end (); ++ it) cout <(* It)-> value <''; cout <Endl;} outputtreepath (root-> left, PATH ); outputtreepath (root-> right, PATH); // The function lifecycle is up, when the previous layer is returned, // local functions will parse the root (current root node). Correspondingly, the root value from the path should also pop up the path. pop_back ();}
16. find a path from the root to a node in the binary tree. the idea is to use the auxiliary stack to track the running process of the recursive call stack, but the process is different. Add the node to the stack. If a path can be found on the left of the node, if it does not need to be synchronized with the recursive stack (that is, the stack is played), true is returned directly. If such a path is not found on the left side, true is returned. if no such path exists between the left and right, it indicates that this path cannot exist on this node. You need to pop up this node in the auxiliary stack. traverse other nodes. it is also a modified version of sequential traversal.

// Obtain a path bool getnodepath (node * root, node * pnode, list <node *> & Path) from the root to a node in the binary tree) {If (root = pnode) // If root = nnode, done {path. push_back (pnode); Return true;} path. push_back (Root); // 1 use root to implement bool isfound = false; If (root-> left) isfound = getnodepath (root-> left, pnode, PATH ); if (! Isfound & root-> right) isfound = getnodepath (root-> right, pnode, PATH); If (! Isfound) // If the left and right sub-trees in 1 are not found, it indicates that such a path does not exist on the root, and the root should pop up path. pop_back (); Return isfound ;}

17 judging whether the B subtree is the sub-structure of the subtree seems to be a problem. No good solutions have been found yet. Please help me.

// Determine whether B is a sub-structure bool isacontainb (node * roota, node * rootb) {If (! Rootb) return true; If (! Roota) return false; If (roota-> value = rootb-> value) return isacontainb (roota-> left, rootb-> left) & isacontainb (roota-> right, rootb-> right); Return isacontainb (roota-> left, rootb) | isacontainb (roota-> right, rootb );}

18. use the first and middle order results to reconstruct the binary tree to find the root in the first order, use the root to find the Division position in the middle order, then cut the first order into two parts from the Division position, and then recursively.

// Use the first and middle order results to reconstruct the Binary Tree node * rebuildtree (int * prec, int * post, int N) {If (! Prec |! Post | n <1) return NULL; node * root = new node (Prec [0]); int I; for (I = 0; I <n & post [I]! = Prec [0]; ++ I); root-> left = rebuildtree (Prec + 1, post, I); root-> right = rebuildtree (Prec + 1 + I, post + 1 + I, n-i-1); Return root ;}
19. Calculate the number of leaf nodes in a binary tree

void CountLeaves(node* root,int& Count){if(!root ) return ;if(!root->left && !root->right)++Count;CountLeaves(root->left,Count);CountLeaves(root->right,Count);}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.