数据结构--二叉树

本文深入讲解了二叉树的基本概念,包括节点的度、树的度等,并详细介绍了二叉树的各种性质及其遍历方法。此外,还提供了二叉树的操作代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

树型结构和线性结构的区别

    线性链表,一个节点最多只有一个前驱和一个后驱(循环链表)。树型结构的话则每一个节点可以有一个前驱节点和多个后驱节点,我们一般用到的是二叉树,也就是说有两个后继节点。

基本概念

    

节点的度:一个节点的子数的数量称为该节点的度

树的度:该树中节点的最大度数

叶子节点:树中度为0的节点称为叶子节点,度不为0的节点称为分支节点

节点的层数:树是一种层次结构

树的深度:一棵树中节点的最大层数称为树的深度

有序树和无序树:树中各节点的子树按一定的顺序从左向右安排称为有序树

森林:m颗互不相交的树的集合


二叉树的性质

1.	二叉树中,第i层节点总数最多为2i-1个
2.	深度为k的二叉树最多2k-1个节点,最少有k个节点,左树
3.	一颗二叉树,叶节点n0,度为2的节点总数n2,则n0=n2+1;
4.	具有n个节点的完全二叉树的深度为k, k>=log2n+1
5.	对于一个具有n个节点的完全二叉树各个节点如果采用顺序方式存储,对于任意节点i,有如下关系:
    a)	如果i!=1,则其父节点的编号为i/2;
    b)	如果2i<=n,则其左子树的根节点编号为2i,如果2*i>n,那么无左子树
因为对于完全二叉树,左子树的根节点编号总是2的倍数
    c)	如果2*i+1<=n,那么右子树根节点编号为2*i+1;否则无右子树

完全二叉树和满二叉树

    满二叉树:除了最后一层叶节点,其他节点都有2个子节点

    完全二叉树: 最后一层从左向右的叶节点连续存在,只缺少右侧若干节点


二叉树的遍历

        先序遍历DLR:先访问根节点,再先序遍历左子树,最后先序遍历右子树

        中序遍历LDR:先中序遍历左子树,再访问根节点,最后中序访问右子树

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


操作二叉树的代码

#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;
	}
}

//添加节点到二叉树 
//添加二叉树的左子节点还是右子节点需要选择
//bt是父节点,node是需要添加的节点,n判断左右 
int BinTreeAdd(ChainBinTree *bt,ChainBinTree *node,int n){
	if(bt==NULL){
		 printf("父结点不存在,请先设置父结点!\n");
        return 0;
	}
	switch(n){
		case 1://添加到左节点
			//.........需要左子节点为空才能添加 ,坑
			if(bt->left){
				printf("左子树结点不为空!\n");
                return 0;
			}else{
				bt->left=node;
			}
		case 2:
			if(bt->right) //右子树不为空 
            {
                printf("右子树结点不为空!\n"); 
                return 0;
            }else
                bt->right=node;
            break;
        default:
            printf("参数错误!\n");
            return 0;
	}
	return 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 BinTreeIsEmpty(ChainBinTree *bt){
	if(bt){
		return 0;
	}else{
		return 1;
	}
}

//计算二叉树深度
/*
一个错误的思路来求解深度,企图利用while循环来判断bt->left==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;
		}else{
			return dep2+1;
		}
	}
 } 
 
//在二叉树中查找相关节点
//思路:递归 ***********************************************************************
// 

ChainBinTree *BinTreeFind(ChainBinTree *bt,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;
			}
		}
	}
}  
//**************************************************************************************

void BinTreeClear(ChainBinTree *bt) // 清空二叉树,使之变为一棵空树
{
     if(bt)
     {
         BinTreeClear(bt->left); //清空左子树 
         BinTreeClear(bt->right);//清空右子树 
         free(bt);//释放当前结点所占内存 
         bt=NULL;
     }
     return; 
}

//参数是一个二叉节点类型指针和一个函数指针,这个函数一般在main里写
//这个函数一般用来对遍历得到的节点进行操作,比如打印数据 
void BinTree_DLR(ChainBinTree *bt,void (*oper)(ChainBinTree *p)){
	if(bt){
		oper(bt);
		BinTree_DLR(bt->left,oper);
		BinTree_DLR(bt->right,oper); 
	} 
	return;
}

//中序 
void BinTree_LDR(ChainBinTree *bt,void (*oper)(ChainBinTree *p)){
	if(bt){
		BinTree_LDR(bt->left,oper);
		oper(bt);
		BinTree_LDR(bt->right,oper); 
	} 
	return;
}

void BinTree_LRD(ChainBinTree *bt,void (*oper)(ChainBinTree *p)) //后序遍历
{
     if(bt)
     {
         BinTree_LRD(bt->left,oper); //后序遍历左子树 
         BinTree_LRD(bt->right,oper); //后序遍历右子树/
         oper(bt); //处理结点数据
     }
     return; 
}

//二叉树按层遍历不适合用递归
//从根节点出发, 
void BinTree_Level(ChainBinTree *bt,void (*oper)(ChainBinTree *p)){

	ChainBinTree *p;
	ChainBinTree *q[QUEUE_MAXSIZE];
	int head,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(bt->left!=NULL){
			tail=(tail+1)%QUEUE_MAXSIZE;
			q[tail]=p->left;
		}
		
		if(bt->right!=NULL){
			tail=(tail+1)%QUEUE_MAXSIZE;
			q[tail]=p->right;
		}	
	} 
	return;
}



    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值