二叉树的基本操作及四种排序

二叉树的基本操作:"二叉树基本操作.cpp"

首先定义二叉链式结构:

#include <stdio.h>
#include <stdlib.h>
#define QUEUE_MAXSIZE 50   //队列大小
typedef char DATA;    //定义元素类型
typedef struct ChainTree
{
	DATA data;
	struct ChainTree *left;     //左子树结点指针
	struct ChainTree *right;   //右子树指针 
} ChainBinTree;

然后对一个二叉树进行初始化,即将已有的一个结点设置为二叉树根结点

ChainBinTree *BinTreeInit(ChainBinTree *node)    //初始化二叉树根结点
{
	if(node!=NULL)     //二叉树根结点不为空 
	  return node;
	else
	  return NULL;
} 
node为一个二叉树结点的指针,若node结点不空,返回该结点指针的值作为二叉树的根结点

添加结点到二叉树:

int BinTreeAddNode(ChainBinTree *bt,ChainBinTree *node,int n)  //添加结点
//bt为父结点,node为子结点,n=1表示添加到左子树,n=2表示添加到右子树
{
	if(bt==NULL)
	{
		printf("父结点不存在,先设置父结点\n");
		return 0;
	}
	switch(n)
	{
		case 1:
			if(bt->left)       //左子树不为空
			{
				printf("左子树结点不为空\n");
				return 0;
				
			}else      //父结点bt的左子树为空,将结点node添加到左子树 
			   bt->left=node;
			   break;
		case 2:
			if(bt->right)  //右子树不为空
			{
				printf("右子树结点不为空\n");
				return 0;
			} else
			     bt->right=node;  //结点node添加到右子树
			break;
		default:
			printf("参数错误\n");
			return 0;    
			
	}
	return 1;      //1表示添加成功 
} 
获取二叉树的左右子树:

ChainBinTree *BinTreeLeft(ChainBinTree *bt)  //返回左子结点
{
	if(bt)   //根结点存在
	   return bt->left;
	else
	   return NULL;
} 

ChainBinTree *BinTreeRight(ChainBinTree *bt)  //返回右子结点
{
	if(bt)
	  return bt->right;
	else 
	  return NULL; 
} 
计算树的深度
int BinTreeDepth(ChainBinTree *bt)    //求二叉树深度
{
	int dep1,dep2;
	if(bt==NULL)
	    return 0;     //对于空树,深度为0
	else{
		dep1=BinTreeDepth(bt->left);
		dep2=BinTreeDepth(bt->right);   //递归调用左右子树深度
		if(dep1>dep2)
		  return dep1+1;  //加1表示加上根结点,整个树的深度
		 else
		   return dep2+1; 
	} 
} 

在二叉树中查找,需要遍历二叉树的每一个结点,逐个比较数据,当找到目标数据时,返回数据所在的结点指针

ChainBinTree *BinTreeFind(ChainBinTree *bt,DATA data);  //在二叉树中找值为data的结点
{
	ChainBinTree *p;
	if(bt==NULL)
	  return NULL;
	else{
		if(bt->data==data)
		  return bt;
		  else{         //分别向左右子树递归查找 
		  	if(p=BinTreeFind(bt->left,data))
		  	  return p;
		  	  else if(p=BinTreeFind(bt->right,data)) 
		  	    return p;
		  	     else
		  	      return NULL;
		  }
	}
}
清空二叉树:在向二叉树添加结点时,每个结点都是由malloc函数申请分配内存,清空时用free释放

void BinTreeClear(ChainBinTree *bt)   //清空二叉树,
{
	if(bt)
	{
		BinTreeClear(bt->left);     //清空左子树
		BinTreeClear(bt->right);     //清空右子树
		free(bt);
		bt=NULL; 
	}
	return;
} 


二叉树的遍历:

遍历是对二叉树的基本操作,所谓遍历二叉树就是按照一定规则和顺序走遍二叉树所有子树,使每一个结点都被访问一次
遍历有四种方法:先序遍历,中序遍历,后序遍历,按层遍历。

对下图:D(data)表示根节点,L(left)表示左子树,R(right)表示右子树


先序遍历(DLR):先访问根节点,在按先序遍历左子树,最后按先序遍历右子树

中序遍历(LDR):先按中序遍历左子树,再访问根结点,最后按中序遍历右结点

后序遍历(LRD):先后序遍历左子树,再后序遍历右子树,最后再访问根结点

先序遍历:

//先序遍历
void BinTree_DLR(BinTree)
{
	if(bt)     //树不为空,
	{
		oper(bt);   //处理结点数据
		BinTree_DLR(bt->left,oper);   //递归处理左子树和右子树
		BinTree_DLR(bt->right,oper); 
	} 
	return;  //递归结束
} 
bt为需要遍历的根结点,函数oper是一个需要对结点进行操作的函数。
中序遍历:

//中序遍历
void BinTree_LDR(BinTree)
{
	if(bt)
	{
		BinTree_LDR(bt->left,oper); //中序遍历左子树
		oper(bt);
		BinTree_LDR(bt->right,oper); 
	}
	return;
} 

后序遍历:

//后序遍历
void BinTree_LRD(BinTree)
{
	if(bt)
	{
		BinTree_LDR(bt->left,oper);   
		BinTree_LDR(bt->right,oper);
		oper(bt);
	}
	return;
} 
对下图:


