数据结构 day07 基础知识学习 (二叉树 的 前中后遍历 ,插入节点,删除叶子节点, 二叉树的节点个数 )

一.今天有点迷。

二.希望大家看的懂代码 ,我已经很努力写注释了。

三.这次的知识很基础 ,(老师关于 二叉树节点删除的哪里 讲的有点差 ,主要是讲之前没有打好框架   (关于父节点的定义   )   这个代码有运用 函数指针 )

四.老师的代码 (4个文件 )

1.tree.h

2.tree.c

3.main.c

4.makefile


五,代码:

1.tree.h

#ifndef __TREE_H__
#define __TREE_H__

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>

typedef struct tree
{
    void* data;
    struct tree* left_tree;
    struct tree* right_tree;
    struct tree* parent;
}tree,* ptree;

typedef  int (*pcmp)(const void* data1,const void*  data2);
//插入数据

bool tree_insert(tree** t,tree* father, void *data,int size,pcmp cpm_fun);


//中序遍历
void tree_Inorder(tree* p,void (*Print)(const void* data_ptr));
//前序
void tree_preorder(tree* p,void (*Print)(const void* data_ptr));

//后序列
void tree_postorder(tree* p,void (*Print)(const void* data_ptr));


//自己写的 不用递归 
void tree_In(tree * t,void  (*Print)(const void * data_ptr));//中序遍历
void tree_post(tree * t,void  (*Print)(const void * data_ptr));//后序列
void tree_pre(tree * t,void  (*Print)(const void * data_ptr));//前序



//找出数据最大数据的节点
tree* tree_max(tree* t);

//找出二茶树中数据最小的节点
tree* tree_min(tree* t);

//查找data_ptr在二茶树中的位置
tree* tree_find(tree* t,void* data_ptr,pcmp cpm_fun);

//统计节点个数
unsigned int tree_size(tree* t);

//节点删除
bool tree_delete(tree** node,pcmp suju);
#endif


tree.c

/**********************************************

*作者 :she001
*
*
************************************************/

#include "tree.h"
//插入数据
bool tree_insert(tree** t,tree* father, void *data,int size,pcmp cpm_fun)   //寻找合适的叶子节点 插入
{
    if (t == NULL || data == NULL || size <=0 || cpm_fun == NULL)
    {
        return false;
    }
    if(*t == NULL)
    {
        tree* pnew = (tree*)malloc(sizeof(tree));  //开辟节点  , 
        if(pnew == NULL)
        {
            return false;
        }
        pnew->left_tree  = NULL;       //双向的 
        pnew->right_tree = NULL;        
        pnew->parent     = father;
        pnew->data       = malloc(size);  
        if(pnew->data == NULL)
        {
            return false;
        }
        memcpy(pnew->data,data,size);  //内容复制过去   ,memcpy  直接复制内存 
        *t = pnew;                     //二级指针 改变一级指针的指向
        return true;                   
    }
    else
    {
        int temp = cpm_fun((*t)->data,data );               //接口函数 (比较函数  ->  判定中)
        if(temp > 0)                                        // 判定  这个节点的数适合在那里  这里是判定这个树,适合在树的左边 
        {
            return tree_insert(&((*t)->left_tree), *t,data,size,cpm_fun);     //递归 直到找到合适的地方 
        }
        else if(temp < 0)                                   //判定  这个节点的数适合在那里  这里是判定这个树,适合在树的右边
        {
            return tree_insert(&((*t)->right_tree),*t,data,size,cpm_fun);       //递归 直到找到合适的地方 
        }
        else
        {
            return false;                                  //有相同的树  所以 程序程序错误 ,不可以建立新的节点
        }
    }
    
}

