数据结构中二叉树各种题型详解及程序
- 格式:docx
- 大小:51.43 KB
- 文档页数:14
实验5:二叉树的建立及遍历(第十三周星期三7、8节)一、实验目的1.学会实现二叉树结点结构和对二叉树的基本操作。
2.掌握对二叉树每种操作的具体实现,学会利用递归方法编写对二叉树这种递归数据结构进行处理的算法。
二、实验要求1.认真阅读和掌握和本实验相关的教材内容。
2.编写完整程序完成下面的实验内容并上机运行。
3.整理并上交实验报告。
三、实验内容1.编写程序任意输入二叉树的结点个数和结点值,构造一棵二叉树,采用三种递归遍历算法(前序、中序、后序)对这棵二叉树进行遍历并计算出二叉树的高度。
2 .编写程序生成下面所示的二叉树,并采用中序遍历的非递归算法对此二叉树进行遍历。
四、思考与提高1.如何计算二叉链表存储的二叉树中度数为1的结点数?2.已知有—棵以二叉链表存储的二叉树,root指向根结点,p指向二叉树中任一结点,如何求从根结点到p所指结点之间的路径?/*----------------------------------------* 05-1_递归遍历二叉树.cpp -- 递归遍历二叉树的相关操作* 对递归遍历二叉树的每个基本操作都用单独的函数来实现* 水上飘2009年写----------------------------------------*/// ds05.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include <iostream>typedef char ElemType;using namespace std;typedef struct BiTNode {ElemType data;//左右孩子指针BiTNode *lchild, *rchild;}BiTNode, *BiTree;//动态输入字符按先序创建二叉树void CreateBiTree(BiTree &T) {char ch;ch = cin.get();if(ch == ' ') {T = NULL;}else {if(ch == '\n') {cout << "输入未结束前不要输入回车,""要结束分支请输入空格!" << endl;}else {//生成根结点T = (BiTNode * )malloc(sizeof(BiTNode));if(!T)cout << "内存分配失败!" << endl;T->data = ch;//构造左子树CreateBiTree(T->lchild);//构造右子树CreateBiTree(T->rchild);}}}//输出e的值ElemType PrintElement(ElemType e) { cout << e << " ";return e;}//先序遍历void PreOrderTraverse(BiTree T) { if (T != NULL) {//打印结点的值PrintElement(T->data);//遍历左孩子PreOrderTraverse(T->lchild);//遍历右孩子PreOrderTraverse(T->rchild);}}//中序遍历void InOrderTraverse(BiTree T) {if (T != NULL) {//遍历左孩子InOrderTraverse(T->lchild);//打印结点的值PrintElement(T->data);//遍历右孩子InOrderTraverse(T->rchild);}}//后序遍历void PostOrderTraverse(BiTree T) { if (T != NULL) {//遍历左孩子PostOrderTraverse(T->lchild);//遍历右孩子PostOrderTraverse(T->rchild);//打印结点的值PrintElement(T->data);}}//按任一种遍历次序输出二叉树中的所有结点void TraverseBiTree(BiTree T, int mark) {if(mark == 1) {//先序遍历PreOrderTraverse(T);cout << endl;}else if(mark == 2) {//中序遍历InOrderTraverse(T);cout << endl;}else if(mark == 3) {//后序遍历PostOrderTraverse(T);cout << endl;}else cout << "选择遍历结束!" << endl;}//输入值并执行选择遍历函数void ChoiceMark(BiTree T) {int mark = 1;cout << "请输入,先序遍历为1,中序为2,后序为3,跳过此操作为0:";cin >> mark;if(mark > 0 && mark < 4) {TraverseBiTree(T, mark);ChoiceMark(T);}else cout << "此操作已跳过!" << endl;}//求二叉树的深度int BiTreeDepth(BiTNode *T) {if (T == NULL) {//对于空树,返回0并结束递归return 0;}else {//计算左子树的深度int dep1 = BiTreeDepth(T->lchild);//计算右子树的深度int dep2 = BiTreeDepth(T->rchild);//返回树的深度if(dep1 > dep2)return dep1 + 1;elsereturn dep2 + 1;}}int _tmain(int argc, _TCHAR* argv[]){BiTNode *bt;bt = NULL; //将树根指针置空cout << "输入规则:" << endl<< "要生成新结点,输入一个字符,""不要生成新结点的左孩子,输入一个空格,""左右孩子都不要,输入两个空格,""要结束,输入多个空格(越多越好),再回车!"<< endl << "按先序输入:";CreateBiTree(bt);cout << "树的深度为:" << BiTreeDepth(bt) << endl;ChoiceMark(bt);return 0;}/*----------------------------------------* 05-2_构造二叉树.cpp -- 构造二叉树的相关操作* 对构造二叉树的每个基本操作都用单独的函数来实现* 水上飘2009年写----------------------------------------*/// ds05-2.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include <iostream>#define STACK_INIT_SIZE 100 //栈的存储空间初始分配量#define STACKINCREMENT 10 //存储空间分配增量typedef char ElemType; //元素类型using namespace std;typedef struct BiTNode {ElemType data; //结点值BiTNode *lchild, *rchild; //左右孩子指针}BiTNode, *BiTree;typedef struct {BiTree *base; //在栈构造之前和销毁之后,base的值为空BiTree *top; //栈顶指针int stacksize; //当前已分配的存储空间,以元素为单位}SqStack;//构造一个空栈void InitStack(SqStack &s) {s.base = (BiTree *)malloc(STACK_INIT_SIZE * sizeof(BiTree));if(!s.base)cout << "存储分配失败!" << endl;s.top = s.base;s.stacksize = STACK_INIT_SIZE;}//插入元素e为新的栈顶元素void Push(SqStack &s, BiTree e) {//栈满,追加存储空间if ((s.top - s.base) >= s.stacksize) {s.base = (BiTree *)malloc((STACK_INIT_SIZE+STACKINCREMENT) * sizeof(BiTree));if(!s.base)cout << "存储分配失败!" << endl;s.top = s.base + s.stacksize;s.stacksize += STACK_INIT_SIZE;}*s.top++ = e;}//若栈不空,则删除s的栈顶元素,并返回其值BiTree Pop(SqStack &s) {if(s.top == s.base)cout << "栈为空,无法删除栈顶元素!" << endl;s.top--;return *s.top;}//按先序输入字符创建二叉树void CreateBiTree(BiTree &T) {char ch;//接受输入的字符ch = cin.get();if(ch == ' ') {//分支结束T = NULL;} //if' 'endelse if(ch == '\n') {cout << "输入未结束前不要输入回车,""要结束分支请输入空格!(接着输入)" << endl;} //if'\n'endelse {//生成根结点T = (BiTNode * )malloc(sizeof(BiTree));if(!T)cout << "内存分配失败!" << endl;T->data = ch;//构造左子树CreateBiTree(T->lchild);//构造右子树CreateBiTree(T->rchild);} //Create end}//输出e的值,并返回ElemType PrintElement(ElemType e) {cout << e << " ";return e;}//中序遍历二叉树的非递归函数void InOrderTraverse(BiTree p, SqStack &S) {cout << "中序遍历结果:";while(S.top != S.base || p != NULL) {if(p != NULL) {Push(S,p);p = p->lchild;} //if NULL endelse {BiTree bi = Pop(S);if(!PrintElement(bi->data))cout << "输出其值未成功!" << endl;p = bi->rchild;} //else end} //while endcout << endl;}int _tmain(int argc, _TCHAR* argv[]){BiTNode *bt;SqStack S;InitStack(S);bt = NULL; //将树根指针置空cout << "老师要求的二叉树序列(‘空’表示空格):""12空空346空空空5空空,再回车!"<< endl << "请按先序输入一个二叉树序列(可另输入,但要为先序),""无左右孩子则分别输入空格。
二叉树算法题
题目一:二叉树的深度
给定一个二叉树,找出其最大深度。
示例:
输入:
# 定义二叉树节点
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
# 创建二叉树
root = TreeNode(3)
root.left = TreeNode(9)
root.right = TreeNode(20)
root.right.left = TreeNode(15)
root.right.right = TreeNode(7)
输出:
4
解释:二叉树的深度为4,分别是 [3], [9, 20], [15, 7] 和 []。
提示:递归深度优先搜索 (DFS) 是一个有效的解决方案。
对于每个节点,我们可以递归地计算其左子树和右子树的深度,然后返回最大的深度。
为了避免重复计算,我们可以使用一个队列来存储已访问的节点。
在计算深度的过程中,我们需要跟踪当前的深度。
当我们到达一个节点的深度时,我们就可以从队列中删除它,因为我们不需要再次计算它。
为了避免进入无限循环,我们需要在算法中使用一个变量来记录访问过的节点数量,如果超过了树中的节点数量,我们可以提前返回结果。
一、基础知识题6.1设树T的度为4,其中度为1,2,3和4的结点个数分别为4,2,1,1,求树T中的叶子数。
【解答】设度为m的树中度为0,1,2,…,m的结点数分别为n0, n1, n2,…, nm,结点总数为n,分枝数为B,则下面二式成立n= n0+n1+n2+…+nm (1)n=B+1= n1+2n2 +…+mnm+1 (2)由(1)和(2)得叶子结点数n0=1+即: n0=1+(1-1)*4+(2-1)*2+(3-1)*1+(4-1)*1=86.2一棵完全二叉树上有1001个结点,求叶子结点的个数。
【解答】因为在任意二叉树中度为2 的结点数n2和叶子结点数n0有如下关系:n2=n0-1,所以设二叉树的结点数为n, 度为1的结点数为n1,则n= n0+ n1+ n2n=2n0+n1-11002=2n0+n1由于在完全二叉树中,度为1的结点数n1至多为1,叶子数n0是整数。
本题中度为1的结点数n1只能是0,故叶子结点的个数n0为501.注:解本题时要使用以上公式,不要先判断完全二叉树高10,前9层是满二叉树,第10层都是叶子,……。
虽然解法也对,但步骤多且复杂,极易出错。
6.3 一棵124个叶结点的完全二叉树,最多有多少个结点。
【解答】由公式n=2n0+n1-1,当n1为1时,结点数达到最多248个。
6.4.一棵完全二叉树有500个结点,请问该完全二叉树有多少个叶子结点?有多少个度为1的结点?有多少个度为2的结点?如果完全二叉树有501个结点,结果如何?请写出推导过程。
【解答】由公式n=2n0+n1-1,带入具体数得,500=2n0+n1-1,叶子数是整数,度为1的结点数只能为1,故叶子数为250,度为2的结点数是249。
若完全二叉树有501个结点,则叶子数251,度为2的结点数是250,度为1的结点数为0。
6.5 某二叉树有20个叶子结点,有30个结点仅有一个孩子,则该二叉树的总结点数是多少。
数据结构二叉树先序中序后序考研题目
摘要:
一、二叉树的基本概念和性质
二、二叉树的遍历方式
三、考研题目中关于二叉树的问题
正文:
一、二叉树的基本概念和性质
二叉树是一种非常重要的数据结构,在计算机科学中有着广泛的应用。
它由一个根节点和两个子节点组成,每个节点也可以有零个或多个子节点。
二叉树具有以下几个重要的性质:
1.每个节点最多只有两个子节点,即左子节点和右子节点。
2.所有节点的左子节点都比它小,所有节点的右子节点都比它大。
3.每个节点的左子树和右子树也是二叉树。
二、二叉树的遍历方式
二叉树的遍历方式有三种:先序遍历、中序遍历和后序遍历。
先序遍历:根节点- > 左子树- > 右子树
中序遍历:左子树- > 根节点- > 右子树
后序遍历:左子树- > 右子树- > 根节点
三、考研题目中关于二叉树的问题
在考研题目中,关于二叉树的问题通常涉及以下几个方面:
1.二叉树的遍历:要求根据二叉树的结构,写出其先序遍历、中序遍历或
后序遍历。
2.二叉树的应用:要求利用二叉树解决具体问题,例如求二叉树的高度、求两个二叉树的最近公共祖先等。
3.二叉树的结构:要求根据二叉树的遍历结果,画出其结构图或者判断其是否存在。
以上就是关于数据结构中二叉树的基本概念、遍历方式和在考研题目中的应用的介绍。
二叉树前中后序遍历做题技巧在计算机科学中,二叉树是一种重要的数据结构,而前序、中序和后序遍历则是二叉树遍历的三种主要方式。
下面将分别对这三种遍历方式进行解析,并提供一些解题技巧。
1.理解遍历顺序前序遍历顺序是:根节点->左子树->右子树中序遍历顺序是:左子树->根节点->右子树后序遍历顺序是:左子树->右子树->根节点理解每种遍历顺序是解题的基础。
2.使用递归或迭代二叉树的遍历可以通过递归或迭代实现。
在递归中,每个节点的处理函数会调用其左右子节点的处理函数。
在迭代中,可以使用栈来模拟递归过程。
3.辨析指针指向在递归或迭代中,需要正确处理指针的指向。
在递归中,通常使用全局变量或函数参数传递指针。
在迭代中,需要使用栈或其他数据结构保存指针。
4.学会断点续传在处理大规模数据时,为了避免内存溢出,可以采用断点续传的方式。
即在遍历过程中,将中间结果保存在文件中,下次遍历时从文件中读取上一次的结果,继续遍历。
5.识别循环和终止条件在遍历二叉树时,要识别是否存在循环,并确定终止条件。
循环可以通过深度优先搜索(DFS)或广度优先搜索(BFS)避免。
终止条件通常为达到叶子节点或达到某个深度限制。
6.考虑边界情况在处理二叉树遍历问题时,要考虑边界情况。
例如,对于空二叉树,需要进行特殊处理。
又如,在处理二叉搜索树时,需要考虑节点值的最小和最大边界。
7.优化空间使用在遍历二叉树时,需要优化空间使用。
例如,可以使用in-place排序来避免额外的空间开销。
此外,可以使用懒加载技术来延迟加载子节点,从而减少内存占用。
8.验证答案正确性最后,验证答案的正确性是至关重要的。
可以通过检查输出是否符合预期、是否满足题目的限制条件等方法来验证答案的正确性。
如果可能的话,也可以使用自动化测试工具进行验证。
以下是10道关于二叉树的归纳总结题目:
1. 二叉树是一种特殊的树形数据结构,每个节点最多有两个子节点,通常称为左子节点和右子节点。
请简述二叉树的定义和特点。
2. 二叉树的遍历是二叉树操作的重要部分,常见的二叉树遍历方式有哪些?请列举并简述它们的含义和操作过程。
3. 什么是二叉树的先序遍历、中序遍历和后序遍历?请给出它们的递归实现方式。
4. 什么是二叉树的深度优先搜索(DFS)和广度优先搜索(BFS)?请分别给出它们的实现方式。
5. 什么是二叉树的平衡?如何判断一棵二叉树是否平衡?请给出判断平衡二叉树的算法。
6. 如何通过迭代方法将一个满二叉树转换为二叉搜索树?请给出详细的算法步骤。
7. 给定一棵二叉搜索树的根节点,如何找到中序遍历的最后一个节点?请给出算法步骤。
8. 如何将一个有序数组转换为二叉搜索树?请给出详细的算法步骤。
9. 什么是二叉树的线索化?如何将一棵二叉树线索化?请给出算法步骤。
10. 在一个无向图中,给定一个节点,如何找到与其距离为k
的所有节点?请给出算法步骤。
以上题目涵盖了二叉树的基本概念、遍历、搜索、转换、线索化和图算法等知识点,可以帮助你更好地理解二叉树数据结构的性质和应用。
数据结构二叉树先序中序后序考研题目在考研所涉及的数据结构中,二叉树以及与之相关的先序、中序和后序遍历是一个重要的考察点。
通过对二叉树的各种遍历方式的理解和掌握,可以帮助考生更好地理解树这个数据结构,提高解题的效率和正确率。
本文将针对数据结构中关于二叉树先序、中序和后序遍历的考研题目进行深入探讨,并希望能为考生提供一些帮助和启发。
一、先序、中序和后序遍历的概念在开始具体讨论考研题目之前,我们先来回顾一下先序、中序和后序遍历的概念。
在二叉树中,所谓的先序、中序和后序遍历,是指对二叉树中的节点进行遍历的顺序方式。
1. 先序遍历:先访问根节点,然后依次递归地访问左子树和右子树。
在遍历过程中,对于任一节点,先访问该节点,然后再访问其左右子树。
2. 中序遍历:先递归地访问左子树,然后访问根节点,最后再递归地访问右子树。
在遍历过程中,对于任一节点,先访问其左子树,然后访问该节点,最后再访问其右子树。
3. 后序遍历:先递归地访问左子树,然后再递归地访问右子树,最后再访问根节点。
在遍历过程中,对于任一节点,先访问其左右子树,然后再访问该节点。
二、考研题目解析1. 题目一:给出一个二叉树的中序遍历和后序遍历序列,构建该二叉树。
这是一个典型的二叉树重建题目,考查对中序和后序遍历结果的理解和利用。
解题的关键在于根据后序遍历序列确定根节点,在中序遍历序列中找到对应的根节点位置,然后再将中序遍历序列分为左右两个子树部分,分别递归构建左右子树。
考生需要对二叉树遍历的特点有清晰的认识,以及对递归构建树结构有一定的掌握。
2. 题目二:给出一个二叉树的先序遍历和中序遍历序列,构建该二叉树。
这个题目与上一个题目相似,同样是考察对二叉树重建的理解和应用。
解题思路也类似,首先根据先序遍历的结果确定根节点,在中序遍历序列中找到对应的根节点位置,然后递归构建左右子树。
需要注意的是,先序遍历序列的第一个元素即为根节点,而中序遍历序列中根节点的左边是左子树,右边是右子树。
在Python中实现二叉树时,可能会遇到各种问题。
以下是一些常见的问题以及相应的解决方法:1. 定义节点类:问题:如何定义一个节点类,以便每个节点都有一个数据元素和一个指向左右子节点的引用?解决方法:python`class Node:def __init__(self, data):self.left = Noneself.right = Noneself.data = data`2. 插入节点:问题:如何插入新的节点到二叉树中?解决方法:python`def insert(root, data):if root is None:return Node(data)else:if data < root.data:root.left = insert(root.left, data)else:root.right = insert(root.right, data)return root`3. 遍历:问题:如何遍历二叉树?例如,前序遍历、中序遍历和后序遍历。
解决方法:对于前序遍历,可以使用递归或迭代。
中序遍历和后序遍历也可以使用类似的方法。
4. 查找:问题:如何在二叉树中查找一个特定的值?解决方法:可以通过递归或迭代进行搜索。
在每个节点处,如果当前节点的值与要查找的值匹配,则返回该节点。
否则,如果当前节点的左子节点不为空,则在左子树中查找;如果右子节点不为空,则在右子树中查找。
如果都没有找到,则返回None。
5. 删除节点:问题:如何从二叉树中删除一个节点?解决方法:这通常涉及到三种情况:要删除的节点是叶子节点、有一个子节点和一个没有子节点。
根据这些情况,需要处理不同的逻辑。
需要注意的是,删除节点后可能需要调整其他节点的引用。
6. 平衡:问题:如何确保二叉树在插入新节点时保持平衡,以防止过度倾斜?解决方法:可以使用平衡二叉搜索树(例如AVL树、红黑树等)或二叉堆来确保二叉树的平衡。
这些数据结构提供了更复杂的操作和更严格的平衡条件。
⼆叉树的⼏个经典例题⼆叉树遍历1题⽬描述编⼀个程序,读⼊⽤户输⼊的⼀串先序遍历字符串,根据此字符串建⽴⼀个⼆叉树(以指针⽅式存储)。
例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表⽰的是空格,空格字符代表空树。
建⽴起此⼆叉树以后,再对⼆叉树进⾏中序遍历,输出遍历结果。
输⼊描述:输⼊包括1⾏字符串,长度不超过100。
输出描述:可能有多组测试数据,对于每组数据,输出将输⼊字符串建⽴⼆叉树后中序遍历的序列,每个字符后⾯都有⼀个空格。
每个输出结果占⼀⾏。
输⼊abc##de#g##f###输出c b e gd f a思路:递归建树。
每次都获取输⼊字符串的当前元素,根据题⽬要求(先序、中序、后序等+其他限制条件)建树。
再根据题⽬要求输出即可。
1 #include<bits/stdc++.h>2using namespace std;3struct node{4char data;5 node *lchild,*rchild;6 node(char c):data(c),lchild(NULL),rchild(NULL){}7 };8string s;9int loc;10 node* create(){11char c=s[loc++];//获取每⼀个字符串元素12if(c=='#') return NULL;13 node *t=new node(c);//创建新节点14 t->lchild=create();15 t->rchild=create();16return t;17 }18void inorder(node *t){//递归中序19if(t){20 inorder(t->lchild);21 cout<<t->data<<'';22 inorder(t->rchild);23 }24 }25int main(){26while(cin>>s){27 loc=0;28 node *t=create();//先序遍历建树29 inorder(t);//中序遍历并输出30 cout<<endl;31 }32return0;33 }⼆叉树遍历2题⽬描述⼆叉树的前序、中序、后序遍历的定义:前序遍历:对任⼀⼦树,先访问跟,然后遍历其左⼦树,最后遍历其右⼦树;中序遍历:对任⼀⼦树,先遍历其左⼦树,然后访问根,最后遍历其右⼦树;后序遍历:对任⼀⼦树,先遍历其左⼦树,然后遍历其右⼦树,最后访问根。
第 6 章树和二叉树1.选择题( 1)把一棵树变换为二叉树后,这棵二叉树的形态是()。
A.独一的B.有多种C.有多种,但根结点都没有左孩子D.有多种,但根结点都没有右孩子( 2)由 3 个结点能够结构出多少种不一样的二叉树?()A. 2 B . 3 C . 4 D. 5( 3)一棵完整二叉树上有1001 个结点,此中叶子结点的个数是()。
A. 250 B . 500 C . 254 D. 501( 4)一个拥有 1025 个结点的二叉树的高h 为()。
A. 11 B . 10 C.11 至 1025 之间 D .10 至 1024 之间( 5)深度为 h 的满 m叉树的第 k 层有()个结点。
(1=<k=<h)k-1B kCh-1 hA. m . m-1 . m D.m-1( 6)利用二叉链表储存树,则根结点的右指针是()。
A.指向最左孩子 B .指向最右孩子 C .空 D .非空( 7)对二叉树的结点从 1 开始进行连续编号,要求每个结点的编号大于其左、右孩子的编号,同一结点的左右孩子中,其左孩子的编号小于其右孩子的编号,可采纳()遍历实现编号。
A.先序 B. 中序 C. 后序 D.从根开始按层次遍历(8)若二叉树采纳二叉链表储存结构,要互换其全部分支结点左、右子树的地点,利用()遍历方法最适合。
A.前序B.中序C.后序D.按层次(9)在以下储存形式中,()不是树的储存形式?A.双亲表示法 B .孩子链表表示法 C .孩子兄弟表示法D.次序储存表示法( 10)一棵非空的二叉树的先序遍历序列与后序遍历序列正好相反,则该二叉树必定满足()。
A.全部的结点均无左孩子B.全部的结点均无右孩子C.只有一个叶子结点D.是随意一棵二叉树( 11)某二叉树的前序序列和后序序列正好相反,则该二叉树必定是()的二叉树。
A.空或只有一个结点B.任一结点无左子树C.高度等于其结点数 D .任一结点无右子树( 12)若 X 是二叉中序线索树中一个有左孩子的结点,且 X 不为根,则 X 的前驱为()。
树是一种比较重要的数据结构,尤其是二叉树。
二叉树是一种特殊的树,在二叉树中每个节点最多有两个子节点,一般称为左子节点和右子节点(或左孩子和右孩子),并且二叉树的子树有左右之分,其次序不能任意颠倒。
二叉树是递归定义的,因此,与二叉树有关的题目基本都可以用递归思想解决,当然有些题目非递归解法也应该掌握,如非递归遍历节点等等。
本文努力对二叉树相关题目做一个较全的整理总结,希望对找工作的同学有所帮助。
二叉树节点定义如下:struct BinaryTreeNode{int m_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<BinaryTreeNode *> q;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.else24. {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.else39. {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)7. int numLeft = GetLeafNodeNum(pRoot->m_pLeft); // 左子树中叶节点的个数8. int numRight = GetLeafNodeNum(pRoot->m_pRight); // 右子树中叶节点的个数9.return (numLeft + numRight);10.}8. 判断两棵二叉树是否结构相同不考虑数据内容。