C语言实现数据结构之二叉树

本文详细介绍了如何在编程中构建二叉树,并实现了先序、中序、后序和层序遍历算法。此外,还涉及了计算二叉树宽度、统计度为1的节点数量以及搜索根节点到指定节点的路径。使用了链式存储结构和栈、队列等数据结构进行辅助。
摘要由CSDN通过智能技术生成
任务

建立二叉树,并实现二叉树的先序、中序、后序、层序遍历,求二叉树的宽度,统计二叉树中度为1的结点的个数,求根结点到指定结点的路径。

分析
  • 先序遍历:首先访问根节点,再访问左子树,再访问右子树。
  • 中序遍历:首先访问左子树,再访问根节点,最后访问右子树。
  • 后序遍历:首先访问左子树,再访问右子树,最后访问根节点。
  • 层序遍历:(用队列)设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。
  • 求二叉树的宽度:逐层求每一层的宽度,最宽的那一层的宽度就是二叉树的宽度。
  • 统计度为1的结点个数:即只有左子树或只有右子树的结点个数。
  • 求根节点到指定结点的路径:先序遍历结点,并用链栈储存路径。
存储结构设计
/*存储结构:链式存储*/
#define MaxSize 100
typedef char TElemType;
typedef struct BiNode {
	char data;
	struct BiNode *lchild, *rchild;
} BiNode, *BiTree;
/*导入非递归遍历需要的“栈”头文件*/
typedef BiTree SElemType;
#include "stack.h"
/*导入层序遍历需要的“队列”头文件*/
typedef BiTree QElemType;
#include "queue.h"

//	链栈
typedef struct STACK {

	int data;
	struct STACK *next;

} StackNode,*Stack;
/********************************链栈基本操作*************************************/
//	入栈
void PushStack(char x) {
	Stack top;
	top = (Stack)malloc(sizeof(StackNode));
	top->data = x;
	top->next = L;		//	第一次是让一开始的头结点存入元素,尾巴指向NULL已经初始化好
	L = top;			//	之后便是创建新的链栈结点和之前的串起来
}

//	出栈
char PopStack() {
	int x;

	if(L->next==NULL) {	//	栈空
		printf("出栈完毕\n");
		exit(-1);
	} else {
		Stack p;
		x = L->data;
		p = L;			//	让原来的L变成P
		L = p->next;	//	原来头结点next指向的变成新的头结点
		free(p);		//	释放原来的头结点
		return x;		//	返回原来头结点里头的元素
	}

}
int flag;	//	标记符
Stack L;	//	链栈头结点指针
源代码
/*存储结构:链式存储*/
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 100
typedef char TElemType;
typedef struct BiNode {
	char data;
	struct BiNode *lchild, *rchild;
} BiNode, *BiTree;
/*导入非递归遍历需要的“栈”头文件*/
typedef BiTree SElemType;
#include "stack.h"
/*导入层序遍历需要的“队列”头文件*/
typedef BiTree QElemType;
#include "queue.h"

//	链栈
typedef struct STACK {

	int data;
	struct STACK *next;

} StackNode,*Stack;

int flag;	//	标记符
Stack L;	//	链栈头结点指针

/*二叉树的创建*/
BiTree create() {
	BiTree t;
	TElemType ch;
	scanf("%c", &ch);
	if(ch == '#')
		t = NULL;
	else {
		t = (BiTree)malloc(sizeof(BiNode));
		t->data = ch;
		t->lchild = create();
		t->rchild = create();
	}

	return t;
}
/*先序遍历(递归):先访问根结点,其次遍历左子树,最后遍历右子树*/
void PreOrder(BiTree t) {
	if(t) {
		printf("%c", t->data);
		PreOrder(t->lchild);
		PreOrder(t->rchild);
	}
}
/*中序遍历(递归):先遍历左子树,其次访问根结点,最后遍历右子树*/
void InOrder(BiTree t) {
	if(t) {
		InOrder(t->lchild);
		printf("%c",t->data);
		InOrder(t->rchild);
	}
}
/*后序遍历(递归):先遍历左子树,其次遍历右子树,最后访问根结点*/
void PostOrder(BiTree t) {
	if(t) {
		PostOrder(t->lchild);
		PostOrder(t->rchild);
		printf("%c", t->data);
	}
}

