二叉树常见面试题(进阶) – 滴巴戈

一、共有权题型

1. 两个植物的节的近来公共先人;

2. 求二叉树中最远的两个植物的节的间隔;

3. 由前序遍历和中序遍历使恢复完成二叉树(如:前序序列:1 2 3 4 5 6 – 中序序列 :3 2 4 1 6 5);

4. 断定一棵树即使是完成二叉树 ;

5. 将两叉搜索树替换为排序的双链表。。摈除创办新植物的节,要责任苗条的树中植物的节搀扶的定位;

6.求二叉树的宽度;

7. 断定一棵二叉树即使是均衡二叉树;

8.断定一颗二叉树即使是另一颗树的子树。

二、解题思惟探析

1。两个植物的节的近来协同先人

两个植物的节的近来公共先人可分为三种境况,辨别辩论为:

(1)搜索二叉树,地面搜索二叉树的使具有特点,左子树打中自己人植物的节都不足根植物的节。,右子树的自己人植物的节都大于踵植物的节。。


万一两个植物的节不足根植物的节,反复左子树 ;
万一两个植物的节大于踵植物的节,反复右子树 ;
别的,左子树打中两个植物的节,右子树打中东西,赠送植物的节是近来的协同先人植物的节。。

 1 Node* GetAncestor(Node* root, Node* x1, Node* X2)//1.该二叉树为搜索二叉树 2        {
 3             断言(X1) && X2);
 4if (x1->_data <= root->_data && x2->_data <= root->记载)
 5            {
 6return GetAncestor(根)->_left, x1, X2);//这两个分配不足根植物的节。,左子树打中近来协同先人 7            }
 8elseif (x1->_data > root->_data && x2->_data > root->记载)
 9            {
10return GetAncestor(根)->_right, x1, X2);//这两个分配大于根植物的节。,左子树打中近来协同先人11            }
12else13return root;  //左子树打中东西,右子树打中东西,寻觅协同先人1415         }

(2)三叉神经链,二叉树植物的节有落到父植物的节的搀扶。率先,预约NODE1的父植物的节NODE1->父父植物的节。,话说回来将NoDE1的自己人父植物的节与NoDE2->父植物的节停止有点。,万一发明两个植物的节相当,如此植物的节是近来的协同先人。,直截了当地交还。万一缺乏找到相当的植物的节,则将node2的自己人父植物的节成二列纵队和node1->_parent->_parent作有点……直到node1->_parent==NULL。指定遗传密码列举如下:

 1     struct BinaryNode   //植物的节的作曲
 2     {  
 3         BinaryNode* _left;  
 4         BinaryNode* _right;  
 5         BinaryNode* _parent;  
 6         int _data;  
 7       
 8         BinaryNode(const int& 记载)  
 9             :_data(记载)  
10             , 左(空)  
11             , 右(空)  
12             , 父(空)  
13         {}  
14     };  
 1   Node * GetLastCommonAncestor(Node * root, Node * node1, Node * node2)  
 2    {  
 3         Node * temp;  
 4while (node1 != 空)  
 5        {  
 6             node1 = node1->_parent;  
 7             temp = node2;  
 8while (气温) != 空)  
 9            {  
10if (node1 == temp->父亲)  
11return node1;  
12                 temp = temp->_parent;  
13            }  
14        }  
15     }  

算法的时期复杂的事物为O(n ^ 2)。,O(n)的另类的算法:

假设的的两个植物的节具有父植物的节,乃,这两个植物的节可以考虑是两个链表的头植物的节。,将两个植物的节的近来公共先人植物的节转变为求两链表的交点,两个链表的尾翼植物的节都是根植物的节。。

 1int Hight(BinaryNode* root, BinaryNode* 植物的节)  
 2    {  
 3int len = 0;  
 4for (; node != NULL; node = node->父亲)  
 5             len++;  
 6 7return len;  
 8    }  
 9     BinaryNode* GetLastCommonAncestor(BinaryNode* root, BinaryNode* node1, BinaryNode* node2)  
10    {  
1112if (根) == NULL || node1 == NULL || node2==空)  
13return NULL;  
1415int len1 = Hight(根),node1);  
16int len2 = Hight(根),node2);  
1719for (; len1 > len2; len1--)  
20             node1 = node1->_parent;  
21for (; len2 > len1; len2--)  
22             node2 = node2->_parent;  
2324while (node1 && node2 && node1 != node2)  
25        {  
26             node1 = node1->_parent;  
27             node2 = node2->_parent;  
28        }  
2930if (node1 == node2)  
31return node1;  
32else33return NULL;  
34     }  

(3)普通二叉树,这种境况可采用与搜索二叉树类似物的溶液

