//树
#ifndef _TREE_H_
#define _TREE_H_
typedef struct linkNode
{
struct btree *p;
struct linkNode *next;
}link_node;
typedef struct linkqueue
{
struct linkNode *front;
struct linkNode *rear;
}link_queue;
typedef struct btree
{
char data;
struct btree *lchild;
struct btree *rchild;
}btree_node;
#endif
#include "tree.h"
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
// 队列
link_queue *create_queue(void)
{
link_queue *q = (link_queue *) malloc(sizeof(link_queue));//队列创建
q->front = (link_node *) malloc(sizeof(link_node)); //数据域 头创建
if(q == NULL || q->front == NULL)
{
perror("malloc");
exit(-1);
}
q->front->next = NULL;
q->rear= q->front;
return q;
}
void enter_queue(btree_node *t,link_queue *q)//操作的是 指针里面的内容 的时候 用的一级指针就好
{
link_node *new = (link_node *)malloc(sizeof(link_node));//数据 节点申请
if(new == NULL)
{
perror("malloc");
exit(-1);
}
new->p = t; //放入数据
new->next = NULL;
q->rear->next = new;//将数据节点 加载到 队列 指向的 数据域 链表当中
q->rear = q->rear->next;//队尾 指向 新加入的数据 节点
}
bool is_empty_queue(link_queue *q)
{
if(q->front == q->rear)//队首 与 队尾 重合时 队列为null
{
printf("队列为NULL");
return true;
}
else
{
return false;
}
}
//才做的是 指针的 指向 用的是二级指针
void out_queue(link_queue *q,btree_node **t)// 这里一定要使用二级指针 传下来的是 存放 节点地址 的地址
{
//如果t 采用一级指针接收的话 就和 普通变量的传递是一样的 一级指针的接收
//可以看成 是指针赋值问题 函数调用结束以后 t会被释放
if(!is_empty_queue(q))
//所以用二级指针 将指针的地址引入
//至于入队的操作 由于已经申请了内存 可以直接用一级指针去接收节点地址
{
link_node *temp = NULL;
temp = q->front;//free
q->front = q->front->next;//队首指向 要出队的 节点
*t = q->front->p;//出队
free(temp);
}
}
void delete_queue(link_queue *q)
{
free(q);
}
///
// 栈操作
link_node *init_stack()//返回栈顶指针
{
link_node *top = (link_node *)malloc(sizeof(link_node));
if(top == NULL)
{
perror("malloc");
exit(-1);
}
top->next = NULL;
return top;
}
//入栈 相当于 链表的头插法 先进后出
void push_stack(btree_node *t,link_node *top)//操作的是 top指针的内容 所以用的一级指针
{
link_node *new = (link_node *)malloc(sizeof(link_node));
if(new == NULL)
{
perror("malloc");
exit(-1);
}
new->p = t;//头插法加载节点
new->next = top->next;
top->next = new;
}
bool is_empty_stack(link_node *top)
{
return ( (top->next==NULL )? true:false);
}
void pop_stack(btree_node **t,link_node *top)//
{
link_node *p = top->next;
if(!is_empty_stack(top))//不是空栈
{
(*t) = p->p;
top->next = p->next;
free(p);
}
}
void delete_stack(link_node *top)
{
if(top->next == NULL)
{
printf("栈已空");
free(top);
}
}
/
void create_btree(btree_node **t)// 节点的地址
{
char ch;
scanf("%c",&ch); //这里 为什么 要用 二级指针: 不管你指针指向谁 你的指针的地址 都不会改变
//因为当传入的 lchild rchild 是一级指针的话 它指向的是节点的地址 开始是NULL 进行malloc 它会返回新的地址
//当传入的是 lchild rchild 二级指针 它是存放一级指针的地址 的话 lchild 的地址虽然会改变 但是存放它们地址 的指针不会改变,不管指针指向谁 其指针的地址是不变的
//二级指针 就是 为了解决 传入 一级指针时 节点地址被 malloc 返回所覆盖的问题
if(ch == '#')
{
*t = NULL; //节点的值
}
else
{
*t = (btree_node *)malloc(sizeof(btree_node));
if(*t == NULL)
{
perror("malloc");
exit(-1);
}
(*t)->data = ch; //第一次创建 根
//每一次递归 都是优先 填入左子节点 当左子节点输入# 再填入右子节点 结束后 再填入一上层的右子节点 直到返回 到根
//进入右子树的创建 同样从上到下 每层的左子节点输入完毕后 再每层返回 进行右子节点的输入
create_btree(&(*t)->lchild);//左子树
create_btree(&(*t)->rchild);//右子树
}
}
void pre_order(btree_node *t)//先序 遍历 第一次碰到 节点 就输出
{
if(t != NULL)
{
printf("%c ",t->data);//根节点 先输出
pre_order(t->lchild);
pre_order(t->rchild);
}
}
void mid_order(btree_node *t)//中序 遍历 第二次碰到 节点 就输出 此时 根节点 一定位于中间某个位置
{
if(t != NULL)
{
mid_order(t->lchild);
printf("%c ",t->data);//根节点 先输出
mid_order(t->rchild);
}
}
void post_order(btree_node *t)//后序 遍历 最后一次 (应该说第三次) 碰到节点再输出
{
if(t != NULL)
{
post_order(t->lchild);
post_order(t->rchild);
printf("%c ",t->data);//根节点 先输出
}
}
void level_order(btree_node *t) //按照 层次遍历二叉树
{
link_queue *p = NULL;
p = create_queue();//创建一个队列 返回一个队列指针
if(p== NULL)
{
printf("create fail\n");
}
while(t != NULL)
{
printf("%c ",t->data);//d
if(t->lchild != NULL)
{
enter_queue(t->lchild,p);//t 入栈 以后 被改变了 t不再是t
}
// if else if 的多分支语句中 当某 条件最先 满足 就会去执行里面的内容 其它分支的条件判断 就不会再执行了
if(t->rchild != NULL)
{
enter_queue(t->rchild,p);
}
if( !is_empty_queue(p) )
{
out_queue(p,&t);//传递一定是 t 指针的地址 否则会改变原先t的指向
}
else
{
break;
}
}
delete_queue(p);//释放队列
}
//先访问节点 当右子节点不为nuLL 入栈
//当左子节点 不为NULL 时 遍历
//当左子节点为null时 出栈
void unpre_order(btree_node *t)//利用栈的先序 非递归遍历
{
link_node * top = init_stack();//创建栈
while(t!= NULL || !is_empty_stack(top))//当是节点为0 栈为空栈跳出循环
{
if(t != NULL)
{
printf("%c ",t->data);
if(t->rchild != NULL)//右子节点都入栈了
{
push_stack(t->rchild,top);
}
t = t->lchild;//当左子节点不为NULL时 继续遍历
//否则 t== NULL 就会出栈
}
else
{
pop_stack(&t,top);//
}
}
delete_stack(top);
}
//回调函数设定
//
void traval(char *str,void (*pfun)(btree_node *),btree_node *t)
{
printf("%s\n",str);
pfun(t);
printf("\n");
}
int main()
{
btree_node *t;
create_btree(&t);
/*
printf("先序递归遍历\n");
pre_order(t);
putchar(10);
printf("中序递归遍历\n");
mid_order(t);
putchar(10);
printf("后序递归遍历\n");
post_order(t);
putchar(10);
printf("基于队列的层次遍历\n");
level_order(t);
printf("基于栈的非递归遍历\n");
unpre_order(t);
*/
traval("先序递归遍历",pre_order,t);
traval("中序递归遍历",mid_order,t);
traval("后序递归遍历",post_order,t);
traval("基于队列的层次递归遍历",level_order,t);
traval("基于栈的非递归遍历",unpre_order,t);
return 0;
}
C 树
最新推荐文章于 2024-08-29 22:43:47 发布