您的位置:首页 > 理论基础 > 数据结构算法

数据结构-二叉树的基本操作

2017-11-05 10:04 465 查看
目标效果:



dsp0603.cpp页面;

#include <stdio.h>
#include <stdlib.h>

#define ElemType char //二叉树中数据元素类型
#include "bintree.h"  //二叉树的实现

//打印结点数据(作为Visit函数)
Status print(char);
//计算二叉树中叶子结点的个数
int LeafCount(BiTree bt);
//计算二叉树的深度
int Deapth(BiTree bt);
//按缩进方式打印二叉树
void PrintTreeIndent(BiTree bt, int indent);

///////////////////////////////////////////////////////////
// 主程序
int main()
{
BiTree bt = 0;

//建立二叉树
printf("建立二叉树(按先序输入二叉树中的结点,空格表示空树)\n");
if( CreateBiTree(bt)==ERROR ) {
printf("ERROR: call CreateBiTree\n");
system("pause");
exit(1);
}
PrintTree(bt);

//遍历二叉树
printf("\n先序遍历: ");
if( PreOrderTraverse(bt)==ERROR )
printf("ERROR: call PreOrderTraverse\n");
printf("\n中序遍历: ");
if( InOrderTraverse(bt)==ERROR )
printf("ERROR: call InOrderTraverse\n");
printf("\n后序遍历: ");
if( PostOrderTraverse(bt)==ERROR )
printf("ERROR: call PostOrderTraverse\n");

printf("\n按层遍历: ");
if( LevelOrderTraverse(bt)==ERROR )
printf("ERROR: call LevelOrderTraverse\n");
//二叉树的应用
printf("\n二叉树中叶子结点的个数: %d\n", LeafCount(bt));
printf("\n二叉树的深度: %d\n", Deapth(bt));
printf("\n按缩进形式打印:\n");
PrintTreeIndent(bt,1);

//销毁二叉树
DestroyBiTree(bt);

system("pause"); //暂停以便查看结果
return 0;
}

///////////////////////////////////////////////////////////
// 函数实现

//计算二叉树中叶子结点的个数
int LeafCount(BiTree bt)
{
if(!bt)          //结点为空
return 0;
if(!bt->lchild&&!bt->rchild)      //没有子节点了
return 1;
else
return LeafCount(bt->lchild)+LeafCount(bt->rchild);
}

//计算二叉树的深度
int Deapth(BiTree bt)
{
int height,leftH,rightH;     //左右子树的深度和最深的深度
if(!bt)
height=0;
else{
leftH=Deapth(bt->lchild);
rightH=Deapth(bt->rchild);
if(leftH>rightH)
height=leftH+1;
else
height=rightH+1;;
}
return height;
}

//按缩进方式打印二叉树
void PrintTreeIndent(BiTree bt, int indent)
{
if(bt){
for(int i=0;i<10-indent;i++)     //这里固定了以10减,正常最规范的应该用树的深度减
printf(" ");
printf("%c",bt->data);
printf("\n");
PrintTreeIndent(bt->lchild,indent+1);
PrintTreeIndent(bt->rchild,indent+1);
}
}


bintree.h页面:
#ifndef BINTREE_H_INCLUDED
#define BINTREE_H_INCLUDED

#include <stdlib.h>
#include "ds.h"

//数据元素的缺省类型用char
#ifndef ElemType
#define ElemType char
#define ELEMTYPE_TAG
#endif
/*下面使用TElemType如同ElemType*/
#define TElemType ElemType
#define QElemType BiTree     //队列元素为二叉树指针类型,所以这里不是普通的char类型
#define MAXQSIZE 100
///////////////////////////////////////////////////////////
// 二叉链表类型
typedef struct BiTNode {
TElemType data;
struct BiTNode *lchild, *rchild; //左右孩子指针
} BiTNode, *BiTree;
//循环队列类型定义
typedef struct{
QElemType *base;
int front;
int rear;
}SqQueue;

//初始化队列
Status InitQueue(SqQueue &Q);
//元素入队
Status EnQueue(SqQueue &Q,QElemType e);
//元素出队
Status DeQueue(SqQueue &Q,QElemType &e);
//销毁队列
Status DestroyQueue(SqQueue &Q);
//队列判空
Status QueueEmpty(SqQueue Q);
// 二叉链表的基本操作

//新建二叉链表结点
BiTree MakeNode(TElemType e, BiTree lch, BiTree rch)
{
BiTree p = (BiTree)malloc(sizeof(BiTNode));
p->data = e;
p->lchild = lch;
p->rchild = rch;
return p;
}

