100000611 - 《算法笔记》9.2小节——数据结构专题(2)->二叉树的遍历

9.2小节——数据结构专题(2)->二叉树的遍历

二叉树遍历一般有先序遍历、中序遍历、后序遍历以及层次遍历。

9.2.1-先序遍历

//先序遍历的实现
void preorder(node *root){
	if(root == NULL){
		return;//到达空树,递归边界 
	}
	//访问根结点root
	printf("%d\n",root->data);
	//访问左子树
	preorder(root->lchild);
	//访问右子树
	preorder(root->rchild); 
}

9.2.2-中序遍历

//中序遍历的实现
void inorder(node *root){
	if(root == NULL){
		return;//到达空树 
	}
	inorder(root->lchild);
	//访问根结点
	printf("%d\n",root->data);
	inorder(root->rchild); 
}

9.2.3-后序遍历

//后序遍历的实现
void postorder(node *root){
	if(root == NULL){
		return;//到达空树 
	}
	inorder(root->lchild);
	inorder(root->rchild); 
	//访问根结点
	printf("%d\n",root->data);
	
}

9.2.4-层次遍历

//层次遍历的实现
void Layerorder(node *root){
	queue<node*> q;//注意队列里存地址
	root->layer = 1;//根结点的层号为1 
	q.push(root);//将根结点地址入队
	while(!q.empty()){
		node *now = q.front();//取出队首元素
		q.pop();
		printf("%d",now->data);//访问队首元素
		if(now->lchild != NULL){
			now->lchild->layer = now->layer + 1;//左孩子的层号为当前层号+1 
			q.push(now->lchild);//左子树非空
		}
		if(now->rchild != NULL){
			now->rchild->layer = now->layer + 1;//右孩子的层号为当前层号+1 
			q.push(now->rchild);//右子树非空
		}	 
	} 
}

遍历汇总

#include <iostream>
#include <cstdio>
using namespace std; 
#include <queue> 
typedef elemtype int;

//二叉树的存储结构 
struct node{
	typename data;//数据域
	node *lchild;//指向左子树根结点的指针
	node *rchild;//指向右子树根结点的指针 
	int layer;//层次 
}; 

//二叉树的遍历
 
//先序遍历的实现
void preorder(node *root){
	if(root == NULL){
		return;//到达空树,递归边界 
	}
	//访问根结点root
	printf("%d\n",root->data);
	//访问左子树
	preorder(root->lchild);
	//访问右子树
	preorder(root->rchild); 
} 

//中序遍历的实现
void inorder(node *root){
	if(root == NULL){
		return;//到达空树 
	}
	inorder(root->lchild);
	//访问根结点
	printf("%d\n",root->data);
	inorder(root->rchild); 
} 

//后序遍历的实现
void postorder(node *root){
	if(root == NULL){
		return;//到达空树 
	}
	inorder(root->lchild);
	inorder(root->rchild); 
	//访问根结点
	printf("%d\n",root->data);
	
} 

//层次遍历的实现
void Layerorder(node *root){
	queue<node*> q;//注意队列里存地址
	root->layer = 1;//根结点的层号为1 
	q.push(root);//将根结点地址入队
	while(!q.empty()){
		node *now = q.front();//取出队首元素
		q.pop();
		printf("%d",now->data);//访问队首元素
		if(now->lchild != NULL){
			now->lchild->layer = now->layer + 1;//左孩子的层号为当前层号+1 
			q.push(now->lchild);//左子树非空
		}
		if(now->rchild != NULL){
			now->rchild->layer = now->layer + 1;//右孩子的层号为当前层号+1 
			q.push(now->rchild);//右子树非空
		}	 
	} 
}

PAT例题A1020

//PATA-1020-Tree-Traversals
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn = 50;
struct node{
	int data;
	node *lchild;
	node *rchild;
};

int pre[maxn],in[maxn],post[maxn];//先序、中序、后序
int n;//结点个数
//当前二叉树的后序序列区间为[postL,postR],中序序列区间为[inL,inR]
//create函数返回构建出的二叉树的根结点地址
node *create(int postL,int postR,int inL,int inR){//根据后序和中序序列前序重构树 
	if(postL > postR){
		return NULL;//后序序列长度小于等于0时,直接返回 
	}
	node *root = new node;//新建一个新的结点,用来存放当前二叉树的根结点
	root->data = post[postR];//新结点的数据域为根结点的值
	int k;
	for(k = inL;k <= inR;k++){
		if(in[k] == post[postR]){//在中序序列中找到in[k] == pre[L]的结点
			break; 
		}
	} 
	int numLeft = k - inL;//左子树的结点个数
	//返回左子树的根结点地址,赋值给root的左指针
	root->lchild = create(postL,postL+numLeft - 1,inL,k - 1);
	//返回右子树的根结点地址,赋值给root的右指针
	root->rchild = create(postL+numLeft,postR - 1,k + 1,inR);
	return root;//返回根结点地址 
} 

