数据结构之二叉树(C语言)

这里的存储结构采用了二叉链表

1.定义存储结构

#include<stdio.h>
#include<stdlib.h>
typedef char eletype;
#define Max 16//这里假设二叉树只有4层 
  typedef struct node{
 	eletype data;
 	struct node * leftChild,*rightChild;	
} BiTreeNode;//二叉节点

2.二叉树的创建函数

BiTreeNode* Create(){//创建一棵二叉树,返回根结点地址
 	printf("先添加虚结点,变成一棵完全二叉树\n");
 	printf("\n");
	printf("按完全二叉树层序编号次序,依次输入每个结点名称,其中虚结点用#表示,结束用@表示\n");
	BiTreeNode * r =NULL,*s,*Q[Max];
	eletype ch;
	int front=1,rear=0;
	scanf(" %c",&ch);
	while(ch!='@')
	{
		s=NULL;
		if(ch!='#')//只要没有遇到虚结点,就为s动态开辟空间 
		{
			s=( BiTreeNode*)malloc(sizeof(BiTreeNode));
			s->data=ch;
			s->rightChild=s->leftChild=NULL;
			
		}
	//将s结点入队
	Q[++rear]=s;
	if(rear==1)
		r=s;//此时s就是根结点 
		else
		{
			if(s)
			{
				//给s结点找双亲结点
				if(rear%2==0)//如果rear是偶数 
				   Q[front]->leftChild=s;//那么它此时就是前一个结点的左孩子结点 
				else//如果是奇数 
				  Q[front] ->rightChild=s;//那么它此时是前一个结点的右孩子结点 
				 
			}
	if(rear%2==1)//说明它此时是前一个结点的右孩子结点 ,
	//也就是说前一个结点的双亲结点全部找到,该下一个了,所以接着front++ 
		front++;
		}
	scanf(" %c",&ch);	
	  
	}
	
 	return r;
 }

这里在创建二叉树的时候还用到了队列,创建了一个指针类型的一维数组,用它来存放二叉节点,

由于我们的存储结构时二叉链表,所以最后只需返回一个根节点即可。

这里特别注意一下代码里scanf("  %c",&ch)  和原本scanf("%c",&ch)的区别。没错,前者在%c之前多了一个空格字符。

二者的区别是:scanf("  %c",&ch) 这里的空格表示scanf在读取字符之前会忽略掉任何空白字符,包括空格、制表符(tab)和换行符。这意味着如果输入缓冲区中存在这些空白字符,scanf会跳过它们,直到读取到下一个非空白字符。这对于读取以空格分隔的字符序列特别有用。

scanf("%c",&ch):没有空格的格式字符串告诉scanf读取下一个可用的字符,不管它是不是空白字符。这意味着即使输入缓冲区中存在空白字符,scanf也会读取它作为输入。

3.接下来是三种遍历

①前根遍历

void preSearch(BiTreeNode * r){
 	if (r){
 		printf(" %c",r->data);
 		preSearch(r->leftChild);//先根遍历左子树
		preSearch(r->rightChild); //先根遍历右子树
	 }
 } 

遍历顺序:根节点 -> 左子树 -> 右子树

过程

  • 如果节点r不为空,首先打印节点r的数据。
  • 然后递归地对节点r的左子树进行先序遍历。
  • 最后递归地对节点r的右子树进行先序遍历。

特点:先序遍历会首先访问根节点,然后是左子树上的所有节点,最后是右子树上的所有节点。

②后根遍历

void postSearch(BiTreeNode * r){ 
 	if (r){
 		postSearch(r->leftChild);//后根遍历左子树
		postSearch(r->rightChild); //后根遍历右子树
		printf(" %c",r->data);
	 }
 } 

遍历顺序:左子树 -> 右子树 -> 根节点

过程

  • 如果节点r不为空,首先递归地对节点r的左子树进行后序遍历。
  • 然后递归地对节点r的右子树进行后序遍历。
  • 最后打印节点r的数据。

特点:后序遍历会访问左子树上的所有节点,然后是右子树上的所有节点,最后访问根节点。

这里每次递归都会先判断当前结点是否为空,如果为空,意味着左结点或者右节点到底了,会返回上一层函数的第二个postSearch函数。

③中根遍历

void inSearch(BiTreeNode * r){ 
 	if (r){
 		inSearch(r->leftChild);//中根遍历左子树
 		printf(" %c",r->data);
		inSearch(r->rightChild); //中根遍历右子树	
	 }

遍历顺序:左子树 -> 根节点 -> 右子树

过程

  • 如果节点r不为空,首先递归地对节点r的左子树进行中序遍历。
  • 然后打印节点r的数据。
  • 最后递归地对节点r的右子树进行中序遍历。

特点:中序遍历会首先访问左子树上的所有节点,然后是根节点,最后是右子树上的所有节点

以及不太好理解的

④层序遍历

void levelorder(BiTreeNode * r){//层序遍历
 		BiTreeNode *Q[Max],*s;
 		int front=-1,rear=-1;//初始队列为空 
 		if(!r) return ;//如果根节点为空则不进行任何操作 
 	   Q[++rear]=r;//将根结点存放在队列的第一个位置 
		while(front!=rear){//只要队列不满 
			s=Q[++front];//将队列前端的结点出队,此时的front=0,所以第一个出队的时根结点 
			printf(" %c",s->data);
			if(s->leftChild)//如果根结点的左结点存在,则入队 
				Q[++rear]=s->leftChild;
			if(s->rightChild)//如果根结点的右结点存在,则入队
				Q[++rear]=s->rightChild	;
		}		
 			
		 
 	 
 	
 }
 

4.销毁函数

void Destory(BiTreeNode * r){//销毁二叉树r
 	if(r){
 		Destory(r->leftChild);
 		Destory(r->rightChild);
 		free(r);
	 } 	
 }

5.主函数调用

int main(){
 	BiTreeNode * root=Create();
 	printf("先根遍历序列:\n");
    preSearch(root);
    printf("\n");
    printf("后根遍历序列:\n");
    postSearch(root);
    printf("\n");
 	printf("中根遍历序列:\n");
 	inSearch(root);
 	printf("\n");
 	printf("层序遍历序列:\n");
 	levelorder(root);
 	printf("\n");
 	Destory(root) ;
 	return 0;
 }
 

6.代码实现结果

为了更好的理解,我们展示一下二叉树图

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值