C语言数据结构二叉树的建立,前序后序层序和中序创建二叉树

二叉树定义

二叉树是递归定义的,其结点有左右子树之分,逻辑上二叉树有五种基本形态:
(1)空二叉树——如图(a);
(2)只有一个根结点的二叉树——如图(b);
(3)只有左子树——如图©; 在这里插入图片描述
(4)只有右子树——如图(d);
(5)完全二叉树——如图(e)。
注意:尽管二叉树与树有许多相似之处,但二叉树不是树的特殊情形。 [1]
类型
(1)完全二叉树——若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排布,这就是完全二叉树。
(2)满二叉树——除了叶结点外每一个结点都有左右子叶且叶子结点都处在最底层的二叉树。
(3)平衡二叉树——平衡二叉树又被称为AVL树(区别于AVL算法),它是一棵二叉排序树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

二叉树储存形式

struct node{
	int data;//数据域
	int layer;//层次
	node *lchild;//左指针域
	node *rchild;//右指针域 
};

二叉树的建立

/*树的形状
3 4 6 0 0 7 8 0 0 0 0 // 0作为一个分支的分割符
         3
      4     0
   6    7    
  0 0  8  0
      0 0  


先序遍历:
3 4 6 7 8
中序遍历:
6 4 8 7 3
后序遍历:
6 8 7 4 3
*/
#include <stdio.h>
#include <stdlib.h>
#include<iostream>
using namespace std;
typedef struct BiTNode
{
    char data;
    struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
void CreateBiTree(BiTree &T)//根据根节点创建树
{
	//&引用 如果函数中需要新建新节点,即对二叉树的结构作出修改就需要引用
	//如果只是修改当前已有节点内容或仅仅是遍历树就不需要引用 
   	char s;
   	cin>>s; 
   	//申请空间 
   	T=(BiTree )malloc(sizeof(BiTNode));
   	//如果s等于0说明当前分支建立完成 
   if(s=='0') T=NULL;//控制分支结束 
   else  {
   	  T->data=s;
   	  CreateBiTree(T->lchild);
   	  CreateBiTree(T->rchild);
   }
}

void PreOrder(BiTree T)//先序
{
   if(T!=NULL){
   printf("%c ",T->data);
   PreOrder(T->lchild);
   PreOrder(T->rchild);
   } 
} 

void InOrder(BiTree T)//中序
{
   if(T!=NULL){
   InOrder(T->lchild);
   printf("%c ",T->data);
   InOrder(T->rchild);
   } 
} 

void PostOrder(BiTree T)//后序
{
   if(T!=NULL){
   PostOrder(T->lchild);
   PostOrder(T->rchild);
   printf("%c ",T->data);
   } 
} 

int main()
{
   BiTNode *T;
   CreateBiTree(T);
   printf("先序遍历:");
   printf("\n");
   PreOrder(T);
   printf("\n");
   printf("中序遍历:");
   printf("\n");
   InOrder(T);
   printf("\n");
   printf("后序遍历:");
   printf("\n");
   PostOrder(T);
   return 0;
}

二叉树的遍历形式
前序、后序、中序 遍历是按照访问根节点的访问顺序区分的。
例如

在这里插入图片描述
前序遍历为先访问***根节点A***再访问它的左子树B最后访问右子树C
中序遍历先访问B节点再访问***根节点A***然后访问C
后序遍历先访问B再访问C最后访问***根节点A***
再看一个比较复杂的二叉树
在这里插入图片描述
前序遍历:ABCDEFGHK

中序遍历:BDCAEHGKF

后序遍历:DCBHKGFEA
在这里插入图片描述
先序遍历

void PreOrder(BiTree T)//先序
{
   if(T!=NULL){
   printf("%c ",T->data);
   PreOrder(T->lchild);
   PreOrder(T->rchild);
   } 
} 

中序遍历

void InOrder(BiTree T)//中序
{
   if(T!=NULL){
   InOrder(T->lchild);
   printf("%c ",T->data);
   InOrder(T->rchild);
   } 
} 

后序遍历

void PostOrder(BiTree T)//后序
{
   if(T!=NULL){
   PostOrder(T->lchild);
   PostOrder(T->rchild);
   printf("%c ",T->data);
   } 
} 

层序遍历
按照上面那张图
先把A加入进队列q中,先访问它然后判断有左节点 B 再把B加入到队列q中继续判断是否有右节点 把E加入进去所以最后的访问顺序就是
ABECFDGHK

//代码实现
void LayerOrder(noed *root) {
	queue<node*>q;
	q.push(root);
	while(!q.empty()) {
		node *now=q.front();
		q.pop();
		printf("%d ",now->data);
		if(now->lchild!=NULL)  q.push(now->lchild);
		if(now->rchild!=NULL)  q.push(now->rchild);
	}
} 

由前序和中序构建树并输出后序

/*
层序遍历:
4163572
中序遍历:
1234567
后序遍历:
2315764
先序遍历:
4132657

思路
先序遍历 根左子树右子树 分为三部分即三个区间 第一个访问的一定是根节点即(preL) 
中序遍历  左子树根右子树  根据后序遍历查找到的根节点在中序遍历中找到根节点的下标(无重复)从而找到
左右根节点的总个数  
先找到4 从中序中找到下标为3说明左子树总个数为3,右子树总个数为3 在中序遍历中得到左子树所在的区间下标为0-2
右子树区间下标为4-6 从先序遍历中得到左子树所在区间(preL+1,preL+numLeft)为 1-3
右子树所在区间(preL+numLeft+1,preR)为4-6 
然后递归建树 
*/

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef struct TreeNode{
	char date;
	struct TreeNode *rTree;
	struct TreeNode *lTree;
}TreeNode,*BiTree;
char pres[100],ins[100];
TreeNode* create(int preL,int preR,int inL,int inR){
	if(preL>preR){
		return NULL;
	}
	BiTree T=(BiTree)malloc(sizeof(TreeNode));
	将当前根节点连接到树上 
	T->date =pres[preL];
	int k;
	for(k=inL;k<=inR;k++){
		if(ins[k]==pres[preL]){
			break;
		}
	}
	//记录左右子树的个数 
	int numLeft=k-inL;
	T->lTree =create(preL+1,preL+numLeft,inL,k-1);
	T->rTree =create(preL+numLeft+1,preR,k+1,inR);
	return T;
}
//后序遍历输出结果 
void BehShowBiTree(BiTree T){
	if(T!=NULL){
		BehShowBiTree(T->lTree );
		BehShowBiTree(T->rTree );
		cout<<T->date;
	}
}
int main(){
	while(cin>>pres>>ins){
		BiTree T;
		T=create(0,strlen(pres)-1,0,strlen(ins)-1);
		BehShowBiTree(T);
		cout<<endl;
	}
}

由后序和中序构建树并输出前序结果

/*
层序遍历:
4163572
中序遍历:
1234567
后序遍历:
2315764
前序遍历:
4132657

思路
后序遍历 左子树右子树根 分为三部分即三个区间 最后一个访问的一定是根节点即(preR) 
中序遍历  左子树根右子树  根据后序遍历查找到的根节点在中序遍历中找到根节点的下标(无重复)从而找到
左右根节点的总个数  
先找到4 从中序中找到下标为3说明左子树总个数为3,右子树总个数为3 在中序遍历中得到左子树所在的区间下标为0-2
右子树区间下标为4-6 从后序遍历中得到左子树所在区间(preL,preL+numLeft-1)为 0-2 
右子树所在区间(preL+numLeft,preR-1)为3-5 
然后递归建树 
*/
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef struct TreeNode{
	char date;
	struct TreeNode *rTree;
	struct TreeNode *lTree;
}TreeNode,*BiTree;
char pres[100],ins[100];
TreeNode* create(int preL,int preR,int inL,int inR){
	if(preL>preR){
		return NULL;
	}
	BiTree T=(BiTree)malloc(sizeof(TreeNode));
	//将当前根节点连接到树上 
	T->date =pres[preR];
	int k;
	//在中序遍历中查找根节点的下标  
	for(k=inL;k<=inR;k++){
		if(ins[k]==pres[preR]){
			break;
		}
	}
	//记录左右子树的个数 
	int numLeft=k-inL;
	T->lTree =create(preL,preL+numLeft-1,inL,k-1);
	T->rTree =create(preL+numLeft,preR-1,k+1,inR);
	return T;
}
//先序遍历输出结果 
void PreShowBiTree(BiTree T){
	if(T!=NULL){
		cout<<T->date;
		PreShowBiTree(T->lTree );
		PreShowBiTree(T->rTree );
	}
}

int main(){
	while(cin>>pres>>ins){
		BiTree T;
		T=create(0,strlen(pres)-1,0,strlen(ins)-1);
		PreShowBiTree(T);
		cout<<endl;
	}
}

由层序和中序构建树并输出结果


/*

3 4 6 7 8
先序遍历:
34678
中序遍历:
64873
后序遍历:
68743
层序遍历:
34678

算法笔记 
P296变形 
层序遍历:
4163572
中序遍历:
1234567
后序遍历:
2315764

输入顺序为先层序遍历后中序遍历
 
*/
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<map>
using namespace std;
typedef struct TreeNode{
	char date;
	struct TreeNode *rTree;
	struct TreeNode *lTree;
}TreeNode,*BiTree;
char pres[100],ins[100];//pres层序遍历  ins中序遍历 
TreeNode* create(int inL,int inR,queue<char> q){
	//队列q表示当前根节点和根的子树(顺序为层序遍历) 
	if(q.empty() ){
		return NULL;
	}
	BiTree T=(BiTree)malloc(sizeof(TreeNode));
	//把当前根连到建立的树上面 
	T->date =q.front() ;
	//char c=T->date;
	q.pop() ;
	if(q.empty() ){
		T->lTree =T->rTree =NULL;
		return T;
	}
	int k;
	//查找根节点  
	for(k=inL;k<=inR;k++){
		if(ins[k]==T->date ){
			break;
		}
	}
	//计算根节点左右子树总个数 
	int numLeft=k-inL,numRight=inR-k;
	//建立左子树 
	if(numLeft>0){
		queue<char> q1;
		//q1代表下一层q 
		int num=0;
		map<char,int> mp;
		//标记根节点左子树 
		for(int i=inL;i<k;i++){
			mp[ins[i]]=++num; 
		}
		//从层序遍历中找到上述标记并记录到q1中(按照层序遍历顺序)
		//顺序的先后代表位置层次关系 
		for(int i=0;i<strlen(pres);i++){
			if(mp[pres[i]]){
				q1.push(pres[i]); 
			}
		}
		T->lTree =create(inL,k-1,q1);
	}
	//建立右子树 
	if(numRight>0){
		queue<char> q2;
		int num=0;
		map<char,int> mp;
		for(int i=k+1;i<=inR;i++){ //注意区间  
			mp[ins[i]]=++num; 
		}
		for(int i=0;i<strlen(pres);i++){
			if(mp[pres[i]]){
				q2.push(pres[i]); 
			}
		}
		T->rTree =create(k+1,inR,q2);
	}
	return T;
}


//后序遍历输出 
void BehShowBiTree(BiTree T){
	if(T!=NULL){
		BehShowBiTree(T->lTree );
		BehShowBiTree(T->rTree );
		cout<<T->date;
	}
}
int main(){
	while(cin>>pres>>ins){
		queue<char> q;
		for(int i=0;i<strlen(pres);i++){
			q.push(pres[i]); 
		}
		BiTree T;
		T=create(0,strlen(ins)-1,q);
		BehShowBiTree(T);
		cout<<endl;
	}
}
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值