二叉链表实现

注意事项:

  1. 使用abcd###e##c#f## 来进行先序输入。或者最后两个为空格,否则会一直提示输入。
  2. 重点关注层序遍历,因为其特性,所以需要一个队列数据结构来进行配合。
  3. 结点拥有的子树数为结点的度,度为0的结点为叶子结点,树的度是树内各结点度的最大值,二叉树即度为二的树。树中结点的最大层次称为树的深度。
  4. 出现半小时BUG:在创建函数定义中使用%d期待输入数字,但实际操作中输入了字母,会导致编译错误。
  5. 半小时BUG2:在队列的出队列函数中,没有设置如果是出列的是最后一个,将尾指针指向头指针。否则会出现尾指针是野指针的情况。
  6. 20分钟BUG3:如果有两个Creat函数都接受字符串输入的情况下,第一个确认输入的ENTER键会在缓冲区保留,直到第二个Creat函数接受字符时接受,导致树无法正确创建!!!用吃回车函数解决。
  7. 半小时BUG4:Destroy函数未正确使用递归!导致调用其的Delete函数也无法使用。
#define QElemtype BiTree
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct BiTNode
{
	char data;
	struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;
 
typedef struct QNode
{
	QElemtype data;
	struct QNode * next;
}QNode, *QueuePtr;
typedef struct
{
	QueuePtr front, rear;
}LinkQ, *LinkQueue;
 
void InitQueue(LinkQueue *q);
void EnQueue(LinkQueue q, QElemtype t);
void DeQueue(LinkQueue q, QElemtype *t);
void DestroyQueue(LinkQueue *q);
int QueueEmpty(LinkQueue q);
 
void CreatBiTree(BiTree *t);//这里由于要递归输入值,所以不能用返回指针值的方法改变结构指针
							//只能用指向指针的指针来做形参!
若二叉树非空,则依次执行以下操作
	⑴ 建立根结点;
	⑵ 建立左子树;
	⑶ 建立右子树。
 
 
void DestroyBiTree(BiTree *t);
void DeleteChild(BiTree p, int LR);//这里根节点没用,LR为01为指示左右孩子。
void InsertChild(BiTree p, int LR, BiTree c);
//P指向二叉树某结点,c与t不相交,且c的右子树为空。
//根据LR为01,插入c为t中p所指结点的左右子数。p所指结点的原左子树或右成为c的右子树
void PreOrderTraverse(BiTree t);
/*若二叉树为空,则空操作,否则:
1. 访问根结点;
2. 先序遍历左子树;
3. 先序遍历右子树*/
void InOrderTraverse(BiTree t);
void PostOrderTraverse(BiTree t);
void LevelOrderTraverse(BiTree t);
 
int main()
{
	BiTree t = NULL;
	CreatBiTree(&t);
	PreOrderTraverse(t);
	printf("NULL\n");
	BiTree p = t->lchild;
	char ch;
	while ((ch = getchar()) != '\n')
		continue;
 
	BiTree c = NULL;
	printf("The second Tree is :\n");
	CreatBiTree(&c);
	PreOrderTraverse(c);
	printf("NULL\n");
	InsertChild(p, 1, c);
	printf("After inserting the left Tree:\n");
	PreOrderTraverse(t);
	printf("NULL\n");
	p = t->lchild->lchild;
	DeleteChild(p, 0);
	printf("The process is finish!\n");
	PreOrderTraverse(t);
	return 0;
}
 
void CreatBiTree(BiTree *t)//先序创建
{
	char ch;
	scanf_s("%c", &ch);
	if (ch == ' ')//出口
		*t = NULL;
	else
	{
		*t = (BiTree)malloc(sizeof(BiTNode));
		if (!*t)
			exit(1);
		(*t)->data = ch;
		CreatBiTree(&((*t)->lchild)); //可以看成:用降阶的自己重复函数的内容
	CreatBiTree(&((*t)->rchild));/*每个递归层都是不同的个体。每一层的递归都可以单独看成//一个树,故可把递归语句看做黑箱,忠诚的降阶执行,直到//出口的到来。出口可以看做想要降阶到什么层次。*/
	}
 
}
void DestroyBiTree(BiTree *t)//递归语句另一层意思是:当用到递归的时候说明是从最下面的点开始的
{
	if (*t)
	{
		if ((*t)->lchild)//找到左右都没有结点的叶子结点开始删除
			DestroyBiTree(&((*t)->lchild));//这两个IF语句同时满足了才能继续进行
		if ((*t)->rchild)
			DestroyBiTree(&((*t)->rchild));
		free(*t);
		(*t) = NULL;
	}
}
void DeleteChild(BiTree p, int LR)//这里根节点没用,删除P所指结点的左或右子树(01标识)。
{
	if (LR == 0)
		DestroyBiTree(&(p->lchild));
	else
		DestroyBiTree(&(p->rchild));
}
void InsertChild(BiTree p, int LR, BiTree c)//插入C(右子树空)为T中P所指结点的左或右子树
{//p所指结点的原左或右子树成为c的右子树
	if (p)
	{
		if (LR == 0)
		{
			c->rchild = p->lchild;
			p->lchild = c;
		}
		else
		{
			c->rchild = p->rchild;
			p->rchild = c;
		}
	}
	else
		exit(1);
 
}
void PreOrderTraverse(BiTree t)//每次递归,都相当于将本次函数运行压入栈中,等到遇到出口,在一一弹出栈,直到所有的栈都弹出结束。这里结束方式是,所有栈为空。
{
	if (t)
	{
		printf("%c->", t->data);
		PreOrderTraverse(t->lchild);
		PreOrderTraverse(t->rchild);
	}
}
void InOrderTraverse(BiTree t)
{
	if (t)
	{
		InOrderTraverse(t->lchild);
		printf("%c ", t->data);
		InOrderTraverse(t->rchild);
	}
}
void PostOrderTraverse(BiTree t)
{
	if (t)
	{
		PostOrderTraverse(t->lchild);
		PostOrderTraverse(t->rchild);
		printf("%c ", t->data);
	}
}
void LevelOrderTraverse(BiTree t)
{
	LinkQ o;
	LinkQueue q = &o; //或者为其指向分配空间
	QElemtype a;
	if (t)
	{
		InitQueue(&q);
		EnQueue(q, t);
		while (!QueueEmpty(q))
		{
			DeQueue(q, &a);
			printf("%c->", a->data);
			if (a->lchild != NULL)
				EnQueue(q, a->lchild);
			if (a->rchild != NULL)
				EnQueue(q, a->rchild);
		}
		printf("NULL\n");
		DestroyQueue(&q);
	}
}
void InitQueue(LinkQueue *q)
{
	(*q)->front = (*q)->rear = (QueuePtr)malloc(sizeof(QNode));
	(*q)->front->next = NULL;
}
void EnQueue(LinkQueue q, QElemtype t)
{
	QueuePtr p = (QueuePtr)malloc(sizeof(QNode));
	p->data = t;
	(*q).rear->next = p;
	p->next = NULL;
	(*q).rear = p;
}
void DeQueue(LinkQueue q, QElemtype *t)
{
	if (q->front == q->rear)
		exit(1);
	QueuePtr p = (*q).front->next;
	q->front->next = p->next;
	(*t) = p->data;
	if (q->rear == p)
		q->rear = q->front;
	free(p);
}
void DestroyQueue(LinkQueue *q)
{
	while ((*q)->front)
	{
		(*q)->rear = (*q)->front->next;
		free((*q)->front);
		(*q)->front = (*q)->rear;
	}
 
}
int QueueEmpty(LinkQueue q)
{
	if (q->front == q->rear)
		return 1;
	else
		return 0;
}

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值