从根植物的节开端遍历,万一NoDE1和NoDE2打中少许东西与根婚配,与根婚配的植物的节是最小的的协同先人。。 万一不婚配,话说回来反复左、右子树,万一有东西 植物的节涌现时左子树中,另东西植物的节涌现时右子树中,根是最小的的协同先人。 万一在左子树中涌现两个植物的节,坐果标明,最小协同先人躺左子树中。,别的在右子树中。

 1 Node* GetAncestor(Node* root, Node* x1, Node* X2)
 2        {
 3             断言(X1) && X2);
 4if (根) == 空) {
 5return NULL;
 6            }
 7if (根) == x1 || root == X2) //万一两个植物的节是爷儿俩相干,当选东西植物的节是协同先人。 8            {
 9return root;
10            }
11bool x1inleft, x2inleft, x1inright, x2inright;
12             x1inleft = JudgeNode(根)->_left, X1)  //决定x1即使在左子树中13             x1inright = JudgeNode(根)->_right X1)  //决定x1即使在右子树中14             断言(X1)inleft || x1in右)  //至多有东西是真的15             x2inleft = JudgeNode(根)->_left, X2);  //决定x2即使在左子树中16             x2inright = JudgeNode(根)->_right, X2);  //决定x2即使在右子树中17             assert(x2inleft || x2in右)  //至多有东西是真的18if ((x1inleft && x2inright) || (x1inright && x2inright))
19            {
20return root;  //左子树打中东西,右子树打中东西,寻觅协同先人21            }
22elseif (x1inleft && x2in左)  //这两个分配在左子树中。,左子树打中近来协同先人23            {
24return GetAncestor(根)->_left, x1, X2);
25            }
26else {  //这两个分配在右子树中。,右子树打中近来协同先人27return GetAncestor(根)->_right, x1, X2);
28            }
29         }

上述的方法的时期复杂的事物为O(n ^ 2)。,时期复杂的事物的以下方法是O(n),再必要额定的围绕来记忆路程。。

1) 找到从根到植物的节1的路程,并记忆在矢径或大厦中。
2)找到从根到植物的节2的路程,并记忆在矢径或大厦中。
3) 遍历这两条路程,直到尤指不期而遇差别的植物的节,前面的东西是最小的的协同先人。

 

 1bool GetNodePaths(Node* root, Node* node, stack& s)
 2        {
 3if (根) == 空)
 4            {
 5returnfalse;
 6            }
 7            s.push(根));
 8if (根) == 植物的节)
 9            {
10return true;
11            }
12bool inleft = GetNodePaths(根)->_left, node, s);
13if (in左)
14            {
15returntrue;
16            }
17bool inright = GetNodePaths(根)->_right, node, s);
18if (inright)
19            {
20returntrue;
21            }
22            s.pop();
23returnfalse;
24        }
25         Node* GetAncestor(Node* root, Node* x1, Node* X2);
26        {
27             断言(X1) && X2);
28             stack paths1, paths2;
29if (!GetNodePaths(根)->_left, x1, paths1) || !GetNodePaths(根)->_right, x2, paths2))
30            {
31return NULL;
32            }
else{
while(()>()){
();
}
while(()<()){
();
}

while(!paths1.empty() && !() && ()!=()){
if(()==())
return ();
();
();
}
}
return NULL;
33 }

两个最远的植物的节经过的间隔为2。

在第一种境况下,两个最远的植物的节经过的间隔是SU。,也有可能性从最远的DI经过的两个植物的节经过的路程。,如图所示:

因而不要去想它。,直截了当地表现两个最远的植物的节与间隔的间隔。有两种处理方法:

它依然必要经过两个子树的高压地带来处理。,另一方面整个树的反复,万一在子树中在以第二位种境况,则最大间隔应该是UPD。,时期复杂的事物为O(n ^ 2)。

 1//求二叉树中最远的两个植物的节的间隔 2    size_t MaxLen()
 3    {
 4         size_t maxlen = 0;
 5        _MaxLen(_root, maxlen);
 6return maxlen;
 7    }
 8void _MaxLen(Node* root, size_t maxlen)  //O(N^2) 9    {
10if (根) == 空)
11        {
12return0;
13        }
14int leftdepth = Depth(根)->左)  
15int rightdepth = Depth(根)->右)
16if (leftdepth + rightdepth > maxlen)
17        {
18             maxlen = leftdepth + rightdepth;
19        }
20         _MaxLen(根)->_left, maxlen);
21         _MaxLen(根)->_right, maxlen);
22     }

时期复杂的事物的另类的处理方案是O(n)。:

 1     size_t _MaxLen(Node* root, size_t maxlen)  //O(N) 2    {
 3if (根) == 空)
 4        {
 5return;
 6        }
 7         size_t left = _MaxLen(根)->_left, maxlen);
 8         size_t right = _MaxLen(根)->_right, maxlen);
 9if (right+left>maxlen)
