其他二叉树知识!二叉树知识汇总


目录

前提知识:

约定:

二叉树节点的存储结构:

创建一个节点:

建立二叉树的几种方法:

一、已知先序遍历顺序,构建二叉树。(链式存储)

二、已知层次遍历顺序,构建二叉树。(链式存储)

三、已知节点关系,建立二叉树(邻接表存储)

四、已知先序和中序遍历顺序,建立二叉树。


前提知识:

约定:

约定二叉树的内容为int类型,并且都>=1,0代表是空节点。我们一般画的二叉树为图一,但是计算机中存储时真实的样子是图二,即需要考虑空节点,不然的话,计算机不知道这个节点已经到头了。

          

例子中树的先序遍历为:1 2 4 3 5 6

若是考虑每个节点的两个空节点,则先序遍历为:1 2 4 0 0 0 3 5 0 0 6 0 0

二叉树节点的存储结构:

struct Node{int data;Node* leftchild;Node* rightchild;
};

一个存储数据的data,左右两个指针都是节点的指针类型。

创建一个节点:

void Create_Node(Node* &t,int x){  //在指针t处生成一个新的节点,内容为xt=new Node;t->data=x;t->leftchild=NULL;t->rightchild=NULL;
}

开辟一个新的Node类型空间,并将地址赋值给指针t。(原来t指向NULL,现在指向了我们生成的新节点,这就是创建节点的过程)

另外新节点*t的左右孩子要指向NULL,这代表节点到此结束,不赋初值会导致一些错误。

参数的问题:

Node * &t 这个参数表示传入的是一个Node类型的指针变量,并且是引用传递,因为我们要修改实参的值,所以要用引用传递。

不懂引用的看这里:https://blog.csdn.net/qq_21989927/article/details/107447970

建立二叉树的几种方法:

一、已知先序遍历顺序,构建二叉树。(链式存储)

这里的先序遍历顺序,必须是包含空节点的,不然是无法确定二叉树的。

样图中的数的先序遍历顺序:1 2 4 0 0 0 3 5 0 0 6 0 0

void Create_Pre(Node* &t){int x; cin>>x;if (x==0) return;else{Create_Node(t,x);Create_Pre(t->leftchild);Create_Pre(t->rightchild);}
}

对于输入的x,若是0,说明是空节点,直接返回return。

若不是空节点,则调用前提知识中的Create_Node函数,在此处创建一个新节点,接着再递归新节点的左右孩子。

因为已知的是先序遍历顺序,所以我们是按先访问根,再访问左右孩子的顺序。

二、已知层次遍历顺序,构建二叉树。(链式存储)

这里又分两种方法:一种是边读入数据边建立二叉树,需要用到队列;另一种是已知的层次遍历顺序在数组中存放好了。

1.使用队列

这种方法样例对应的读入是:1 2 3 4 0 5 6 0 0 0 0 0 0  (0是空节点)

void Create_Level(Node* &t){queue<Node*> q;int x;cin>>x;if (x!=0) {Create_Node(t,x);q.push(t);}while (!q.empty()){Node* s=q.front();cin>>x;if (x!=0){Create_Node(s->leftchild,x);q.push(s->leftchild);}cin>>x;if (x!=0){Create_Node(s->rightchild,x);q.push(s->rightchild);}q.pop();}
}

使用队列的方法,首先要入读一个x,判断这棵树是否存在,若是0,说明空树,不为0,创建节点后入队。

当队列不为空时,队列中每一个元素都需要再读取两个数字(就算是叶子节点也起码也得读两个0)。

这种方法建立二叉树,执行过程中会发现,每次读取的两个数,对应的都是队首元素的左右孩子,这和给定的层次遍历顺序对应。

2.使用数组

给定的层次遍历已经存放在数组中,我们只需要判断一个节点的左右孩子是否存在即可,左孩子为i*2,右孩子为i*2+1。

注意要从a[1]开始存储,a[0]不用。

int a[100]={0,1,2,3,4,0,5,6};
void Create_Tree(Node* &t,int i){if (a[i]==0) return;Create_Node(t,a[i]);if (a[i*2]!=0) Create_Tree(t->leftchild,i*2);if (a[i*2+1]!=0) Create_Tree(t->rightchild,i*2+1);
}

3.两种方法的区别:

建造过程的不同:

利用队列,树是一层一层被构造出来的,对数据的访问也是严格按照层次遍历的顺序执行的;

利用数组,树的构造过程实际上是先根,再左孩子,再右孩子的。通过跳跃访问数组内容,实现的是先序遍历建立二叉树。

输入数据的不同:

