一.今天有点迷。
二.希望大家看的懂代码 ,我已经很努力写注释了。
三.这次的知识很基础 ,(老师关于 二叉树节点删除的哪里 讲的有点差 ,主要是讲之前没有打好框架 (关于父节点的定义 ) 这个代码有运用 函数指针 )
四.老师的代码 (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