//按先序次序输入二叉树中的结点值(字符)构造二叉树
Status CreateBiTree(BiTree &T)
{
char ch;
read(ch); // NOTE: 这里用字符类型
if( ch==' ' ) //空格代表空指针
T = 0;
else {
T=(BiTree)malloc(sizeof(BiTNode));
if(!T)
return ERROR;
else{
T->data=ch;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
}
return OK;
}

//销毁二叉树
Status DestroyBiTree(BiTree &T)
{
T=NULL;
return OK;
}

//先序遍历二叉树T,对每个结点数据调用Visit函数
Status PreOrderTraverse(BiTree T)
{
if(T){
printf("%c",T->data);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
return OK;
}

//中序遍历二叉树T,对每个结点数据调用Visit函数
Status InOrderTraverse(BiTree T)
{
if(T){
InOrderTraverse(T->lchild);
printf("%c",T->data);
InOrderTraverse(T->rchild);
}
return OK;
}

//后序遍历二叉树T,对每个结点数据调用Visit函数
Status PostOrderTraverse(BiTree T)
{
if(T){
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
printf("%c",T->data);
}
return OK;
}

//按层次顺序遍历二叉树T,对每个结点数据调用Visit函数
Status LevelOrderTraverse(BiTree T)
{
//将每一层的节点分别入队列,然后分别读取,读取后继续将它们的子节点入队,所以保证是按照一层一层来遍历的
BiTree P=T;
SqQueue Q;
InitQueue(Q);   //初始化队列
if(P)
{
EnQueue(Q,P);
while(!QueueEmpty(Q))
{
DeQueue(Q,P);   //出队列
printf("%c",P->data);
if(P->lchild)
EnQueue(Q,P->lchild);
if(P->rchild)
EnQueue(Q,P->rchild);
}
}
DestroyQueue(Q);
return OK;
}

//以直观方式打印二叉树
void PrintTree(BiTree t, int level=0)
{
int i;
if(t) {
PrintTree(t->rchild, level+1);
for(i=0; i<level; i++) printf("    ");
write(t->data); write('\n');
PrintTree(t->lchild, level+1);
}
}

//构造一个空队列
Status InitQueue(SqQueue &Q)
{
Q.base=(QElemType *)malloc(MAXQSIZE*sizeof(QElemType));
if(!Q.base)
return ERROR;
Q.front=Q.rear=0;
return OK;
}
//元素入队
Status EnQueue(SqQueue &Q,QElemType e)
{
if((Q.rear+1)%MAXQSIZE==Q.front)
return ERROR;
Q.base[Q.rear]=e;
Q.rear=(Q.rear+1)%MAXQSIZE;
return OK;
}
//元素出队
Status DeQueue(SqQueue &Q,QElemType &e)
{
if(Q.front==Q.rear)
return ERROR;
e=Q.base[Q.front];
Q.front=(Q.front+1)%MAXQSIZE;
return OK;
}
//判断队列是否为空
Status QueueEmpty(SqQueue Q)
{
if(Q.rear==Q.front)
return OK;
else
return ERROR;
}
//销毁队列
Status DestroyQueue(SqQueue &Q)
{
if(!Q.base)
return ERROR;
Q.rear=Q.front;
free(Q.base);
return OK;
}
//取消缺省类型的定义以免影响其它部分
#ifdef ELEMTYPE_TAG
#undef ElemType
#undef ELEMTYPE_TAG
#endif

#endif //BINTREE_H_INCLUDED


说几个小问题:
1.项目里有层次遍历,需要使用队列存储,我偷懒直接复制的前边博客里循环队列操作的代码,结果出现以下错误,return还不变成蓝色(code blocks中return等关键字是蓝色),百度是因为中文空格和英文空格的原因,只要把空格都删掉然后重新在英文输入法中把空格重新敲一遍就行了的。



2.循环队列我定义了100个元素,这也就意味着层次遍历时,结点个数最多为99个,不知道循环队列插入时判满后能不能再进行动态分配,课本上是没讲的,如果不能的话存储用链式队列比较好,对个数没要求。
3.凹入打印那里,因为空格个数递减,所以我是用一个初始值10减去一个递增变量,正确初始值应该为树的深度,因为每一层的长度一样,最多有个数为深度的不同凹入情况,但是因为输入的都是简单树,加上循环队列那里就对结点个数有要求了,所以这里就不那样写了,自己明白就好。

我的项目一般都会在学校机房里做前半部分,环境为VC6.0,后半部分是在自己电脑上做的,环境为code blocks,最近几次在电脑上都是新建一个项目,删掉main函数后导入几个操作页面,但是修改后还是修改的原先那个vc项目,并且在原项目中是运行的之前的结果的,我上传的也是原项目,所以如果下载源码,不要直接运行debug中的那个exe文件,打开后编译运行一下就好。

源码链接:点击打开链接
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: