数据结构之二叉树

本文详细介绍了二叉树的基本概念及其链式存储结构,并提供了C语言实现示例。同时,深入探讨了二叉排序树的构建、遍历及删除操作,通过实例演示了如何利用二叉排序树进行数据的高效管理。

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

二叉树:二叉树是每个节点最多有两个子树的树结构

二叉树分两种:顺序结构的二叉树和链式存储的二叉树

但前者容易造成空间的浪费,所以适合用于完全二叉树
而二叉树链表就不会出现这样的问题

一、二叉树链表结构: lchild-data-rchild
一个数据域和两个指针域,分别存放左孩子和右孩子的指针
这里写图片描述

二叉树链表C代码实现:

#include "string.h"
#include "stdio.h"    
#include "stdlib.h"   
#include "io.h"  
#include "math.h"  
#include "time.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAXSIZE 100 /* 存储空间初始分配量 */

//二叉树分两种:顺序结构的二叉树和链式存储的二叉树
//但前者容易造成空间的浪费,所以适合用于完全二叉树
//而二叉树链表就不会出现这样的问题
// 二叉树链表:  lchild-data-rchild
//一个数据域和两个指针域,分别存放左孩子和右孩子的指针


#define ClearBiTree DestroyBITree; 

typedef int Status ;
int index = 1;

typedef char String[24];   //在这里我们把0号单元存放字符串的长度
String str;
typedef char Ele;
Ele Nil = ' ';            //Nil为空 



//赋值字符数组
Status StrAssign(String T,char *chars){

    int i;
    if(strlen(chars)>MAXSIZE){
        return ERROR;
    }else{
        T[0] = strlen(chars);

        for(i=1;i<=T[0];i++){

            T[i] = *(chars+i-1);

        }
    }

    return OK;
}

//定义二叉树链表的数据结构
typedef struct BiTNode{
    Ele data;                    //数据域 
    struct BiTNode *lchild,*rchild;  //两个指针域 
}BiTNode,*BiTree;

 //初始化为空的空二叉树
 Status InitBiTree(BiTree *T){
    *T = NULL;
    return OK;
 } 
//摧毁一个二叉树,递归实现
void DestroyBiTree(BiTree *T){

    if(*T){
        if((*T)->lchild){

            DestroyBiTree(&(*T)->lchild);    //销毁左孩子树 
        }
        if((*T)->rchild){

            DestroyBiTree(&(*T)->rchild);   //销毁右孩子树 
        }

        free(*T);
        *T = NULL;
    }
} 

//构造二叉树
//这里我们使用  # 作为空的判断,并赋值为NULL 
//继续递归实现 
void CreateBiTree(BiTree *T) {

    Ele ch;
    ch = str[index++];

    if(ch=='#'){

        *T = NULL;

    } else{

        *T = (BiTree)malloc(sizeof(BiTNode));  //分配结点
        if(!*T){
            return;   //如果分配失败,返回 
        }

         (*T)->data = ch;  //赋值
         CreateBiTree(&(*T)->lchild);//构造左结点
         CreateBiTree(&(*T)->rchild);//构造右结点

    }

}
//是否为空? 
Status BiTreeEmpty(BiTree T){
    if(T){
        printf("该二叉树不为空\n");
        return FALSE;
    }else{
        printf("该二叉树为空\n");
        return TRUE;
    }
} 

//返回二叉树的深度
//递归的终止条件为0;
//由于return 对于i和j进行+1操作,
//所以实现了逐级递增 
int BiTreeDepth(BiTree T){

    int i,j;
    if(!T){
        return ERROR;
    }
    if(T->lchild){
        i = BiTreeDepth(T->lchild); 
    }else{
        i = 0;
    }

    if(T->rchild){
        j = BiTreeDepth(T->rchild);
    }else{
        j = 0;
    }

    return i>j?i+1:j+1;
} 

//返回二叉树的根
Ele Root(BiTree T){

    if(BiTreeEmpty(T)){

        return Nil;

    }else{

        return T->data;
    }
}

//三种遍历方式
//前序
void PreOrder(BiTree T){

    if(T==NULL){
        return;
    }
    printf("%c ",T->data);   /* 先结点,显示结点数据 */      //根-->左-->右 
    PreOrder(T->lchild);     //再左子树 
    PreOrder(T->rchild);     //右子树 

}
//中序
void MiddleOrder(BiTree T){
    if(T==NULL){
        return ;
    }
    MiddleOrder(T->lchild);           //左-->根--->右 
    printf("%c ",T->data);
    MiddleOrder(T->rchild);

}
//后序
void PostOrder(BiTree T){
    if(T==NULL){
        return;
    }

    PostOrder(T->lchild);         //左-->右-->根 
    PostOrder(T->rchild);
    printf("%c ",T->data); 

}


