C 树

//树

#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;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值