//中序遍历
void tree_Inorder(tree* p,void (*Print)(const void* data_ptr))   //加了一个 函数借口  与写一个输出函数差不多   ,主要是老师写的 模板代码  ,但是今天老师的状态不对 思路有点不对  父母节点没写好,有bug 
{
    if(p == NULL)
    {
        return ;
    }
    tree_Inorder(p->left_tree,Print);                  // 递归 遍历二叉树
    Print(p->data);
    tree_Inorder(p->right_tree,Print);                 //递归 遍历二叉树
}
//5 2 8 9 25
/*  伪代码
void tree_Inorder(8)
{
  tree_Inorder(8->left_tree == 2)
  {
        tree_Inorder(2->left_tree)
        p-->2
        tree_Inorder(2->right_tree == 5)
        {
            tree_Inorder(5->left_tree)
             p-->5;
            tree_Inorder(5->right_tree)

        }

  }
  p-->8
  tree_Inorder(8->right_tree == 9)
  {
    tree_Inorder(9->left == NULL)
    p--->9
    tree_Inorder(9-->right === 25)
    {
        tree_Inorder(25->left == NULL)
        P-->25
        tree_Inorder(25->right == NULL)
    }
  }
}

*/
// 前序遍历
void tree_preorder(tree* p,void (*Print)(const void* data_ptr))
{
    if(p == NULL)
    {
        return ;
    }
    Print(p->data);
    tree_preorder(p->left_tree,Print);
    tree_preorder(p->right_tree,Print);
}
//后续遍历
void tree_postorder(tree* p,void (*Print)(const void* data_ptr))
{
    if(p == NULL)
    {
        return ;
    }
    tree_postorder(p->left_tree,Print);
    tree_postorder(p->right_tree,Print);
    Print(p->data);
}
//找出数据最大数据的节点
tree* tree_max(tree* t)
{
    if(t == NULL)
    {
        return NULL;
    }
    if(t->right_tree != NULL)           //从根节点 一直往右边查找 
    {
        return tree_max(t->right_tree);
    }
    return t;
// 2 5 8 9 25
}  
/**
 *  tree* tree_max(8)
 * {
 *      tree_max(8->right === 9)
 *      {
 *        tree_max(9-->right == 25)
 *        {
 *            if(25-->right )
 *         }
 *          return 25;     
 *      }
 * return 9
 * }
*/

//找出二茶树中数据最小的节点
tree* tree_min(tree* t)
{
    if(t == NULL)
    {
        return NULL;
    }
    if(t->left_tree != NULL)
    {
        return tree_min(t->left_tree);            //从根开始 一直往左边查找
    }
    return t;
}

//查找data_ptr在二茶树中的位置
tree* tree_find(tree* t,void* data_ptr,pcmp cpm_fun)
{
    if(t == NULL || data_ptr == NULL|| cpm_fun == NULL)
    {
        return NULL;
    }
    int temp = cpm_fun(t->data  ,data_ptr);                  //接口函数判断 这个数该往什么地方(左 或 右) 去找对比的数据
    if(temp < 0)
    {
        return tree_find(t->right_tree,data_ptr,cpm_fun);     //往左遍历
    }
    else if(temp > 0)
    {
        return tree_find(t->left_tree,data_ptr,cpm_fun);      //往右遍历
    }else
    {
        return t;
    }
}

//统计节点个数  2 5 8 9 25
unsigned int tree_size(tree* t)            
{
    if (t == NULL)
    {
        return 0;
    }
    return tree_size(t->left_tree)+tree_size(t->right_tree)+1;     //递归的调用    是一个节点 它就会加一 空节点不会 
}
/*

tree_size(8)
{
    tree( 2 ) + tree(9) + 1
    tree(2)
    {
        return  tree(0) + tree(5) +1;
    }
    tree(9)
    {
        return  tree(0) + tree(25) +1;
    }
}
*/

//删除node节点
bool tree_delete(tree** node,pcmp suju) //  只修改叶子节点 (老师的思路不太清晰)
{
    if(*node == NULL)
    {
        return false;
    }
    //左子树 和右子树 都为NULL  说明是叶子节点  只修改叶子节点
    if((*node)->left_tree == NULL && (*node)->right_tree == NULL)
    {
        int mm = suju((*node)->data,(*node)->parent->data);
        if(mm)   //写的程序 把void * 类型的 确定下来了 
        {
            (*node)->parent->right_tree = NULL;                          //把这个节点的父母节点的右节点指向空  
        }
        else
        {
            (*node)->parent->left_tree = NULL;                          //把这个节点的父母节点的左节点指向空  
        }
        free((*node)->data);   //释放节点数据
        free((*node));          //释放  节点 
        (*node)->parent = NULL;  //防止野指针
        return true;
    }
    return false;
}



void tree_In(tree * t,void  (*Print)(const void * data_ptr))//中序遍历
{
    if(t ==NULL)
    {
        printf("空间开辟失败!\n");
        return; 
    }
    //准备一个栈
    ptree stack[100];
    int stack_num=-1 ;
    ptree temp = t;
    while(stack_num!=-1 || temp!=NULL )
    {
        while(temp!=NULL)
        {
             
            stack[++stack_num]=temp;
            temp=temp->left_tree;
        }
        if(stack_num!=-1) //注意打印过的数据,其指针不再进栈 数据思路还行
        {
            temp=stack[stack_num--];
            Print(temp->data);              //先打左节点 再打本身 
            temp=temp->right_tree;
        }
    }
}