int main(){

    int i;
    BiTree T;
    Ele e;
    InitBiTree(&T); 
    StrAssign(str,"ABDH#K###E##CFI###G#J##");
    CreateBiTree(&T);
    printf("树的深度=%d \n\n",BiTreeDepth(T));
    printf("树的根=%c \n",Root(T));

    //前序遍历
    printf("前序遍历:");
    PreOrder(T);
    printf("\n");

    //中序遍历
    printf("中序遍历:");
    MiddleOrder(T);
    printf("\n");

    //后序遍历 
    printf("后序遍历:");
    PostOrder(T);
    printf("\n\n");

    //清空 
    printf("清空后\n");
    DestroyBiTree(&T); 
    BiTreeEmpty(T); 

    return 0;
}

这里写图片描述

二、二叉排序树

一般我们把小于结点p放在p结点的左边–p->lchild,将大于p结点的放在右边–p->rchild.

删除结点图:
1、
这里写图片描述

2、
这里写图片描述

#include "stdio.h"    
#include "stdlib.h"   
#include "io.h"  
#include "math.h"  
#include "time.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100 /* 存储空间初始分配量 */


typedef int Status;

//二叉树结构 
typedef struct BiTNode{

    int data;
    struct BiTNode *lchild,*rchild;  
}BiTNode,*BiTree;

/* 递归查找二叉排序树T中是否存在key, */
/* 指针f指向T的双亲,其初始调用值为NULL */
/* 若查找成功,则指针p指向该数据元素结点,并返回TRUE */
/* 否则指针p指向查找路径上访问的最后一个结点并返回FALSE */

Status SearchBiTree(BiTree T,int key,BiTree f,BiTree *p){

    if(!T){  //查找不成功 

        *p = f;
        return FALSE;
    }else if(key==T->data){   //查找成功 
        *p = T;
        return TRUE;
    }else if(key<T->data){
        return SearchBiTree(T->lchild,key,T,p);    //继续左子树查找 
    }else {
        return SearchBiTree(T->rchild,key,T,p);    //继续右子树找 
    }

}

//插入一个点(数据) 
Status InsertBiTree(BiTree *T,int key){

    BiTree p,s;
    if(!SearchBiTree(*T,key,NULL,&p)){

        s = (BiTree)malloc(sizeof(BiTNode));   //新结点 
        s->data = key;
        s->lchild = s->rchild = NULL;

        if(!p){          //如果查找的二叉树刚好为空,则插入作为根结点 

            *T = s;

        }else if(key<p->data){   //插入左边 

            p->lchild = s;

        }else if(key>p->data){   //插入右边 

            p->rchild = s;
        }

        return TRUE;    //不是关键字,并且插入成功 

    }else{

        return FALSE;  //说明是二叉树的关键字 
    }
} 

//删除一个结点p
Status Delete(BiTree *p){

    BiTree q,s;
    if((*p)->rchild==NULL){   //右空,只需重接左结点 

        q = *p;
        *p = (*p)->lchild;
        free(q);

    }else if((*p)->lchild==NULL){  //左空, 只需重接右结点

        q =*p;
        *p = (*p)->rchild;
        free(q);

    }else{                    //左右均不为空,那就需要重接左右结点 

        q = *p;
        s = (*p)->lchild;     //先转左边,然后右到尽头,最终找到删除点的前驱,, 
        while(s->rchild){     //个人觉得这里的删除并不是唯一的,也可以先右再左 ,                   
            q = s;            //只要符合大小的排序就行
            s = s->rchild;
        }
        (*p)->data = s->data;  

        if(q!=(*p)){
            q->rchild = s->lchild;  /*  重接q的右子树 */ 
        }else{
            q->lchild = s->lchild;/*  重接q的左子树 */
        } 
        free(s);

    }

    return TRUE;
} 

//递归找到要删除的结点
Status DeleteBiTree(BiTree *T,int key){

    if(!T){
        return FALSE;
    }else if((*T)->data == key){
        Delete(T);
    }else if(key<(*T)->data){
        return DeleteBiTree(&(*T)->lchild,key);
    }else{
        return DeleteBiTree(&(*T)->rchild,key);
    }
} 

//遍历
 void PreOrderTraverse(BiTree T)
{ 
    if(T==NULL)
        return;
    printf("%d ",T->data);/* 显示结点数据,可以更改为其它对结点操作 */
    PreOrderTraverse(T->lchild); /* 再先序遍历左子树 */
    PreOrderTraverse(T->rchild); /* 最后先序遍历右子树 */
}

int main(){

    int arr[10] = {62,88,58,47,35,73,51,99,37,93};
    BiTree T = NULL;
    int i;
    //此时将数组变成一颗排序二叉树比较简单
    for(i=0;i<10;i++){
        InsertBiTree(&T,arr[i]);
    } 
    //当画出图后,我们用前序遍历的遍历出来的结果和输出的结果是一致的 
    PreOrderTraverse(T);
    printf("\n"); 

    DeleteBiTree(&T,47);
    PreOrderTraverse(T);
    printf("\n");
    DeleteBiTree(&T,93);    
    PreOrderTraverse(T);

    return 0;
}

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值