如何建树?

二叉树-建树-方式一

dfs使用root左右指针建立树节点关系,返回根节点root

二叉树-建树-方式二

dfs使用二维数组,int nds[n][2],如:nds[i][0]表示i节点的左子节点,nds[i][1]表示i节点的右子节点

树-建树

dfs使用邻接表保存树节点关系,vector nds[n],如:nds[i][j]表示节点i的子节点j

二叉查找树-建树

二叉查找树-建树-方式一:前序序列

如前序序列:8 6 5 7 10 8 11

8是根节点

左子树:从6开始往后找小于8的都为8的左子树节点

右子树:从最后一位11开始往前找大于8的都为8的右子树节点

继续递归过程,直到完成建树

node * create(int preL,int preR){
if(preL>preR)return NULL;
node * root = new node(pre[preL]);
int k=preL+1;
while(k<preR&&abs(pre[k])<=abs(pre[preL]))k++;//找第一个大于根节点的值
root->f=create(preL+1,k-1);
root->r=create(k,preR);
return root;
}

二叉查找树-建树-方式二:依次插入

非递归

node * root;
void insert(int n) {
if(root==NULL) {
root=new node(n,1);
return;
}
node * p=root;
while(p!=NULL) {
if(p->data<n) {
if(p->right==NULL){
p->right=new node(n,p->h+1);
return;
}
else p=p->right;
} else {
if(p->left==NULL){
p->left=new node(n,p->h+1);
return;
}
else p=p->left;
}
}
}

递归

void insert(node* &root, int data, int dep) {
if(root == NULL) { //到达空结点时,即为需要插入的位置
root = new node(data,dep);
root->data = data;
root->left = root->right = NULL; //此句不能漏
return;
}
if(data <= root->data) insert(root->left, data, root->h+1); //插在左子树
else insert(root->right, data, root->h+1); //插在右子树
}

完全二叉查找树建树

完全二叉查找树,任意节点序列建树

注:二叉查找树(不一定要完全二叉树)任意节点序列,升序排序,即为二叉查找树的中序序列

  1. 方式一:模拟递归打印中序序列的过程,将中序序列依次插入到数组建树
  2. 方式二:找root在中序序列中的位置k并将root保存到数组,递归处理startk-1左子树和k+1end右子树,完成建树
void inOrder(int root) { //root保存在1位置,index初始化为0
if(root>n) return;
inOrder(root*2);
CBT[root]=number[index++];
inOrder(root*2+1);
}

方式二

void getLevel(int start, int end, int index) {
if(start>end)return;
int n=end-start+1;
int l=log(n+1)/log(2);//最后一层的层数
int leave=n-(pow(2,l)-1); //最后一层叶子结点数
//pow(2, l - 1) - 1是除了root结点所在层和最后?层外,左?树的结点个数,pow(2, l - 1) 是l+1
//层最多拥有的属于根结点左?树的结点个数,min(pow(2, l - 1), leave)是最后?个结点真正拥有的
//属于根结点左?树上的结点个数
int root = start+(pow(2,l-1)-1)+min((int)pow(2,l-1),leave);
level[index]=in[root];
getLevel(start,root-1,2*index+1);
getLevel(root+1,end,2*index+2); }

序列转换

前序后序转中序

后序倒数第一个节点为根root,root在前序中为第一个节点

后序倒数第二个节点为root的右子树的根节点rightTreeRoot,rightTreeRoot在前序中将序列分为左边部分(root和root的左子树),右边部分(root的右子树包含rightTreeRoot)

若rightTreeRoot前只有一个节点,那么说明该rightTreeRoot的父节点root只有一个子节点,即rightTreeRoot既可以为root的左子节点也可以为root的右子节点

node * create(int preL,int preR,int postL,int postR) {
if(preL>preR)return NULL;
node * root = new node;
root->data=post[postR];
root->left=NULL;
root->right=NULL;
if(preL==preR)return root;
int k=preL+1;
while(k<=preR&&pre[k]!=post[postR-1])k++;
if(k-preL>1) {
root->left=create(preL+1,k-1,postL,postL+(k-preL-1)-1);
root->right=create(k,preR,postL+(k-preL-1),postR-1);
} else {
unique = false;
root->right=create(k,preR,postL+(k-preL-1),postR-1);
}
return root;
}

前序中序转后序

前序第一个节点为根root,root在中序中位置为k,将序列分为左边部分(root的左子树),右边部分(root的右子树)

inLk-1为下次左递归的后序序列,其对应的后序序列为preL+1preL+(k-inL);

k+1inR为下次递归的后序序列,其对应的后序序列为postL+(k-inL)+1preR;

