任务
建立二叉树,并实现二叉树的先序、中序、后序、层序遍历,求二叉树的宽度,统计二叉树中度为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;
}