二叉树 -- Tree

本文介绍了二叉树的基本概念,包括其定义和有序二叉树的特点。详细阐述了三种遍历方式:先序、中序和后序遍历,并提供了相应的代码实现。此外,还讨论了如何在有序二叉树中插入、查找、删除节点以及修改节点数据的操作。最后,给出了一个简单的main函数示例来展示这些操作的应用。

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

数据结构 – 二叉树



一、定义

说明

  1. 是一种特殊的树,每个节点最多有两个子节点(左节点、右节点)。
  2. 有序二叉树(最核心的二叉树),需要掌握。

下图为有序二叉树,从根节点开始,大小左右排列:

在这里插入图片描述

二、三种遍历方式

  1. 先序遍历:
    处理节点自己的数据 -> 处理左节点 -> 处理右节点

  2. 中序遍历(重点掌握):
    处理左节点 -> 处理节点自己的数据 -> 处理右节点

  3. 后序遍历:
    处理左节点 -> 处理右节点 -> 处理自己的节点

三、数据结构

  1. 定义 Tree 结构,由两部分组成:

定义描述节点的数据结构:

typedef struct node{
    int data;//数据
    struct node *left;//左子树
    struct node *right;//右子树
}node_t;

声明整棵树的数据结构:

typedef struct tree{
    node_t *root;//根节点地址
    int cnt;//节点个数
}tree_t;

三、功能函数

  1. create_node:创建新的节点,malloc 动态创建:
static node_t *create_node(int data)
{
    //分配内存
    node_t *pnode=(node_t *)malloc(sizeof(node_t));
    //初始化节点
    pnode->data=data;
    pnode->left=NULL;
    pnode->right=NULL;
    return pnode;
}
  1. insert_data:向根节点 Tree 中插入新节点 pnode:

定义子函数:proot为根节点,pnode为新节点;

/* 请查看二级指针定义,否则是内存空间上的复制 */
/* 需要针对tree进行操作 */
/* 过程中使用迭代操作,请留意 */
void insert(node_t **proot,node_t *pnode)
{
    //递归函数的退出条件:根节点为空(root,L,R)
    if(NULL==*proot){        //当树只有根节点时
         *proot=pnode;
          return ;   
    }
    //插入到左子树中
    if((*proot)->data > pnode->data){
        insert(&(*proot)->left,pnode);    
        return;
    }else {  //插入到到右子树
        insert(&(*proot)->right,pnode);
        return;
    }  
}

向有序二叉树创建新的节点;

void insert_data(tree_t *tree,int data)
{
    //创建新的节点
    node_t *pnode=create_node(data);
    //调用递归函数进行插入,注意递归法则
    insert(&tree->root,pnode);
    //更新个数
    tree->cnt++; 
}

在这里插入图片描述

  1. travel_data:中序遍历

定义子函数 : travel

void travel(node_t *proot)
{
    //递归函数的结束判断
    if(proot != NULL){
        /*中序遍历*/
        travel(proot->left);//左节点
        printf("%d",proot->data);//处理节点自己
        travel(proot->right); //右节点 
} 

定义调用函数:

void travel_data(tree_t *tree)
{
    //调用递归函数遍历
    travel(tree->root);
    printf("\n");
}

注意 ---- 该遍历过程中需要重点理解递归的流程:

在这里插入图片描述

  1. clear_data:清空二叉树

定义子函数:清除节点的递归函数

void clear(node_t **proot)
{
    if(*proot != NULL)
    {
        //清空左子树
        clear(&(*proot)->left);
        //清空右子树
        clear(&(*proot)->right);
        //释放节点内存
        free(*proot);
        *proot=NULL;    
    }    
}

定义调用函数:

void clear_data(tree_t *tree)
{
     clear(&tree->root);
     tree->cnt=0;   
}

注意----该遍历过程中需要重点理解递归的流程:

在这里插入图片描述

  1. del_data:删除某个节点

定义 find 子函数:在根节点下查找数据

说明:寻找方法同样使用递归,递推查找。

node_t **find(node_t **pproot,int data)
{
    //1. 如果树为空,直接返回
    if(NULL == *pproot){
        return pproot;    
    }
    //2. 比较节点和目标值,若相等返回节点
    if(data == (*pproot)->data){
        return pproot;    
    }
    //3. 如果目标值小于节点的值,左子树找寻
    if(data < (*pproot->data)){
        return find(&(*pproot)->left,data);    
    }
    else {
        return find(&(*pproot)->right,data);  //右子树找              
    }    
}

定义 find_data 调用函数

说明: 传递tree树节点中root的值,root为树节点指向下一节点的节点地址,使用 & 和前面类似,避免内存空间的复制,对root的改变会做用到 本tree;
注意:返回值为 ** 二级指针,表明找到data后,data这个节点就是新的树节点。

 // 传递整个树
node_t **find_data(tree_t *tree,int data)  
{
    //调用递归函数从root开始查找要删除的节点并返回这个节点的地址
    return find(&tree->root,data);    //传递树的首节点
}

定义 del_data 删除节点函数
删除节点的第四点好好体会,其实就是做暂存,然后free掉;

void del_data(tree_t *tree,int data)
{
    //1. 首先要找到删除的节点,返回这个节点的首地址
    node_t **ppnode=find_data(tree,data);
    if (NULL == *ppnode){
        printf("要寻找的目标节点不存在");
        return;    
    }
    
    //2. 如果找到要删除的节点,将节点的左子树插入到右子树
    if((*ppnode)->left != NULL){
            insert(&(*ppnode)->right,(*ppnode)->left);
    }
    
    //3. 将要删除节点的右子树给到要删除节点的父节点的左子树
    node_t *ptemp = *ppnode; //临时暂存
    *ppnode=(*ppnode)->right;
    
    //4. 释放内存
    free(*ptemp);
    *ptemp = NULL; //好习惯
    
    //5. 更新计数
    tree->cnt--;
}
  1. modify_data:修改节点数据;
/*修改元素*/
void modify_data(tree_t *tree,int old_data,int new_data)
{
    //删除旧结点
    del_data(tree,old_data);
    //插入新的节点
    insert_data(tree,new_data);
}
  1. main 函数:功能函数写好之后咱们看看调用;
int main(void)
{
    //1. 种树
    tree_t tree;
    
    //2. 初始化=NULL
    tree.root=NULL
    tree.cnt=0
    
    //3. 添加新节点
     insert_data(&tree,50);

     //采用中序遍历方式
     travel_data(&tree);
     
     //删除40
     del_data(&tree,40);

     //将10修改成250
     modify_data(&tree,10,250);

     return 0;
}

总结

数据结构形式不在多,在于深入理解他在做什么,好好理解树tree

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值