void postFirst(int inL,int inR, int preL,int preR) {
if(inL>inR||flag) return;
int k=inL;
while(k<inR&&in[k]!=pre[preL])k++;
postFirst(inL, k-1, preL+1, preL+(k-inL));
postFirst(k+1, inR, preL+(k-inL)+1, preR);
if(flag==false) {
printf("%d", pre[preL]);
flag=true;
}
}

后序中序转前序

后序第一个节点为根root,root在中序中位置为k,将序列分为左边部分(root的左子树),右边部分(root的右子树)

inLk-1为下次左递归的后序序列,其对应的后序序列为postLpostL+(k-inL)-1;

k+1inR为下次递归的后序序列,其对应的后序序列为postL+(k-inL)postR-1;

node * create(int postL,int postR,int inL,int inR) {
if(postL>postR)return NULL;
node * root=new node;
root->data=post[postR];
// 找到当前根节点在中序遍历中的位置
int i;
for(i=inL; i<=inR; i++) {
if(post[postR]==in[i])
break;
}
int numLeft=i-inL;
root->left=create(postL,postL+numLeft-1,inL,inL+numLeft-1);//inL+numLeft=i
root->right=create(postL+numLeft,postR-1,inL+numLeft+1,inR);//inL+numLeft=i
return root;
}

二叉查找树前序转后序

二叉查找树前序序列

  • pre[0]为root
  • 从pre[1]开始第一个大于root的值(位置为k,pre[1]pre[k-1]即为root左子树)
  • 从pre[N-1]开始第一个小于root的值(位置为k,pre[k+1]pre[N-1]即为root右子树)
void getPost(int root, int tail) {
if(root>tail)return;
int i=root+1;
int j=tail;
if(!isMirror) {
while(i<=tail&&pre[i]<pre[root])i++;
while(j>root&&pre[j]>=pre[root])j--;
} else {
while(i<=tail&&pre[i]>=pre[root])i++;
while(j>root&&pre[j]<pre[root])j--;
}
if(i-j!=1)return;
getPost(root+1,j);//左子树
getPost(i,tail); //右子树
post.push_back(pre[root]);
}

如何进行层级遍历序列?

方式一

建树,借助队列层级遍历

方式二

建树时,记录index到结点(如:节点i的左子节点index=2i+1,节点i的右子节点index=2i+2),之后节点index升序排序,依次打印即为层序序列

如何记录层级?

DFS中如何记录层级?如何记录每层叶子节点数?

记录层级-方式一-辅助数组

dfs函数参数中记录当前处理节点的层级,使用int max_h记录最大层数方便后续层级遍历,可使用int leaf[n]记录对应层级叶子节点数

void dfs(int index,int h) {
max_h=max(h,max_h);//记录最大层数
if(nds[index].size()==0) { //叶子节点
leaf[h]++;
return;
}
for(int i=0; i<nds[index].size(); i++) {
dfs(nds[index][i],h+1);
}
}

记录层级-方式二-结构体中定义层级变量

struct node {
int data;
node * left;
node * right;
int depth;
};
void dfs(node * root) {
queue<node*> q;
root->depth=0;
q.push(root);
while(!q.empty()) {
node * now = q.front();
q.pop();
// printf("%d-%d ",now->data,now->depth);
result[now->depth].push_back(now);
if(now->left!=NULL) {
now->left->depth=now->depth+1;
q.push(now->left);
}
if(now->right!=NULL) {
now->right->depth=now->depth+1;
q.push(now->right);
}
}
}

BFS中如何记录层级?如何记录每层叶子节点数?

使用int h[n]记录节点层级,如:h[i]即为节点i的层级,使用int max_h记录最大层数方便后续层级遍历,可使用int leaf[n]记录对应层级叶子节点数

void bfs(){
queue<int> q;
q.push(1);
while(!q.empty()){
int now = q.front();
q.pop();
max_h=max(max_h,h[now]);
if(nds[now].size()==0){
leaf[h[now]]++;
} else{
for(int i=0;i<nds[now].size();i++){
h[nds[now][i]]=h[now]+1;
q.push(nds[now][i]);
}
}
}
}

如何判断树是否为完全二叉树

方式一

数组存储树(节点index=i,左右子节点index分别为2i+1,2i+2),判断数组中间是否有空闲位置

方式二

数组存储树(节点index=i,左右子节点index分别为2i+1,2i+2),最大index==结点数n-1即为完全二叉树

方式二

BFS借助队列广度优先遍历,若遇到NULL则为非完全二叉树,因为完全二叉树在借助队列BFS遍历时,中间不可能出现NULL

