树结构是一类重要的非线性数据结构,树在计算机领域中也得到广泛应用,尤以二叉树最为常用。如在操作系统中,用树来表示文件目录的组织结构,在编译系统中,用树来表示源程序的语法结构,在数据库系统中,树结构也是信息的重要组织形式之一。在这里,我们会详细讲解二叉树。
二叉树( Binary Tree)是n(n≥0)个结点所构成的集合,它或为空树(n=O)或为非空树,对于非空树T:(1)有且仅有一个称之为根的结点;
(2)除根结点以外的其余结点分为两个互不相交的子集T和T,分别称为T的左子树和右子树,且T和T本身又都是二叉树。
二叉树与树一样具有递归性质,二叉树与树的区别主要有以下两点:
(1)二叉树每个结点至多只有两棵子树(即二叉树中不存在度大于2的结点);
(2)二叉树的子树有左右之分,其次序不能任意颠倒。
二叉树的递归定义表明二叉树或为空,或是由一个根结点加上两棵分别称为左子树和右子树的、互不相交的二叉树组成。由于这两棵子树也是二叉树,则由二叉树的定义,它们也可以是空树。由此,二叉树可以有5种基本形态,如图所示。

遍历二叉树是二叉树最基本的操作,也是二叉树其他各种操作的基础,遍历的实质是对二叉树进行线性化的过程,即遍历的结果是将非线性结构的树中结点排成一个线性序列。由于二叉树的每个结点都可能有两棵子树,因而需要寻找一种规律,以便使二树上的结点能排列在一个线性队列上,从而便于遍历。
二叉树是由3个基本单元组成:根结点、左子树和右子树。因此,若能依次遍历这三部分,便是遍历了整个二叉树。假如从L、D、R分别表示遍历左子树、访问根结点和遍历右子树,则可有DLR、LDR、LRD、DRL、RDL、RLD这6种遍历二叉树的方案。若限定先左后右,则只有前3种情况,分别称之为先(根)序遍历、中(根)序遍历和后(根)序遍历。下面介绍二叉树的遍历:
1.二叉树的递归遍历
(1)先序遍历(根节点、左子树、右子树)
PreOrderTraverse(BiTree T){
if(T){
visit(T->data);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
}
(2)中序遍历(左子树、根节点、右子树)
InOrderTraverse(BiTree T){
if(T){
InOrderTraverse(T->lchild);
visit(T->data);
InOrderTraverse(T->rchild);
}
}
(3)后序遍历(左子树、右子树、根节点)
PostOrderTraverse(BiTree T){
if(T){
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
visit(T->data);
}
}
2.二叉树的非递归
(1)先序遍历(根节点、左子树、右子树)
void PreOrder2(BiTree T){
BiTree stack[MAXSIZE], BiTNode;
int top = -1;
if (T == NULL){
printf("树空\n");
return;
}
else{
top++;
// 仿照一个栈
stack[top] = T; // 将根节点入栈
while (top > -1){
//出栈
BiTNode = stack[top--];
printf(" %c ", BiTNode->data);
// 先把右子树放进去,栈是先进去后出,所以下面的左子树先出
if (BiTNode->rchild != NULL){
stack[++top] = BiTNode->rchild; // 入栈
}
if (BiTNode->lchild != NULL){
stack[++top] = BiTNode->lchild;
}
}
}
}
(2)中序遍历(左子树、根节点、右子树)
void InOrder2(BiTree T){
BiTree stack[MAXSIZE], BiTNode;
int top = 0;
// 判断树是否为空
if (T == NULL){
printf("树空\n");
return;
}
BiTNode = T;
while (BiTNode != NULL || top > 0){
// 将所有的左子树节点入栈
while (BiTNode != NULL){
stack[++top] = BiTNode;
BiTNode = BiTNode->lchild;
}
// 如果右节点为空的话,执行下列语句
BiTNode = stack[top--];
printf(" %c ", BiTNode->data);
// 扫描右节点
BiTNode = BiTNode->rchild;
}
}
(3)后序遍历(左子树、右子树、根节点)
void PostOrder2(BiTree T){
BiTNode *p = T;
BiTNode *stack[MAXSIZE];
int num = 0;
BiTNode *have_visited = NULL;
while (NULL != p || num>0)
{
while (NULL != p)
{
stack[num++] = p;
p = p->lchild;
}
p = stack[num - 1];
if (NULL == p->rchild || have_visited == p->rchild)
{
printf(" %c ", p->data);
num--;
have_visited = p;
p = NULL;
}
else
{
p = p->rchild;
}
}
}
3.层次遍历
void Level_traversal(BiTree T){
if (T == NULL){
printf("树空\n");
return;
}
BiTree stack[MAXSIZE], BiTNode;
BiTNode = T;
int front = 0; // 使用 front, rear模拟队列
int rear = 0;
stack[rear++] = BiTNode;
while (front != rear){
BiTNode = stack[front++]; // 模拟队列,先获取front当前元素,然后在指向 front ++ 位元素
printf(" %c ", BiTNode->data);
// 左右子树入队列
if (BiTNode->lchild != NULL){
stack[rear++] = BiTNode->lchild;
}
if (BiTNode->rchild != NULL){
stack[rear++] = BiTNode->rchild;
}
}
}
完整代码如下:
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
// 二叉树的实现
// 定义 二叉树的 结构体
typedef struct BiTNode{
char data;
struct BiTNode *lchild;
struct BiTNode *rchild;
}BiTNode, *BiTree;
// 依据前序遍历创建二叉树
BiTree CreateBiTree(){
BiTNode *T = NULL;
char c;
scanf("%c", &c);
if (c != '#'){
T = (BiTNode*)malloc(sizeof(BiTNode));
T->data = c;
T->lchild = CreateBiTree(); // 递归创建
T->rchild = CreateBiTree();
}
else{
T = NULL;
}
return T;
}
// 递归前序遍历二叉树
void PreOrder1(BiTree T){
if (T != NULL){
printf(" %c ", T->data);
PreOrder1(T->lchild);
PreOrder1(T->rchild);
}
}
// 非递归前序遍历二叉树
void PreOrder2(BiTree T){
BiTree stack[MAXSIZE], BiTNode;
int top = -1;
if (T == NULL){
printf("树空\n");
return;
}
else{
top++;
// 仿照一个栈
stack[top] = T; // 将根节点入栈
while (top > -1){
//出栈
BiTNode = stack[top--];
printf(" %c ", BiTNode->data);
// 先把右子树放进去,栈是先进去后出,所以下面的左子树先出
if (BiTNode->rchild != NULL){
stack[++top] = BiTNode->rchild; // 入栈
}
if (BiTNode->lchild != NULL){
stack[++top] = BiTNode->lchild;
}
}
}
}
// 递归中序遍历二叉树
void InOrder1(BiTree T){
if (T != NULL){
InOrder1(T->lchild);
printf(" %c ", T->data);
InOrder1(T->rchild);
}
}
// 非递归实现中序遍历二叉树
void InOrder2(BiTree T){
BiTree stack[MAXSIZE], BiTNode;
int top = 0;
// 判断树是否为空
if (T == NULL){
printf("树空\n");
return;
}
BiTNode = T;
while (BiTNode != NULL || top > 0){
// 将所有的左子树节点入栈
while (BiTNode != NULL){
stack[++top] = BiTNode;
BiTNode = BiTNode->lchild;
}
// 如果右节点为空的话,执行下列语句
BiTNode = stack[top--];
printf(" %c ", BiTNode->data);
// 扫描右节点
BiTNode = BiTNode->rchild;
}
}
// 递归后序遍历二叉树
void PostOrder1(BiTree T){
if (T != NULL){
PostOrder1(T->lchild);
PostOrder1(T->rchild);
printf(" %c ", T->data);
}
}
// 非递归实现后序遍历
void PostOrder2(BiTree T){
BiTNode *p = T;
BiTNode *stack[MAXSIZE];
int num = 0;
BiTNode *have_visited = NULL;
while (NULL != p || num>0)
{
while (NULL != p)
{
stack[num++] = p;
p = p->lchild;
}
p = stack[num - 1];
if (NULL == p->rchild || have_visited == p->rchild)
{
printf(" %c ", p->data);
num--;
have_visited = p;
p = NULL;
}
else
{
p = p->rchild;
}
}
}
// 层次遍历,打印出二叉树的值
void Level_traversal(BiTree T){
if (T == NULL){
printf("树空\n");
return;
}
BiTree stack[MAXSIZE], BiTNode;
BiTNode = T;
int front = 0; // 使用 front, rear模拟队列
int rear = 0;
stack[rear++] = BiTNode;
while (front != rear){
BiTNode = stack[front++]; // 模拟队列,先获取front当前元素,然后在指向 front ++ 位元素
printf(" %c ", BiTNode->data);
// 左右子树入队列
if (BiTNode->lchild != NULL){
stack[rear++] = BiTNode->lchild;
}
if (BiTNode->rchild != NULL){
stack[rear++] = BiTNode->rchild;
}
}
}
int main(){
printf("请按先序输入二叉树:\n");
BiTree T = CreateBiTree();
printf("递归前序遍历:\n");
PreOrder1(T);
printf("\n");
printf("递归中序遍历:\n");
InOrder1(T);
printf("\n");
printf("递归后序遍历:\n");
PostOrder1(T);
printf("\n");
printf("非递归实现前序遍历:\n");
PreOrder2(T);
printf("\n");
printf("非递归实现中序遍历:\n");
InOrder2(T);
printf("\n");
printf("非递归实现后序遍历:\n");
PostOrder2(T);
printf("\n");
printf("层次遍历:\n");
Level_traversal(T);
printf("\n");
return 0;
}
本文详细介绍了二叉树的概念及其在操作系统、编译系统和数据库系统中的应用。接着,阐述了二叉树与普通树的区别,并列举了二叉树的5种基本形态。重点讲解了二叉树的三种遍历方式——先序遍历、中序遍历和后序遍历,分别给出了递归和非递归的实现方法。最后,展示了层次遍历的实现过程。

1231

被折叠的 条评论
为什么被折叠?