如果一棵树如图:

对于队列的方法,   输入为 1 0 3 5 6 0 0 0 0

对于数组的方法,数组中:1 0 3 0 0 5 6 0 0 0 0

因为对于队列来,如果一个节点为空节点,那么自然不会加入队列,也不会再去访问他。

而对于数组来说,要严格执行左孩子是*2,右孩子是*2+1的规则,所以空间浪费会很多。

三、已知节点关系,建立二叉树(邻接表存储)

假设题目输入中,我们只知道 x , y 之间有一条边,但是并不知道 x , y 的父子关系的时候,可以使用邻接表的方法存储树。
这时候把树看做一个图,建边要建双向边,然后在从根做dfs,确定每个节点的深度,顺便也可以求出每个节点的父亲节点,这样节点之间的父子关系就清楚了。

例题:
第一行输入N、root,表示这棵树有N个节点,根为root。
接下来 N-1 行每行包含两个正整数 x, y,表示 x 结点和 y 结点之间有一条直接连接的边(数据保证可以构成树)。

求每个节点的深度和每个节点的父亲节点。

代码:

#include<iostream>
using namespace std;const int MaxN=500050;
struct Edge{int v;int next;
};
Edge e[MaxN];
int last[MaxN];
int n,m,root,tot;
int deep[MaxN];
int f[MaxN];  void build(int x,int y){tot++;e[tot].v=y;e[tot].next=last[x];last[x]=tot;
}//编号为x的节点,父亲是fa
void dfs(int x,int fa){f[x]=fa;deep[x]=deep[fa]+1;for (int j=last[x]; j!=0; j=e[j].next){int y=e[j].v;if (y!=fa) dfs(y,x);      }
}int main(){cin>>n>>root;for (int i=1; i<=n-1; i++){int x,y;cin>>x>>y;build(x,y);build(y,x);}dfs(root,0);for (int i=1; i<=n; i++) cout<<deep[i]<<" "; cout<<endl;for (int i=1; i<=n; i++) cout<<f[i]<<" "; cout<<endl;
} 

此种方法不仅适合二叉树,也适合多叉树。

四、已知先序和中序遍历顺序,建立二叉树。

LeetCode的题目:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/

输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

例如前序遍历 preorder = [3,9,20,15,7]
       中序遍历 inorder = [9,3,15,20,7]
建立如下二叉树并返回根节点。
    3
   / \
  9  20
      /  \
   15   7

思路就是递归分治。 对于一个先序遍历序列,第一个一定是根节点,如样例的3。我们只要在中序遍历序列中找到这个3,那么3之前的都是左子树,之后的都是右子树。再依次递归处理即可。
因为题目说不含重复数字,所以在中序遍历中找根的这个工作可以借助哈希表。
还要注意,因为我们递归的是中序遍历的序列,所以还要再加一个参数用来记录此序列的先序遍历第一个是谁,也就是根节点是谁。

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/
class Solution {
public:unordered_map<int,int> h;TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {int n=inorder.size();for (int i=0; i<n; i++) h[inorder[i]]=i; //哈希求位置TreeNode* head=build(preorder,inorder,0,n-1,0);//0~n-1 根是0return head;}TreeNode* build(vector<int>& preorder,vector<int>& inorder,int l,int r,int g){if (l>r) return NULL;TreeNode* t=new TreeNode(preorder[g]); //构造函数int j=h[preorder[g]]; //在inorder找pre[g]t->left=build(preorder,inorder,l,j-1,g+1);t->right=build(preorder,inorder,j+1,r,g+j-l+1);return t;}
};

建立二叉树:已知层次遍历顺序建立二叉树、已知先序遍历顺序建立二叉树相关推荐

  1. 【中序、后序遍历序列】【前序、中序遍历序列】构造二叉树

    前置知识 第1点:每一个节点都可以看作一棵树的根节点. 第2点:掌握前序.中序.后序遍历顺序.前序遍历:根左右,中序遍历:左根右,后序遍历:左右根. 第3点:掌握双指针或者说滑动窗口,窗口所承载的是左 ...

  2. 二叉树遍历方法——前、中、后序遍历(图解)

    目录 一.前序遍历 (1)递归版本 (2)非递归版本 二.中序遍历 (1)递归版本 (2)非递归版本 三.后序遍历 (1)递归版本 (2)非递归版本 四.总结 五.测试程序 六.程序输出 二叉树的遍历 ...

  3. 二叉树的层序遍历,前序遍历(递归,非递归),中序遍历(递归,非递归),后续遍历(递归,非递归)