10        {
11             maxlen = right + left;
12        }
13return left > right ? left + 1 : right + 1;
14     }

3. 前序遍历和中序遍历使恢复完成二叉树

如此题是要用一颗二叉树的前序遍历序列和中序遍历序列,如:前序序列:1 2 3 4 5 6 – 中序序列 :3 2 4 1 6 5,来重行构造二叉树。人们可以应用根植物的节的状态特点在前序SE中。。图解解析指引航线列举如下:

创办右子树的方法与。当 prev 遍历前序序列,即二叉树创办填写。指定遗传密码列举如下:

 1//由前序遍历和中序遍历使恢复完成二叉树(如:前序序列:1 2 3 4 5 6 - 中序序列 :3 2 4 1 6 5) 2         Node* RebulidTree(char* prev, char* inbgein, char* inend)
 3        {
 4             断言 && inbgein && inend);
 5if (inbgein > inend || prev == ''\0'')
 6            {
 7return NULL;
 8            }
 9             Node* root = new 植物的节(*PRV)  //率先创办根植物的节10char* div = inbgein;  //让div查找根植物的节11while (DIV) <= inend) {
12if (*div == *前级)
13                {
14if (inbgein <= div -1)
15                    {
16                         root->_left = RebulidTree(++prev, inbgein, div - 1);//反复创办左子树17                    }
18else {
19                         root->_left = NULL;
20                    }
21if (DIV) + 1 <= inend)
22                    {
23                         root->_right = RebulidTree(++prev, div + 1, inend);//反复创办右子树24                    }
25else {
26                         root->_right = NULL;
27                    }
28break;
29                }
30                 ++div;
31            }
32return root;
33         }

4. 断定一棵树即使是完成二叉树

完成二叉树: 前n-1层满,万一在空白,则层N,它在右首掉了,n层最右首的植物的节,在左边是满的。,右首是空的。。

这是东西层序遍历非反复法的变型题,还必要应用额定的围绕来记忆植物的节。。依据层序遍历二叉树,查找第东西非完成植物的节(此植物的节独自地两个案件),这孩子是空的,或许只剩缺乏利息的。,万一前面的植物的节有非满植物的节,则责任。

 1bool IsComplateTree(Node* 根)
 2    {
 3         queue q;
 4if (根))
 5        {
 6             q.push(根));  //率先将植物的节压入队列 7        }
 8//在在这里,万一拉环发表辩论满植物的节,则预约拉环。 9bool tag = true;
10while (!())
11        {
12             Node* front = ();  
13            q.pop();
14//万一非满植物的节曾经涌现,则前面再涌现存的孩子的海里则必然责任完成二叉树。15if (承认)左)
16            {
17if (拉环) == false)
18                {
19returnfalse;
20                }
21                 q.push(承认)左)
22            }
23else {
24                 tag = false;
25            }
26if (承认)右)
27            {
28if (拉环) == false)
29                {
30returnfalse;
31                }
32                 q.push(承认)右)
33            }
34else {
35                 tag = false;
36            }
37        }
38returntrue;
39     }

以第二位种认为方法:将自己人植物的节泊车队列中,究竟什么时候人们断定队列头时,万一队列头是空的,这么JUM,万一尔后队列中而且元素则责任完成二叉树。

 1bool IsCompleteTree(BinaryTreeNode *普罗特)
 2{
 3if(普罗特 == 空)
 4returnfalse;
 5 6           queue q;
 7          q.push(普罗特);
 8           BinaryTreeNode* pCur = ();
 9while(pCUR) != 空)
10          {
11               q.pop();
12                q.push(pCUR) -> 左)
13                q.push(pCUR) -> 右)
14                pCur = ();
15          }
1617           q.pop();//滚出空无所有的防喷器
18//由于有东西空的。,因而假如头不为空就责任完成二叉树19while(! ())
20          {
21if(() != 空)
22returnfalse;
23               q.pop();
24          }
25returntrue;
26 }

5. 将两叉搜索树替换为排序的双链表。

与二叉树的提供线索花化同样

 1void _ToList(Node* cur, Node*& 前级)
 2    {
 3if (库尔 == 空)
 4return;
 5 6         _ToList(库尔->_left, 前级);
 7// 8         cur->_left = prev;
 9if(前级)
10             prev->_right = cur;
1112         prev = cur;
1314         _ToList(库尔->_right, 前级);
15    }
1617     Node* ToList(Node* 根)
18    {
19         Node* prev = NULL;
20        _ToList(根), 前级);
2122         Node* head = root;
23while (头) && head->左)
24        {
25             head = head->_left;
26        }
2728return head;
29     }