/*先序遍历(非递归)*/
void PreOrder1(BiTree t) {
	SeqStack s;
	BiNode *e;
	InitStack(&s);
	while(t||!StackIsEmpty(&s))		//当t已经没有子结点或栈已空,结束遍历
		if(t) {
			printf("%c", t->data);		//访问
			Push(&s, t);
			t = t->lchild;		//若t仍有左孩子,则继续遍历
		} else {
			Pop(&s, &e);
			t = e->rchild;
		}
}
/*中序遍历(非递归)*/
void InOrder1(BiTree t) {
	BiTree p;
	SeqStack s;
	InitStack(&s);
	while(t||!StackIsEmpty(&s))	//当t已经没有子结点或栈已空,结束遍历
		if(t) {
			Push(&s, t);
			t = t->lchild;		//若t仍有左孩子,则继续遍历
		} else {
			Pop(&s, &p);
			printf("%c", p->data);		//访问
			t = p->rchild;
		}
}
/*层序遍历*/
void Level(BiTree t) {
	BiTree p;
	SeqQueue q;
	InitQueue(&q);
	printf("%c", t->data);
	EnterQueue(&q, t);
	while(!QueueIsEmpty(&q)) {
		DeleteQueue(&q, &p);
		if(p->lchild) {
			printf("%c", p->lchild->data);
			EnterQueue(&q, p->lchild);
		}
		if(p->rchild) {
			printf("%c", p->rchild->data);
			EnterQueue(&q, p->rchild);
		}
	}
}
/*求二叉树的宽度*/
int TreeWidth(BiTree T) {
	if(!T)
		return 0;

	int front = -1, rear = -1;
	int last = 0, ever = 0;		 	//last指向当前层的最右结点
	int max = 0, width = 0;			//max保存最大宽度,width保存本层宽度
	BiTree Q[MaxSize];				//初始化队列Q,元素是二叉树结点指针
	Q[++rear] = T;					//根结点入队
	BiTree p;
	while(front < rear) {			//当队非空,继续循环
		p = Q[++front];  			//p保存当前结点
		width++;  					//宽度+1
		if(p->lchild)
			Q[++rear] = p->lchild;
		if(p->rchild)
			Q[++rear] = p->rchild;
		if(front == last) {			//处理该层的最右结点
			if(max < width)
				max = width; 			//若该层的宽度大于max,替换max
			last = rear;
			width = 0;				//每一层宽度置空一次
		}
	}
	return max;
}
/*统计二叉树中度为1的结点的个数*/
int Count(BiTree T) {
	if(T->lchild == NULL && T->rchild == NULL)		/*某树没有子树*/
		return 0;

	if(T->lchild != NULL && T->rchild != NULL)      /*某结点有左右子树*/
		return Count(T->lchild) + Count(T->rchild);

	else if(T->lchild != NULL && T->rchild == NULL) { /*某结点只有左子树*/
		printf("结点%c\n", T->data);
		return 1 + Count(T->lchild);
	}


	else if(T->lchild == NULL && T->rchild != NULL) { /*某结点只有右子树*/
		printf("%c\n", T->data);
		return 1 + Count(T->rchild);
	}


	return 0;
}
/********************************链栈基本操作*************************************/
//	入栈
void PushStack(char x) {
	Stack top;
	top = (Stack)malloc(sizeof(StackNode));
	top->data = x;
	top->next = L;		//	第一次是让一开始的头结点存入元素,尾巴指向NULL已经初始化好
	L = top;			//	之后便是创建新的链栈结点和之前的串起来
}

