目录
第一章 设计简介
1.1设计背景
二叉树并不适合顺序存储,因为会造成空间浪费的现象。所以,用链式存储结构设计了对二叉树的先序遍历、中序遍历、后序遍历、求二叉树深度、求二叉树的叶子节点数、求二叉树中所有节点个数等函数,可以快速对二叉树进行操作。
1.2总体设计
1.在main中函数调用各个函数首先输入,当输入结束按下回车,输出结果。
2.定义结构体。
3. void CreateBiTree(BiTree *bt)此函数利用先序遍历创建二叉链表。
4. void PreOrder(BiTree root)先序遍历二叉树函数。
5. void InOrder(BiTree root)中序遍历二叉树函数。
6. void PostOrder(BiTree root)后序遍历二叉树函数。
7. void countleaf(BiTree root, int&n)叶子节点数函数。
8. void depth(BiTree root, int &dep)深度函数。
9. int num(BiTree root)所有节点数函数。
10. void LayerOrder(BiTree root)层序二遍历二叉树函数。
第二章 程序核心代码讲解
2.1核心代码与分析
2.1.1代码和分析
1.创建二叉树
typedef struct Node
{
char data; //数据域
struct Node * Lchild;//左孩子域
struct Node * Rchild; //右孩子域
}*BiTNode,*BiTree;
定义二叉树的二叉链表节点的结构,对于任意的二叉树来说,每个节点只有两个孩子,一个双亲节点所以我们设计每个节点包括三个域:数据域、左孩子域和右孩子域。如图:2—1
/* 利用扩展先序遍历序列创建二叉链表*/
void CreateBiTree(BiTree *bt)
{
char ch;
ch = getchar() ;//从键盘输入
if(ch == '.' )
{
*bt = NULL;//判断输入
}
else
{
*bt = (BiTree) malloc (sizeof(BiTNode) ) ;
(*bt) ->data = ch;
CreateBiTree(&((*bt) ->Lchild));
CreateBiTree(&((*bt) ->Rchild));
}
}
通过getchar()输入n个任意的字符,通过malloc申请新节点,节省空间。这一段代码实现了二叉树的建立,二叉树的存储。二叉树的每一个节点都有data域,左孩子域,右孩子树。
2.遍历的操作
/*先序递归遍历二叉树*/
void PreOrder(BiTree root)
{//先序遍历二叉树,root为指向二叉树(或某一字树)根节点的指针。
if(root != NULL)
{
printf("%c ", root->data);//访问根节点
PreOrder(root->Lchild);//先序遍历左子树
PreOrder(root->Rchild);//先序遍历右子树
}
}
/*后序递归遍历二叉树 */
void PostOrder(BiTree root)
{//后序遍历二叉树,root为指向二叉树(或某一字树)根节点的指针。
if(root != NULL)
{
PostOrder(root -> Lchild);//后序遍历左子树
PostOrder(root -> Rchild);//后序遍历右子树
printf("%c ", root->data);//访问根节点
}
}
void InOrder(BiTree root)
{//中序遍历二叉树,root为指向二叉树(或某一字树)根节点的指针。
if(root != NULL)
{
InOrder(root->Lchild);//中序遍历左子树
printf("%c ", root->data);//访问根节点
InOrder(root->Rchild);//中序遍历右子树
}
}
这三种遍历的算法区别在于printf("%c ", root->data);语句的位置不同,但都采用了递归的方法。就是从二叉树的根节点开始,把它的左节点以及左节点下面的节点再当作一棵二叉树,和右节点以及右节点下面的节点也再当作一棵二叉树,依此类推,直到节点下面没有节点为止。
3.求叶子节点数
void countleaf(BiTree root, int&n)
{
if (root)
{
countleaf(root->Lchild, n);
if(!root->Lchild && !root->Rchild)
{
n++;
}
countleaf(root->Rchild, n);
}
}
判断root是否为空,不为空则调用countleaf函数然后再判断如果root->Lchild && root->Rchild为空的话累加n。直到条件不满足,调用count leaf函数。利用函数递归实现叶子节点数的计算。
4.求深度函数
void depth(BiTree root, int &dep)
{
int dep1, dep2;
if(!root)
{
dep=0;
}
else
{
depth(root->Lchild, dep1);
depth(root->Rchild, dep2);
dep=dep1>dep2?dep1+1: dep2+1;
}
}
5.求叶子节点总数函数
int num(BiTree root)
{
if (root == NULL)
{
return 0;
}
else
{
return(num(root->Lchild) + num(root->Rchild)) + 1;
}
}
如果root等于空的话return0结束函数。不为空则通过函数递归累加计算树中所有的节点数。直到条件不满足返回结果在主函数中输出。
6.队列与二叉树的层序遍历
typedef struct QueueNode{
BiTree data;
struct QueueNode *next;
} LinkQueueNode; //队列中的每个节点
typedef struct
{
LinkQueueNode *front;
LinkQueueNode *rear;
} LinkQueue; //队列
/* 队列的初始化 */
void InitQueue(LinkQueue *Q)
{
Q->front = (LinkQueueNode *) malloc(sizeof(LinkQueueNode) ) ;
if(Q->front != NULL) {
Q->rear = Q->front;
Q->front->next = NULL;
} else printf("分配空间失败!\n") ;
}
/* 入队 */
void EnterQueue(LinkQueue *Q, BiTree x)
{
LinkQueueNode *NewNode;
NewNode = (LinkQueueNode *) malloc(sizeof(LinkQueueNode) ) ;
if(NewNode != NULL) {
NewNode->data = x;
NewNode->next = NULL;
Q->rear->next = NewNode;
Q->rear = NewNode;
}
}
/* 队列判空*/
int QueueIsEmpty(LinkQueue *Q)
{
if(Q->front == Q->rear)
return 1;
else return 0;
}
/* 出队*/
void DeleteQueue(LinkQueue *Q, BiTree *x)
{
LinkQueueNode *p;
if(Q->front == Q->rear)
return ;
p= Q->front->next;
Q->front->next = p->next;
if(Q->rear == p)
Q->rear = Q->front;
*x = p->data;
free(p) ;
}
void LayerOrder(BiTree root)
{
BiTree *x;
x = (BiTree *) malloc(sizeof(BiTree) ) ;
if(x == NULL) {
printf("出错!\n") ;
}
LinkQueue *Q;
Q = (LinkQueue *) malloc(sizeof(LinkQueue) ) ;
InitQueue(Q) ;
EnterQueue(Q, root) ;
while(!QueueIsEmpty(Q) ) {
DeleteQueue(Q, x) ;
printf("%c ", (*x) ->data) ;
if((*x) ->Lchild) EnterQueue(Q, (*x) ->Lchild) ;
if((*x) ->Rchild) EnterQueue(Q, (*x) ->Rchild) ;
}
}
二叉树的层序遍历,主要有两个关键要素,一是队列,二是递归,实现算法。对于一个二叉树,层序遍历就是把根结点传进队列,然后进入while循环直到队列为空为止,然后每一次取出队列的队首元素,输出值,然后依次判断是否存在左右子树,如果存在把左右子树进行入列。循环结束,最后输出层序遍历。
先序,中序、后序遍历,对应的是深度优先而层序遍历对应的是广度优先。
7.主函数
int main()
{
int n=0, dep,s;
BiTree root;
CreateBiTree(&root) ;
printf("先序递归遍历: \n");
PreOrder(root);
printf("\n");
printf("中序递归遍历: \n");
InOrder(root);
printf("\n");
printf("后序递归遍历: \n") ;
PostOrder(root);
printf("\n");
depth(root, dep);
printf("深度 dep=%d\n", dep);
countleaf(root, n);
printf("叶子结点数 n=%d\n", n);
printf("\n");
printf("所有节点个数: \n");
s=num(root);
printf("%d\n",s);
return 0;
}
控制台先输入二叉树内容当输入完成后按下回车键依次输出先序遍历结果、中序遍历结果、后序遍历结果、二叉树深度、叶子节点数、所有节点的个数。return0结束程序。
第三章 结果展示
图3-1运行结果
图3-2运行结果
以图3-1的运行结果为例,输入abc..de.g..f...,依次输出函数结果。接下来分析讲解,以先序遍历为例,先让指针指向a节点。按照先序遍历的规则,先输出根节点a。此时递归进入,指针指向b节点,输出b结点,进一步递归进入b节点的左子树输出c。然后递归退层到b节点访问b的右子树输出d。此时a的左子树遍历完成,开始遍历a的右子树指针指向e输出e再依次访问e的左子树和右子树。遍历结束输出abcdegf.
完整代码
#include<stdio.h>
#include<stdlib.h>
typedef struct Node{
char data;
struct Node * Lchild;
struct Node * Rchild;
}*BiTNode,*BiTree; //二叉树节点, 二叉链表
typedef struct QueueNode{
BiTree data;
struct QueueNode *next;
} LinkQueueNode; //队列中的每个节点
typedef struct
{
LinkQueueNode *front;
LinkQueueNode *rear;
} LinkQueue; //队列
/* 队列的初始化 */
void InitQueue(LinkQueue *Q)
{
Q->front = (LinkQueueNode *) malloc(sizeof(LinkQueueNode) ) ;
if(Q->front != NULL) {
Q->rear = Q->front;
Q->front->next = NULL;
} else printf("分配空间失败!\n") ;
}
/* 入队 */
void EnterQueue(LinkQueue *Q, BiTree x)
{
LinkQueueNode *NewNode;
NewNode = (LinkQueueNode *) malloc(sizeof(LinkQueueNode) ) ;
if(NewNode != NULL) {
NewNode->data = x;
NewNode->next = NULL;
Q->rear->next = NewNode;
Q->rear = NewNode;
}
}
/* 队列判空*/
int QueueIsEmpty(LinkQueue *Q)
{
if(Q->front == Q->rear)
return 1;
else return 0;
}
/* 出队*/
void DeleteQueue(LinkQueue *Q, BiTree *x)
{
LinkQueueNode *p;
if(Q->front == Q->rear)
return ;
p= Q->front->next;
Q->front->next = p->next;
if(Q->rear == p)
Q->rear = Q->front;
*x = p->data;
free(p) ;
}
void LayerOrder(BiTree root)
{
BiTree *x;
//这里要记得申请空间
x = (BiTree *) malloc(sizeof(BiTree) ) ;
if(x == NULL) {
printf("出错!\n") ;
}
LinkQueue *Q;
Q = (LinkQueue *) malloc(sizeof(LinkQueue) ) ;
InitQueue(Q) ;
EnterQueue(Q, root) ;
while(!QueueIsEmpty(Q) ) {
DeleteQueue(Q, x) ;
printf("%c ", (*x) ->data) ;
if((*x) ->Lchild) EnterQueue(Q, (*x) ->Lchild) ;
if((*x) ->Rchild) EnterQueue(Q, (*x) ->Rchild) ;
}
}
/* 利用扩展先序遍历序列创建二叉链表*/
void CreateBiTree(BiTree *bt)
{
char ch;
ch = getchar() ;//从键盘输入
if(ch == '.' ) *bt = NULL;//判断输入
else
{
*bt = (BiTree) malloc (sizeof(BiTNode) ) ;
(*bt) ->data = ch;
CreateBiTree(&((*bt) ->Lchild));
CreateBiTree(&((*bt) ->Rchild));
}
}
/*先序递归遍历二叉树*/
void PreOrder(BiTree root)
{
if(root != NULL)
{
printf("%c ", root->data);
PreOrder(root->Lchild);
PreOrder(root->Rchild);
}
}
/*后序递归遍历二叉树 */
void PostOrder(BiTree root)
{
if(root != NULL)
{
PostOrder(root -> Lchild);
PostOrder(root -> Rchild);
printf("%c ", root->data);
}
}
void InOrder(BiTree root)
{
if(root != NULL)
{
InOrder(root->Lchild);
printf("%c ", root->data);
InOrder(root->Rchild);
}
}
void countleaf(BiTree root, int&n)
{
if (root)
{
countleaf(root->Lchild, n);
if(!root->Lchild && !root->Rchild)
{
n++;
}
countleaf(root->Rchild, n);
}
}
void depth(BiTree root, int &dep)
{
int dep1, dep2;
if(!root)
{
dep=0;
}
else
{
depth(root->Lchild, dep1) ;
depth(root->Rchild, dep2) ;
dep=dep1>dep2?dep1+1: dep2+1;
}
}
int num(BiTree root)
{
if (root == NULL)
{
return 0;
}
else
{
return(num(root->Lchild) + num(root->Rchild)) + 1;
}
}
//void PrintTree (BiTree Boot,int nLayer){
// if(Boot==NULL)return;
// PrintTree(Boot->Rchild,nLayer+1);
// for(int i=0;i<nLayer;i++){
// printf("");
// printf("%c\n",Boot->data);
// PrintTree(Boot->Lchild,nLayer+1) ;
// }
//}
int main()
{
int n=0, dep,s;
BiTree root;
CreateBiTree(&root) ;
printf("先序递归遍历: \n");
PreOrder(root);
printf("\n");
printf("中序递归遍历: \n");
InOrder(root);
printf("\n");
printf("后序递归遍历: \n") ;
PostOrder(root);
printf("\n");
printf("层序遍历: \n") ;
LayerOrder(root) ;
printf("\n");
depth(root, dep);
printf("深度 dep=%d\n", dep);
countleaf(root, n);
printf("叶子结点数 n=%d\n", n);
printf("\n");
printf("所有节点个数: \n");
s=num(root);
printf("%d\n",s);
printf("\n");
//PrintTree(root,n);
return 0;
}