    文章目录 二叉树的层序遍历 前序遍历 递归版本 非递归版本 中序遍历 递归版本 非递归版本 后序遍历 递归版本 非递归版本 二叉树的层序遍历 void printTree(BinaryTree* ar ...

  4. golang二叉树的递归和非递归方式的前中后序遍历

    二叉树的递归和非递归方式中序遍历 方法一:递归 思路与算法 首先我们需要了解什么是二叉树的中序遍历:按照访问左子树--根节点--右子树的方式遍历这棵树() (前序和后序遍历方式一样,就是打印root节 ...

  5. 理解——先序遍历是入栈过程,中序遍历是出栈过程

    遇到这样一道题:先序序列为a,b,c,d的不同二叉树的个数是多少? 拿到这个问题 首先,要了解到先序遍历和中序遍历都是需要用到栈,其中,先序遍历是入栈过程,中序遍历是出栈过程 然后,二叉树的先序序列和 ...

  6. 二叉树非递归dfs——简单思路搞定前中后序遍历

    前言:相信很多同学都被二叉树非递归dfs的前中后序遍历方法弄的头疼.网上的答案,什么前中后序遍历各有一套写法,还有什么一个栈的写法,两个栈的写法.看起来能理解,一闭眼自己写都记不住.今天介绍一种用一种 ...

  7. MFC二叉树可视化绘制 (C++)—— 插入、删除、先序遍历、中序遍历、后序遍历、层序遍历(基于平衡二叉树实现)

    界面展示: 相关文章目录 平衡二叉树的构造过程图解 C/C++平衡二叉树实现 -- 插入.删除.先序遍历.中序遍历.后序遍历.层序遍历(设计详解) MFC 在对话框中绘制图形的方法 -- 及二叉树绘制 ...

  8. 树形结构:迭代方式遍历树,宽度优先,先序遍历,中序遍历,后序遍历

    迭代的方式处理树,就必须清楚你将要访问的顺序,对应的就是指针怎么走,你必须很清楚 树的宽度优先搜索,他是一层一层的访问,就搞不清楚怎么划分子问题了,但是你访问的顺序 你很清楚,那么就使用迭代的方式实现 ...

  9. leetcode 589. N 叉树的前序遍历,590. N 叉树的后序遍历(Java版)

    589. N 叉树的前序遍历 https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/ 题解 import java.util.A ...

  10. 数据结构之SWUSTOJ978: 输出利用先序遍历创建的二叉树的中序遍历序列 and SWUSTOJ979: 输出利用先序遍历创建的二叉树的后序遍历序列

    题目: 代码: #include<iostream> using namespace std; typedef struct Binarynode {char data;struct Bi ...

最新文章

  1. Puppet 4 性能提升超2倍,升级前应该你知悉的变化
  2. ACL 2021 | 结构化知识蒸馏方法
  3. Java学习正嗨Day2!
  4. Cassandra1.2文档学习(7)—— 规划集群部署
  5. 让ubuntu使用root帐号并让winscp以root身份登录
  6. 递推DP URAL 1586 Threeprime Numbers
  7. java 前端模板_前端项目模板
  8. 计算机java毕业设计选题汇总(2022)
  9. html变形金刚代码,百度变形金刚JS特效
  10. EditText焦点
  11. mybatis报错:Could not find resource com/**/dao/Mapper.xml
  12. 数码计算机英语单词,数码相机的规格词汇中英对照
  13. 1 -- > PCI / PCIe 配置空间详解
  14. 使用Camera X遇到的坑_OnPause时没有释放相机导致回来时黑屏
  15. 【虚拟机】无法连接虚拟设备 sata0:0,因为主机上没有相应的设备。 您要在每次开启此虚拟机时都尝试连接此虚拟设备吗?
  16. STA series --- 6 .Crosstalk and Noise
  17. 基于Revit铝模板设计-区域配模
  18. 谷歌高质量外链,google英文外链怎么做效果好?
  19. 智能制造并非只是自动化
  20. CentOS6.5 安装CPAN,从而安装perl的各种模块

热门文章

  1. 深入理解iputils网络工具-第5篇 arping:地址解析程序
  2. ARM指令——跳转指令
  3. 文件路径问题( ./ 和 ../ 和 @/ )
  4. Android Studio Buid缓慢问题
  5. 函数指针的用法以及用途详解
  6. 《H3C交换机常用命令》——【华三交换机常用配置及维护命令技能】
  7. 计算机网络的形成和发展
  8. C语言之memcpy()函数
  9. 史上最全Python快速入门教程,让你快速入门python学好python
  10. 丁香园开源接口管理系统 - API Mocker