void tree_post(tree * t,void  (*Print)(const void * data_ptr))//后序列
{
    if(t ==NULL)
    {
        printf("空间开辟失败!\n");
        return; 
    }
    //准备一个栈
    ptree stack[100];
    int stack_num=-1 ;
    ptree temp = t;
    ptree plastVisit=NULL; //访问标记
    while(temp!=NULL )
    {   
        stack[++stack_num] =temp;
        temp=temp->left_tree;  //先移到 最左边
    }
    while(stack_num!=-1)
    {
        temp=stack[stack_num--];
        if(temp->right_tree==NULL || temp->right_tree==plastVisit)
        {
            Print(temp->data);    //到了节点打印数据 或者右边的树已经打过
            plastVisit=temp;   //标记这个最右的节点已经走过
        }
        else
        {
            stack[++stack_num]=temp;   
            temp=temp->right_tree;
            while(temp!=NULL)
            {
                stack[++stack_num]=temp;
                temp=temp->left_tree;
            }

        }
    }

}
void tree_pre(tree * t,void  (*Print)(const void * data_ptr))//前序
{
     if(t ==NULL)
    {
        printf("空间开辟失败!\n");
        return; 
    }
    //准备一个栈
    ptree stack[100];
    int stack_num=-1 ;
    ptree temp = t;
    while(stack_num!=-1 || temp!=NULL)  //开始因为 节点不是空的所以可以进去
    {
        while(temp!=NULL)
        {
            Print((temp->data));
            stack[++stack_num] = temp;  //走过的路需要记载 进栈
            temp=temp->left_tree;
        }
        if(stack_num!=-1)
        {
            temp=stack[stack_num];       
            stack_num--;
            temp=temp->right_tree;   //看看这个节点的右节点
        }
    }


}


















main.c

#include "tree.h"
#include <time.h>

int int_cmp_fun(const void* data1,const void*  data2)  //数据插入树中 的函数
{
    if(data1 ==NULL || data2 == NULL)
    {
        return 0;
    }
    return (*(int*)data1) - (*(int*)data2);
}

void Print(const void* data_ptr)              // 打印函数
{
    if(data_ptr == NULL)
    {
        return ;
    }
    printf("%d\t",*(int*)data_ptr);

}

int  bijiao(const void* data1,const void * data2) //删除二叉树节点所利用的函数
{
    if(data1 ==NULL || data2 == NULL)
    {
        return 0;
    }
    return (*(int*)data1) - (*(int*)data2);
}
int main()
{
    srand(time(NULL));
    tree* t = NULL;
    int arr[6] = {4,2,8,0,5,7} ;
    for(int i  = 0 ; i < 6;++i)
    {
        tree_insert(&t,NULL,&arr[i],sizeof(int),int_cmp_fun);
    }  
    tree* ptemp = tree_min(t);       //查找最小树的空间节点
    printf("\n%d\n",*((int*)(ptemp->data)));
    unsigned int gg =tree_size(t); 
    tree_In(t,Print);
    printf("\n");
    printf("树的空间节点数目为:%u\n",gg);
    tree_post(t,Print);


    /*
    tree_Inorder(t,Print);          //中序遍历
    printf("\n-------------------\n");
    tree_postorder(t,Print);        //后序遍历
    printf("\n-------------------\n");
    tree_preorder(t,Print);         //前序遍历
    printf("\n-------------------\n");
    ptemp = tree_find(t,&arr[3],int_cmp_fun);     //查找 0 这个数据的节点
    tree_delete(&ptemp,bijiao);                   //删除之前 找到的节点
    tree_Inorder(t,Print);                         //中序遍历
    printf("\n-------------------\n");
    ptemp = tree_find(t,&arr[5],int_cmp_fun);       //查找 7 这个数据的节点
    tree_delete(&ptemp,bijiao);                     //删除之前 找到的节点
    tree_Inorder(t,Print);                            //中序遍历
   
    ptemp = tree_max(t);                           //查找最大树的空间节点
    printf("\n%d\n",*(int*)(ptemp->data));         //打印这个节点 的数据
    */
    return 0;
}

makefile

OUT : tree.o main.o 
	gcc -g main.o tree.o -o OUT
tree.o : tree.c
	gcc -g -c tree.c -o tree.o
main.o : main.c
	gcc -g -c main.c -o main.o 
clean:
	rm *.o OUT

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值