int num = 0;//已输出的结点个数
void BFS(node *root){
	queue<node*> q;//注意队列里是存地址
	q.push(root);//将根结点地址入队
	while(!q.empty()){
		node *now = q.front();//取出队首元素
		q.pop();
		printf("%d",now->data);//访问队首元素 
		num++;
		if(num < n)	printf(" ");
		if(now->lchild != NULL)	q.push(now->lchild);//左子树非空
		if(now->rchild != NULL)	q.push(now->rchild);//右子树非空 
	} 
} 

int main(){
	scanf("%d",&n);
	for(int i=0;i < n;i++){
		scanf("%d",&post[i]);
	}
	for(int i=0;i < n;i++){
		scanf("%d",&in[i]);
	}
	node *root = create(0,n-1,0,n-1);//建树
	BFS(root);//层序遍历
	return 0; 
} 

9.2.5二叉树的静态实现

#include <iostream>
#include <cstdio>
using namespace std; 
#include <queue> 
typedef int elemtype;
#define maxn 1000 
//二叉树的静态实现
struct node{
	elemtype data;//数据域
	int lchild;
	int rchild;
}Node[maxn];
//新建结点 
int index = 0;
int newNode(int v){//分配一个Node数组中的结点给新的结点,index为其下标
	Node[index].data = v;//数据域为v
	Node[index].lchild = -1;//以-1或maxn表示空,因为数组范围是0~maxn-1 
	Node[index].rchild = -1;
	return index++;
}
//查找,root为根结点在数组中的下标
void search(int root,int x,int newdata){
	if(root == -1){//用-1代替NULL
		return;//空树,死胡同 
	}
	if(Node[root].data == x){//找到数据域为x的结点,把它修改成newdata
		Node[root].data = newdata; 
	}
	search(Node[root].lchild,x,newdata);//往左子树搜索x(递归式)
	search(Node[root].rchild,x,newdata);//往右子树搜索x(递归式) 
} 

//插入,root为根结点在数组中的下标
void insert(int &root,int x){//记得加引用
	if(root == -1){//空树,说明查找失败,也即插入位置(递归边界)
		root = newNode(x);//给root赋以新的结点
		return; 
	} 
	if(Node[root].data > x){
		insert(Node[root].lchild,x);//往左子树搜索(递归式) 
	}
	else
	{
		insert(Node[root].rchild,x);//往右子树搜索(递归式) 
	}
} 

//二叉树的建立,函数返回根结点root的下标
int Create(int data[],int n){
	int root = -1;//新建根结点
	for(int i=0;i<n;i++){
		insert(root,data[i]);//将data[0]~data[n-1]插入二叉树中 
	} 
	return root; 
} 

//静态二叉树的遍历
//先序遍历
void preorder(int root){
	if(root == -1){
		return;//到达空树,递归边界 
	}
	//访问根结点root,例如将其数据域输出
	printf("%d\n",Node[root].data);
	preorder(Node[root].lchild);
	preorder(Node[root].rchild); 
} 

//中序遍历
void inorder(int root){
	if(root == -1){
		return;//到达空树,递归边界 
	}
	inorder(Node[root].lchild);
	//访问根结点root,例如将其数据域输出
	printf("%d\n",Node[root].data);
	inorder(Node[root].rchild); 
} 

//后序遍历
void postorder(int root){
	if(root == -1){
		return;//到达空树,递归边界 
	}
	postorder(Node[root].lchild);
	postorder(Node[root].rchild); 
	//访问根结点root,例如将其数据域输出
	printf("%d\n",Node[root].data);
} 

//层序遍历
void LayerOrder(int root){
	queue<int> q;//此队列里存放结点下标
	q.push(root);//将根结点地址入队
	while(!q.empty()){
		int now = q.front();//取出队首元素
		q.pop();
		printf("%d ",Node[now].data);//访问队首元素
		if(Node[now].lchild != -1)	q.push(Node[now].lchild);//左子树非空
		if(Node[now].rchild != -1)	q.push(Node[now].rchild);//右子树非空 
	} 
}

Codeup习题

链接:http://codeup.cn/contest.php?cid=100000611

问题A-复原二叉树

链接: http://codeup.cn/problem.php?cid=100000611&pid=0

//问题A-复原二叉树
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
string pre,in;//输入前序和中序字符串 
struct BiTNode{
	char data;
	BiTNode *lchild;
	BiTNode *rchild;
};

BiTNode *Create(int preL,int preR,int inL,int inR){
	if(preL > preR)	return NULL;
	BiTNode *root = new BiTNode;
	root->data = pre[preL];
	int k;
	for(k=inL;k < inR;k++){
		if(pre[preL] == in[k])	break;
	}
	int leftNum = k - inL;
	root->lchild = Create(preL + 1,preL + leftNum,inL,k - 1);
	root->rchild = Create(preL + leftNum + 1,preR,k + 1,inR); 
}

void postOrder(BiTNode *root){
	if(root == NULL){
		return;
	}
	postOrder(root->lchild);
	postOrder(root->rchild);
	printf("%c",root->data);
}
int main(){
	while(cin>>pre>>in){
		BiTNode *root = Create(0,pre.length()-1,0,in.length()-1);
		postOrder(root);
		cout<<endl;
	}
	return 0;
}

问题B-二叉树

链接: http://codeup.cn/problem.php?cid=100000611&pid=1

//问题B-二叉树
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

int main(){
	int m,n;
	while(cin>>m>>n && (m!=0 || n!=0)){
		int sum = 1;
		int left = 2 * m;
		int right = 2 * m + 1;
		while(right < n){// 数除最后一层的子树中结点数 
			sum += right - left + 1;
			left *= 2;
			right = 2 * right + 1;
		}
		if(left <= n){//计数n结点所在层子树上结点数 
			sum += n - left + 1;
		}
		cout<<sum<<endl;
	}
	return 0;
}
	

问题C-二叉树遍历

由前序、中序求后序
链接: http://codeup.cn/problem.php?cid=100000611&pid=2

//问题C-二叉树遍历
//由前序中序输出后序遍历序列
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
//char str[110];
string pre,in;
struct BiTNode{
	char data;
	struct BiTNode *lchild;
	struct BiTNode *rchild;
};
BiTNode *Create(int preL,int preR,int inL,int inR){//由前序中序还原二叉树 
	if(preL > preR)	return NULL;
	BiTNode *root = new BiTNode;
	root->data = pre[preL];
	int k;
	for(k=inL;k< inR;k++){
		if(in[k] == pre[preL])	break;//在中序序列中找到当前树的树根 
	}
	int numLeft = k - inL;
	//前序的第一个数为树根,numLeft为左子树结点数,
	//用前序的子树树根逐渐将中序的序列进行划分 
	root->lchild = Create(preL + 1,preL + numLeft,inL,k - 1);
	root->rchild = Create(preL + numLeft + 1,preR,k + 1,inR); 
}

void postorder(BiTNode *root){
	if(root == NULL)	return;
	postorder(root->lchild);
	postorder(root->rchild);
	printf("%c",root->data);
}
int main(){
	while(cin>>pre>>in){
		BiTNode *root = Create(0,pre.length()-1,0,in.length()-1);//注意此处pre.length错误,它本身是一个函数而不是成员变量 
		postorder(root);
		cout<<endl;
	}
	return 0;
}
	

问题D-二叉树遍历

由先序求中序
链接: http://codeup.cn/problem.php?cid=100000611&pid=3

//问题 D: 二叉树遍历
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

struct node{
	char data;
	node *lchild;
	node *rchild;
};
char str[110];
node *create(int &index){//根据先序遍历构造二叉树 
	int len = strlen(str);
	if(str[index] == '#'){
		return NULL;
	}
	node *root = new node;
	root->data = str[index];
	root->lchild = create(++index);
	root->rchild = create(++index); 
	return root;
}

void inorder(node *root){//中序输出
	if(root == NULL)	return;
	inorder(root->lchild);
	printf("%c ",root->data);
	inorder(root->rchild);
}

int main(){
	while(scanf("%s",str) != EOF){
		int x = 0;
		node *root = create(x);
		inorder(root);
		printf("\n");
	}
	return 0;
}
	

小结

二叉树的可以根据前序+中序或后序+中序或层次+中序还原二叉树,遍历多用递归形式,毕竟二叉树的定义就是递归形式的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李霁明

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值