数据结构中二叉树各种题型详解及程序.docx
- 文档编号:11070319
- 上传时间:2023-02-24
- 格式:DOCX
- 页数:21
- 大小:37.26KB
数据结构中二叉树各种题型详解及程序.docx
《数据结构中二叉树各种题型详解及程序.docx》由会员分享,可在线阅读,更多相关《数据结构中二叉树各种题型详解及程序.docx(21页珍藏版)》请在冰豆网上搜索。
数据结构中二叉树各种题型详解及程序
树是一种比较重要的数据结构,尤其是二叉树。
二叉树是一种特殊的树,在二叉树中每个节点最多有两个子节点,一般称为左子节点和右子节点(或左孩子和右孩子),并且二叉树的子树有左右之分,其次序不能任意颠倒。
二叉树是递归定义的,因此,与二叉树有关的题目基本都可以用递归思想解决,当然有些题目非递归解法也应该掌握,如非递归遍历节点等等。
本文努力对二叉树相关题目做一个较全的整理总结,希望对找工作的同学有所帮助。
二叉树节点定义如下:
structBinaryTreeNode
{
intm_nValue;
BinaryTreeNode*m_pLeft;
BinaryTreeNode*m_pRight;
};
相关链接:
题目列表:
1.求二叉树中的节点个数
2.求二叉树的深度
3.前序遍历,中序遍历,后序遍历
4.分层遍历二叉树(按层次从上往下,从左往右)
5.将二叉查找树变为有序的双向链表
6.求二叉树第K层的节点个数
7.求二叉树中叶子节点的个数
8.判断两棵二叉树是否结构相同
9.判断二叉树是不是平衡二叉树
10.求二叉树的镜像
11.求二叉树中两个节点的最低公共祖先节点
12.求二叉树中节点的最大距离
13.由前序遍历序列和中序遍历序列重建二叉树
14.判断二叉树是不是完全二叉树
详细解答
1.求二叉树中的节点个数
递归解法:
(1)如果二叉树为空,节点个数为0
(2)如果二叉树不为空,二叉树节点个数=左子树节点个数+右子树节点个数+1
参考代码如下:
1.int GetNodeNum(BinaryTreeNode * pRoot)
2.{
3. if(pRoot == NULL) // 递归出口
4. return 0;
5. return GetNodeNum(pRoot->m_pLeft) + GetNodeNum(pRoot->m_pRight) + 1;
6.}
2.求二叉树的深度
递归解法:
(1)如果二叉树为空,二叉树的深度为0
(2)如果二叉树不为空,二叉树的深度=max(左子树深度,右子树深度)+1
参考代码如下:
1.int GetDepth(BinaryTreeNode * pRoot)
2.{
3. if(pRoot == NULL) // 递归出口
4. return 0;
5. int depthLeft = GetDepth(pRoot->m_pLeft);
6. int depthRight = GetDepth(pRoot->m_pRight);
7. return depthLeft > depthRight ?
(depthLeft + 1) :
(depthRight + 1);
8.}
3.前序遍历,中序遍历,后序遍历
前序遍历递归解法:
(1)如果二叉树为空,空操作
(2)如果二叉树不为空,访问根节点,前序遍历左子树,前序遍历右子树
参考代码如下:
1.void PreOrderTraverse(BinaryTreeNode * pRoot)
2.{
3. if(pRoot == NULL)
4. return;
5. Visit(pRoot); // 访问根节点
6. PreOrderTraverse(pRoot->m_pLeft); // 前序遍历左子树
7. PreOrderTraverse(pRoot->m_pRight); // 前序遍历右子树
8.}
中序遍历递归解法
(1)如果二叉树为空,空操作。
(2)如果二叉树不为空,中序遍历左子树,访问根节点,中序遍历右子树
参考代码如下:
1.void InOrderTraverse(BinaryTreeNode * pRoot)
2.{
3. if(pRoot == NULL)
4. return;
5. InOrderTraverse(pRoot->m_pLeft); // 中序遍历左子树
6. Visit(pRoot); // 访问根节点
7. InOrderTraverse(pRoot->m_pRight); // 中序遍历右子树
8.}
后序遍历递归解法
(1)如果二叉树为空,空操作
(2)如果二叉树不为空,后序遍历左子树,后序遍历右子树,访问根节点
参考代码如下:
1.void PostOrderTraverse(BinaryTreeNode * pRoot)
2.{
3. if(pRoot == NULL)
4. return;
5. PostOrderTraverse(pRoot->m_pLeft); // 后序遍历左子树
6. PostOrderTraverse(pRoot->m_pRight); // 后序遍历右子树
7. Visit(pRoot); // 访问根节点
8.}
4.分层遍历二叉树(按层次从上往下,从左往右)
相当于广度优先搜索,使用队列实现。
队列初始化,将根节点压入队列。
当队列不为空,进行如下操作:
弹出一个节点,访问,若左子节点或右子节点不为空,将其压入队列。
1.void LevelTraverse(BinaryTreeNode * pRoot)
2.{
3. if(pRoot == NULL)
4. return;
5. queue
6. q.push(pRoot);
7. while(!
q.empty())
8. {
9. BinaryTreeNode * pNode = q.front();
10. q.pop();
11. Visit(pNode); // 访问节点
12. if(pNode->m_pLeft !
= NULL)
13. q.push(pNode->m_pLeft);
14. if(pNode->m_pRight !
= NULL)
15. q.push(pNode->m_pRight);
16. }
17. return;
18.}
5.将二叉查找树变为有序的双向链表
要求不能创建新节点,只调整指针。
例如如下的二叉搜索树,
若采用中序遍历,其遍历顺序为1-2-3-4-5-6-7,通过适当的指针变换操作,可变成的双向有序链表如下:
递归解法:
(1)如果二叉树查找树为空,不需要转换,对应双向链表的第一个节点是NULL,最后一个节点是NULL
(2)如果二叉查找树不为空:
如果左子树为空,对应双向有序链表的第一个节点是根节点,左边不需要其他操作;
如果左子树不为空,转换左子树,二叉查找树对应双向有序链表的第一个节点就是左子树转换后双向有序链表的第一个节点,同时将根节点和左子树转换后的双向有序链表的最后一个节点连接;
如果右子树为空,对应双向有序链表的最后一个节点是根节点,右边不需要其他操作;
如果右子树不为空,对应双向有序链表的最后一个节点就是右子树转换后双向有序链表的最后一个节点,同时将根节点和右子树转换后的双向有序链表的第一个节点连接。
参考代码如下:
1./******************************************************************************
2.参数:
3.pRoot:
二叉查找树根节点指针
4.pFirstNode:
转换后双向有序链表的第一个节点指针
5.pLastNode:
转换后双向有序链表的最后一个节点指针
6.******************************************************************************/
7.void Convert(BinaryTreeNode * pRoot,
8. BinaryTreeNode * & pFirstNode, BinaryTreeNode * & pLastNode)
9.{
10. BinaryTreeNode *pFirstLeft, *pLastLeft, * pFirstRight, *pLastRight;
11. if(pRoot == NULL)
12. {
13. pFirstNode = NULL;
14. pLastNode = NULL;
15. return;
16. }
17.
18. if(pRoot->m_pLeft == NULL)
19. {
20. // 如果左子树为空,对应双向有序链表的第一个节点是根节点
21. pFirstNode = pRoot;
22. }
23. else
24. {
25. Convert(pRoot->m_pLeft, pFirstLeft, pLastLeft);
26. // 二叉查找树对应双向有序链表的第一个节点就是左子树转换后双向有序链表的第一个节点
27. pFirstNode = pFirstLeft;
28. // 将根节点和左子树转换后的双向有序链表的最后一个节点连接
29. pRoot->m_pLeft = pLastLeft;
30. pLastLeft->m_pRight = pRoot;
31. }
32.
33. if(pRoot->m_pRight == NULL)
34. {
35. // 对应双向有序链表的最后一个节点是根节点
36. pLastNode = pRoot;
37. }
38. else
39. {
40. Convert(pRoot->m_pRight, pFirstRight, pLastRight);
41. // 对应双向有序链表的最后一个节点就是右子树转换后双向有序链表的最后一个节点
42. pLastNode = pLastRight;
43. // 将根节点和右子树转换后的双向有序链表的第一个节点连接
44. pRoot->m_pRight = pFirstRight;
45. pFirstRight->m_pLeft= pRoot;
46. }
47.
48. return;
49.}
6.求二叉树第K层的节点个数
递归解法:
(1)如果二叉树为空或者k<1返回0
(2)如果二叉树不为空并且k==1,返回1
(3)如果二叉树不为空且k>1,返回左子树中k-1层的节点个数与右子树k-1层节点个数之和
参考代码如下:
1.int GetNodeNumKthLevel(BinaryTreeNode * pRoot, int k)
2.{
3. if(pRoot == NULL || k < 1)
4. return 0;
5. if(k == 1)
6. return 1;
7. int numLeft = GetNodeNumKthLevel(pRoot->m_pLeft, k-1); // 左子树中k-1层的节点个数
8. int numRight = GetNodeNumKthLevel(pRoot->m_pRight, k-1); // 右子树中k-1层的节点个数
9. return (numLeft + numRight);
10.}
7.求二叉树中叶子节点的个数
递归解法:
(1)如果二叉树为空,返回0
(2)如果二叉树不为空且左右子树为空,返回1
(3)如果二叉树不为空,且左右子树不同时为空,返回左子树中叶子节点个数加上右子树中叶子节点个数
参考代码如下:
1.int GetLeafNodeNum(BinaryTreeNode * pRoot)
2.{
3. if(pRoot == NULL)
4. return 0;
5. if(pRoot->m_pLeft == NULL && pRoot->m_pRight == NULL)
6. return 1;
7. int numLeft = GetLeafNodeNum(pRoot->m_pLeft); // 左子树中叶节点的个数
8. int numRight = GetLeafNodeNum(pRoot->m_pRight); // 右子树中叶节点的个数
9. return (numLeft + numRight);
10.}
8.判断两棵二叉树是否结构相同
不考虑数据内容。
结构相同意味着对应的左子树和对应的右子树都结构相同。
递归解法:
(1)如果两棵二叉树都为空,返回真
(2)如果两棵二叉树一棵为空,另一棵不为空,返回假
(3)如果两棵二叉树都不为空,如果对应的左子树和右子树都同构返回真,其他返回假
参考代码如下:
1.bool StructureCmp(BinaryTreeNode * pRoot1, BinaryTreeNode * pRoot2)
2.{
3. if(pRoot1 == NULL && pRoot2 == NULL) // 都为空,返回真
4. return true;
5. else if(pRoot1 == NULL || pRoot2 == NULL) // 有一个为空,一个不为空,返回假
6. return false;
7. bool resultLeft = StructureCmp(pRoot1->m_pLeft, pRoot2->m_pLeft); // 比较对应左子树
8. bool resultRight = StructureCmp(pRoot1->m_pRight, pRoot2->m_pRight); // 比较对应右子树
9. return (resultLeft && resultRight);
10.}
9.判断二叉树是不是平衡二叉树
递归解法:
(1)如果二叉树为空,返回真
(2)如果二叉树不为空,如果左子树和右子树都是AVL树并且左子树和右子树高度相差不大于1,返回真,其他返回假
参考代码:
1.bool IsAVL(BinaryTreeNode * pRoot, int & height)
2.{
3. if(pRoot == NULL) // 空树,返回真
4. {
5. height = 0;
6. return true;
7. }
8. int heightLeft;
9. bool resultLeft = IsAVL(pRoot->m_pLeft, heightLeft);
10. int heightRight;
11. bool resultRight = IsAVL(pRoot->m_pRight, heightRight);
12. if(resultLeft && resultRight && abs(heightLeft - heightRight) <= 1) // 左子树和右子树都是AVL,并且高度相差不大于1,返回真
13. {
14. height = max(heightLeft, heightRight) + 1;
15. return true;
16. }
17. else
18. {
19. height = max(heightLeft, heightRight) + 1;
20. return false;
21. }
22.}
10.求二叉树的镜像
递归解法:
(1)如果二叉树为空,返回空
(2)如果二叉树不为空,求左子树和右子树的镜像,然后交换左子树和右子树
参考代码如下:
1.BinaryTreeNode * Mirror(BinaryTreeNode * pRoot)
2.{
3. if(pRoot == NULL) // 返回NULL
4. return NULL;
5. BinaryTreeNode * pLeft = Mirror(pRoot->m_pLeft); // 求左子树镜像
6. BinaryTreeNode * pRight = Mirror(pRoot->m_pRight); // 求右子树镜像
7. // 交换左子树和右子树
8. pRoot->m_pLeft = pRight;
9. pRoot->m_pRight = pLeft;
10. return pRoot;
11.}
11.求二叉树中两个节点的最低公共祖先节点
参考代码如下:
1.bool FindNode(BinaryTreeNode * pRoot, BinaryTreeNode * pNode)
2.{
3. if(pRoot == NULL || pNode == NULL)
4. return false;
5.
6. if(pRoot == pNode)
7. return true;
8.
9. bool found = FindNode(pRoot->m_pLeft, pNode);
10. if(!
found)
11. found = FindNode(pRoot->m_pRight, pNode);
12.
13. return found;
14.}
15.
16.BinaryTreeNode * GetLastCommonParent(BinaryTreeNode * pRoot,
17. BinaryTreeNode * pNode1,
18. BinaryTreeNode * pNode2)
19.{
20. if(FindNode(pRoot->m_pLeft, pNode1))
21. {
22. if(FindNode(pRoot->m_pRight, pNode2))
23. return pRoot;
24. else
25. return GetLastCommonParent(pRoot->m_pLeft, pNode1, pNode2);
26. }
27. else
28. {
29. if(FindNode(pRoot->m_pLeft, pNode2))
30. return pRoot;
31. else
32. return GetLastCommonParent(pRoot->m_pRight, pNode1, pNode2);
33. }
34.}
递归解法效率很低,有很多重复的遍历,下面看一下非递归解法。
非递归解法:
先求从根节点到两个节点的路径,然后再比较对应路径的节点就行,最后一个相同的节点也就是他们在二叉树中的最低公共祖先节点
参考代码如下:
1.bool GetNodePath(BinaryTreeNode * pRoot, BinaryTreeNode * pNode,
2. list
3.{
4. if(pRoot == pNode)
5. return true;
6. if(pRoot == NULL)
7. return false;
8. path.push_back(pRoot);
9. bool found = false;
10. found = GetNodePath(pRoot->m_pLeft, pNode, path);
11. if(!
found)
12. found = GetNodePath(pRoot->m_pRight, pNode, path);
13. if(!
found)
14. path.pop_back();
15. return found;
16.}
17.BinaryTreeNode * GetLastCommonParent(BinaryTreeNode * pRoot,
18. BinaryTreeNode * pNode1,
19. BinaryTreeNode * pNode2)
20.{
21. if(pRoot == NULL || pNode1 == NULL || pNode2 == NULL)
22. return NULL;
23.
24. list
25. GetNodePath(pRoot, pNode1,
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 二叉 各种 题型 详解 程序