PAT-树-DFS-BFS相关问题解决方案整理的更多相关文章

  1. 【前端芝士树】Vue.js面试题整理 / 知识点梳理

    [前端芝士树] Vue.js 面试题整理 MVVM是什么? MVVM 是 Model-View-ViewModel 的缩写. Model代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑. ...

  2. DFS/BFS+思维 HDOJ 5325 Crazy Bobo

    题目传送门 /* 题意:给一个树,节点上有权值,问最多能找出多少个点满足在树上是连通的并且按照权值排序后相邻的点 在树上的路径权值都小于这两个点 DFS/BFS+思维:按照权值的大小,从小的到大的连有 ...

  3. [LeetCode]695. 岛屿的最大面积(DFS/BFS)、200. 岛屿数量(DFS/BFS待做/并差集待做)

    695. 岛屿的最大面积 题目 给定一个包含了一些 0 和 1的非空二维数组 grid , 一个 岛屿 是由四个方向 (水平或垂直) 的 1 (代表土地) 构成的组合.你可以假设二维矩阵的四个边缘都被 ...

  4. HDU 5692 线段树+dfs序

    Snacks Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Sub ...

  5. 【DFS/BFS】NYOJ-58-最少步数(迷宫最短路径问题)

    [题目链接:NYOJ-58] 经典的搜索问题,想必这题用广搜的会比较多,所以我首先使的也是广搜,但其实深搜同样也是可以的. 不考虑剪枝的话,两种方法实践消耗相同,但是深搜相比广搜内存低一点. 我想,因 ...

  6. Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序

    题目:http://www.tsinsen.com/A1505 A1505. 树(张闻涛) 时间限制:1.0s   内存限制:512.0MB    总提交次数:196   AC次数:65   平均分: ...

  7. ID(dfs+bfs)-hdu-4127-Flood-it!

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4127 题目意思: 给n*n的方格,每个格子有一种颜色(0~5),每次可以选择一种颜色,使得和左上角相 ...

  8. 51 nod 1681 公共祖先 (主席树+dfs序)

    1681 公共祖先 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题   有一个庞大的家族,共n人.已知这n个人的祖辈关系正好形成树形结构(即父亲向儿子连边). 在另 ...

  9. BZOJ_3252_攻略_线段树+dfs序

    BZOJ_3252_攻略_线段树+dfs序 Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏.今天他得到了一款新游戏< ...

随机推荐

  1. leetcode349 350 Intersection of Two Arrays & II

    """ Intersection of Two Arrays Given two arrays, write a function to compute their in ...

  2. SSM 整合配置以及一个简单登陆案例(个人记录)

    SSM 文件以及大部分参考博客 https://blog.csdn.net/qq598535550/article/details/51703190 简答的登陆注册案例下载链接在末尾补贴图了 我建立的 ...

  3. Job for nginx.service failed because the control process exited with error code. See “systemctl stat

    启动nginx服务时如果遇到这个错误 Job for nginx.service failed because the control process exited with error code. ...

  4. Kafka--初识Kafka

    前言 数据为企业的发展提供动力.我们从数据中获取信息,对他们进行分析处理,然后生成更多的数据.每个应用程序都会产生数据,包括日志消息,度量指标,用户活动记录,响应消息等.数据的点点滴滴都在暗示一些重要 ...

  5. C++学习链表

    #include"pch.h" #include<iostream> #include<string> using namespace std; struc ...

  6. Python序列内单双引的问题——未解决

    在学习python基础的时候,遇到这样一个问题: tuple=(2,2.3,"yeah",5.6,False)list=[True,5,"smile"] 这样输 ...

  7. 2. FTP 服务器安装

    vsftp 安装(linux) Linux : 安装,创建虚拟用户,配置,防火墙设置 1. 安装 执行yum -y install vsftpd 注意: (1) 是否使用sudo权限执行请根据您具体环 ...

  8. webservice 的简单实现

    1.什么是webservice: 服务端整出一些资源让客户端访问(获取数据) 一个跨语言.跨平台的规范2.作用:跨平台调用.跨语言调用.远程调用 3.什么时候使用webservice: 1.新旧系统之 ...

  9. div 100% 填充页面

    css中 html,body{ margin:0; padding:0; height:100%; }

  10. bzoj 4260REBXOR

    什么什么trie树??呵呵呵,,,, 一直在困惑怎么处理哪连续一段最大..看了题解迷惑了好久.. 然后突然发现,是xor啊,,在trie树里找到以前得插入的前缀和,然后找到与现在前缀和每一位都不同的, ...