6.求二叉树的宽度

同样的的二叉树的宽度是指:二叉树各层植物的节数字的最大值的。

人们知情层序遍历二叉树是应用 queue 来完成的:每回标记东西植物的节后,万一有左子树和右子树,摆布子树被压入 queue,这么此刻的队列中可能性既象征赠送层的植物的节,它还象征下苗圃植物的节。。

人们必要的是东西特派层的植物的节等于。,因而人们必要从结的开端,记载每层的等于,就赠送层的每个植物的节,在树爸后,按下树的左、右子树。 queue,当赠送层整个从队列中爸时,队列中剩的是下苗圃植物的节。。话说回来有点过去的受到的队列大多数和最大宽度。,最大值的是队列的宽度。。期末考试队列是空的,受到的maxWidth执意二叉树的宽度!

 1int 宽度(植物的节) 根)
 2    {
 3         queue q;
 4if (根))
 5            q.push(根));
 6int maxwidth = 1;
 7while (!())    
 8        {
 9int length = ();
10while (上涂料 > 0)    
11            {
12                 Node* front = ();
13                q.pop();
14if (承认)左)
15                {
16                     q.push(承认)左)
17                }
18if (承认)右)
19                {
20                     q.push(承认)右)
21                }
22            }
23             maxwidth = maxwidth > () ? maxwidth : ();
24        }
25return maxwidth;
26     }

7. 二叉树即使是均衡二叉树

二叉树中每东西植物的节的摆布子树高压地带之差均不足2即为均衡二叉树。这么当一颗二叉树的自己人子树都是均衡二叉树时,它本身必定为均衡二叉树,用如此以为可以反复断定。二叉树即使是均衡二叉树。指定遗传密码列举如下:

 1//--断定一棵二叉树即使是均衡二叉树 2bool IsBalance(Node* 根)  //O(N^2) 3    {
 4if (根) == 空)
 5        {
 6returnfalse;
 7        }
 8int left = Depth(根)->左)
 9int right = Depth(根)->右)  
10return ABS(右) - 左) < 2 && IsBalance(根)->左) && IsBalance(根)->右)
11     }

这种方法借助摆布的高压地带有点来决定即使为二叉树,需屡次遍历二叉树,时期复杂的事物为O(n ^ 2)。上面是O(n)的东西算法:

 1bool IsBalance(Node* root, int& 吃水)  //O(N) 2    {
 3if (根) == 空)
 4        {
 5             depth = 0;
 6returntrue; 7        }
 8int leftdepth = 0;
 9if (IsBalance(根)->_left, left吃水) == false)
10        {
11returnfalse;
12        }
13int rightdepth = 0;
14if (IsBalance(根)->_right, right吃水) == false)
15        {
16returnfalse;
17        }
18         depth = rightdepth > leftdepth ? rightdepth + 1 : leftdepth + 1;
19return abs(leftdepth - right吃水) < 2;
20     }

 8.二叉树即使为另一颗树的子树

断定一颗二叉树即使是另一颗树的子树。

 先在找二叉树里找根植物的节,找到后,决定后续植物的节即使相当。,万一相当,它是一棵子树。。

 1bool JudgeNextTree(Node* next, Node* 小孩) //两棵树的原点植物的节的值相当。,安心植物的节即使相当 2    {
 3if (小孩) == 空)
 4        {
 5returntrue;
 6        }
 7if 下一步 == 空)
 8        {
 9returnfalse;
10        }
11if 下一步->_data == child->记载)    //
12        {
13return JudgeNextTree下一步->_left, child->左) && JudgeNextTree下一步->_right, child->右)
14        }
15else {
16returnfalse;  //万一摆布小孩平等的,它是一棵子树。,别的就责任17        }
18    }
19bool JudgeTree(Node* parent, Node* 小孩) //决定孩子即使是双亲的子树20    {
21if (小孩) == 空) //空树是少许树的子树。22        {
23returntrue;
24        }
25if (父亲) == 空)  //空树缺乏空树的子树。26        {
27returnfalse;
28        }
29if (父亲)->_data == child->记载)  //赠送植物的节与找到子树的根植物的节的时期同样的。30        {
31return JudgeNextTree(父亲), 小孩);  //从相当植物的节断定它即使是子树32        }
33elseif (JudgeTree(父亲)->_left, child->左) == true)  //决定赠送植物的节的左子树即使与TH同样的。34        {
35returntrue;
36        }
37else {
38return JudgeTree(父亲)->_right, child->右)  //决定赠送植物的节的右子树即使与39        }
40     }

发表评论

电子邮件地址不会被公开。 必填项已用*标注