先序遍历后各结点顺序:A,B,D,H,I,E,J,K,C,F,L,G。

中序遍历后各节点顺序:H,D,I,B,J,E,K,A,L,F,C,G

后序遍历后各结点顺序:H,I,D,J,K,E,B,L,F,G,C,A

按层遍序:对上面所示的二叉树,共有四层,按层遍历得到的顺序就是:A,B,C,D,E,F,G,H,I,J,K,L

由于二叉树按层遍历,使用循环队列进行处理,实现逐层遍历:

//按层遍历
void BinTree_Level(ChainBinTree *bt,void (*oper)(ChainBinTree *p))  
{
	ChainBinTree *p;
	ChainBinTree *q[QUEUE_MAXSIZE];   //定义一个顺序队列
	int head=0,tail=0;
	if(bt)      //若队首指针不空 
	{
		tail=(tail+1)%QUEUE_MAXSIZE;  //计算循环队列的队尾序号 
		q[tail]=bt;       //将二叉树根指针入队
	} 
	while(head!=tail)  //队列不为空,进行循环
	{
		head=(head+1)%QUEUE_MAXSIZE; //计算循环队列的队首序号
		p=q[head];     //获取队首元素 
		oper(p);       //处理队首元素 
		if(p->left!=NULL)     //结点有左子树,则左子树指针进队
		{
			tail=(tail+1)%QUEUE_MAXSIZE; 
			q[tail]=p->left;   //将左子树指针进队 
		} 
		if(p->right!=NULL)     //结点有右子树;右子树指针进队
		{
			tail=(tail+1)%QUEUE_MAXSIZE;
			q[tail]=p->right;
		} 
	} 
	return;
} 
首先从根结点开始,每层的结点逐步进入队列,这样就可得到按层遍历的效果。

以上是二叉树相关操作,接下来是测试这些操作的:

#include<stdio.h>
#include<stdlib.h>
#include "二叉树基本操作.cpp"
void oper(chainBinTree *p)   //操作二叉树结点的数据
{
	printf("%c",p->data);   //在本例中函数的操作只是输出结点中的字符即可
	return; 
} 
ChainBinTree *InitRoot()  //创建二叉树根结点
{
	ChainBinTree *node;
	if(node=(ChainBinTree *)malloc(sizeof(ChainBinTree)))
	{
		printf("输入根结点数据:");
		scanf("%s",&node->data);
		node->left=NULL;
		node->right=NULL;
		return node;    //返回根结点 
	}
        return NULL;
}

void Addnode(ChainBinTree *bt)     //给二叉树添加子结点
{
	ChainBinTree *node,*parent;
	DATA data;
	char select;
	if(node=(ChainBinTree *)malloc(sizeof(ChainBinTree)))
	{
		printf("输入二叉树结点数据:");
		fflush(stdin);  //清空输入缓存区
		scanf("%s",&node-data);
		node->left=NULL;
		node->right->NULL;
		printf("输入父结点数据:");  //提示输入父结点数据,将该结点作为新增结点的父结点
		fflush(stdin);
		scanf("%s",&data);
		parent=BinTreeFind(bt,data);   //查找指定数据的结点
		if(!parent)     //没有找到指定 数据 的结点
		{
			printf("没有找到父结点\n");
			free(node); //释放创建结点的内存
			return; 
		} 
		printf(1.添加到左子树\n 2.添加到右子树\n);
		do{
			select=getch();
			select-='0';
			if(select==1||select==2)
			  BinTreeAddNode(parent,node,select);    //新增加的结点添加到指针父结点下,完成结点添加操作
		}while(select!=1&&select!=2);
	
	}
	return;
} 
int main()
{
	ChainBinTree *root=NULL;   //root是指向二叉树根结点的指针
	char select;
	void (*oper1)();       //指向函数的指针,将测试程序中编写的函数oper赋值给该指针,用来处理各结点数据
	oper1=oper;     //指向具体的操作函数
	do{
		printf("\n1.设置二叉树的根元素       2.添加二叉树的结点\n");
		printf("3.先序遍历      4.中序遍历       5.后序遍历    6、按层遍历"\n);
		ptintf("7.二叉树的深度       0.退出\n");
	    select=getch();
	    switch(select){
	    	case '1':
	    		root=InitRoot();
	    		break;
	    	case '2':
	    		AddNode(root);
	    		break;   
	    	case '3':
			    printf("\n先序遍历结果:");
				BinTree_DLR(root,oper1);
				printf("\n");
				break;
			case '4':
			    printf("\n中序遍历结果:");
				BinTree_LDR(root,oper1);
				printf("\n");
				break;
			case '5':
			    printf("\n后序遍历的结果:");
				BinTree_LRD(root,oper1);
				printf("\n");
			case '6':
				printf("按层遍历结果:");
				BinTree_level1(root,oper1);
				printf("\n");
				break;
			case '7':
	     		printf("二叉树的深度:%d\n",BinTreeDepth(root));
				break;
			case  '0':
				break;
				
	    }
	}while(select!='0');
	BinTreeClear(root);  //清空二叉树
	root=NULL;
	return 0; 
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值