//	出栈
char PopStack() {
	int x;

	if(L->next==NULL) {	//	栈空
		printf("出栈完毕\n");
		exit(-1);
	} else {
		Stack p;
		x = L->data;
		p = L;			//	让原来的L变成P
		L = p->next;	//	原来头结点next指向的变成新的头结点
		free(p);		//	释放原来的头结点
		return x;		//	返回原来头结点里头的元素
	}

}
/*******************************************************************************/
/*搜索从根结点到指定结点的路径*/
void CherkNode(BiTree T,int data) {
	if(T==NULL) {
		return;
	}

	if(flag==1) {	//	标记符flag 还是1时,表示还没找到要找的结点
		//printf("入栈元素为: %d\n",T->Data);
		PushStack(T->data); 	//	入栈
	}
	if(T->data == data) {	//	已经在二叉树中遍历到要找的结点元素
		//printf("元素找到,元素为: %d\n",T->Data);
		flag = 0;
		return;
	}

	CherkNode(T->lchild,data);	//	遍历这个结点左子树,为NULL时才结束递归,返回上一级结点
	CherkNode(T->rchild,data);	//	遍历这个结点的右子树,为NULL时返回上一级结点

	if(flag==1) {	//	递归遍历二叉树每条路径中寻找,由于遍历一个结点
		//	就会让元素入栈,以便将后面元素不是要找路径之中的元素,从栈中清除
		//printf("出栈元素: %d\n",T->Data);
		PopStack();	//	清除非要寻找路径上的栈中元素
	}


}
//	搜索路径
void SearchPath(BiTree T,int data) {
	int temp[30];	//	用来存最后找到的路径各个结点里头的数据
	int i;
	flag = 1;		//	标记符

	L = (Stack)malloc(sizeof(StackNode));	//	分配空间给指针
	L->next = NULL;		//	让第一个结点指针指向NULL,最后也就是栈底指针

	if(T==NULL) {	//	空树
		return;
	}

	CherkNode(T,data);	//	搜索二叉树中要找的结点,进行入栈出栈操作

	for(i=0; L->next; i++) {
		temp[i] = PopStack();	//	找到的路径元素逆序存放在数组temp[]中
	}
	printf("路径寻找成功,路径如下:\n");
	for(i--; i>=0; i--) {
		printf("%c ",temp[i]);
	}
}


int main() {
	BiTree t;
	int y;
	int code, i, a, b, order;
	TElemType ch;
	printf("--------------------二叉树基本操作系统----------------\n");
	printf(" | 1.创建二叉树         | | 2.先序遍历               |\n");
	printf("------------------------------------------------------\n");
	printf(" | 3.中序遍历           | | 4.后序遍历               |\n");
	printf("------------------------------------------------------\n");
	printf(" | 5.层序遍历           | | 6.二叉树的宽度           |\n");
	printf("------------------------------------------------------\n");
	printf(" | 7.度为1的结点的个数  | | 8.根结点到指定结点的路径 |\n");
	printf("------------------------------------------------------\n");
	printf(" | 0.退出系统                                        |\n");
	printf("------------------------------------------------------\n");

	for(;;) {
		printf("\n请选择操作:");
		scanf("%d", &code);
		switch(code) {
			case 1:
				printf("请输入一个二叉树:");
				getchar();
				t = create();
				printf("创建成功!\n");
				break;
			case 2:
				PreOrder(t);
				break;
			case 3:
				InOrder(t);
				break;
			case 4:
				PostOrder(t);
				break;
			case 5:
				Level(t);
				break;
			case 6:
				printf("该树的宽度为:%d\n", TreeWidth(t));
				break;
			case 7:
				printf("该树中度为1的结点的个数为:%d\n", Count(t));
				break;
			case 8:
				printf("请输入想要到达的结点:");
				getchar();
				scanf("%c", &ch);
				SearchPath(t, ch);
				break;
			case 0:
				printf("谢谢使用!\n");
				exit(0);
			default:
				printf("暂时不支持该功能!\n");
		}
		getchar();
	}

	return 0;
}
运行结果

  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值