二叉树的建立及相关操作

二叉树的建立及相关操作


二叉树的建立及其相关的操作是数据结构学科当中相当重要的一个内容,也是应用非常广泛的一种经典结构,本文力图通过五个大模块向大家分别介绍:建立二叉树,三序遍历二叉树,给出叶子结点,显示二叉树,销毁二叉树。的全过程。希望大家对这部分只是有一个深入的理解。
    我们在文章中设计实现了一个抽象数据类型二叉树的演示程序。对程序的功能定义是这样的:
设计实现ADT Bitree 的 create, traverse, insert, delete 等基本操作;
设计可操作的应用界面:
待加工的数据为字符型,在过程中键入;
需要建立的子程序算法如下:
[1]建立一棵二叉树;
[2]给出三序遍历树后的结点序列( 字符数据 ) ;
[3]给出叶子结点( 字符数据 );
[4]显示二叉树;
[5]清理空间;
[6]可执行的主程序中要给出可选的菜单:
1.Create Binary Tree from keyboard;
2.Create Binary Tree from file;
3.Write tree data to file;
4.PreOrder travel;
5.InOrder travel
6.PostOrder travel
7.Show leaves
8.Display the structure of the binary tree
9.Clear binary tree data
10.Exit

问题设计和总体设计
本题共分五个大模块:建立二叉树,三序遍历二叉树,给出叶子结点,显示二叉树,销毁二叉树。由菜单决定执行哪个功能模块。
详细设计
1、从键盘建立二叉树
采用先序遍历的顺序进行创建,并输入数据,由键盘输入每个节点的数据,当输入为“#”时,当前操作的节点指针为NULL,采用先左子树后右子树的顺序函数根据输入数据的形式,生成相应的二叉树结构。
2、从文件建立二叉树
3、三序遍历二叉树
分别采用先序、中序、后序遍历二叉树。
4、出叶子节点
给出叶子节点,可以在任何一种遍历的算法中进行。如果某节点的左孩子和右孩子均不存在,那么此节点就是此二叉树的叶子节点。
5、显示二叉树
本程序采用图形模式形象地输出二叉树的空间结构,采用层次遍历的算法分层访问每一个节点,并计算相应的屏幕坐标,将二叉树居中显示。
6、空二叉树
采用后序遍历实现二叉树的清空操作。
测试数据
输入或文件中的数据序列为: ABC##D##E#F##
先序遍历: ABCDEF
中序遍历: CBDAEF
后序遍历: CDBFEA
显示叶子节点: CDF
图形模式下显示二叉树的空间结构如下图



程序简要使用说明
使用二叉树时必须先建立二叉树,建立的方式可以是直接输入,可以是从文件读取, 但必须先建立,清空后如果要继续操作也要重新建立二叉树,否则程序将会提示错误,用户只需按照提示做即可,数据的输入格式请参照测试数据。
程序源代码提供如下:
#include <stdio.h>
#include <malloc.h>
#include <conio.h>
#include <stdlib.h>
#include <math.h>
#include <graphics.h>

#define OVERFLOW -2
#define R 10

FILE *fp=NULL;
char FileName[20];

int Max( int a, int b)
{
return a>b?a:b;
}
struct BintreeNode
{
char Data;
BintreeNode *lChild,*rChild;
int Left,Top,Right,Bottom,OX,OY;
};
struct LeavesPtrNode
{
BintreeNode *LeavesPtr;
LeavesPtrNode *Next;
};
struct DrawingQueue
{
LeavesPtrNode *pHead,*pTail;
int Length;
};

void PostOrder(BintreeNode *t, void (*visit)(BintreeNode *));

void Visit(BintreeNode *t)
{
if(t) pr intf("%c",t->Data);
}

void DeleteNode(BintreeNode *t)
{
if(t) free(t);
}

void WriteDataToFile(BintreeNode *t)
{
if(t)
{
putc(t->Data,fp);
WriteDataToFile(t->lChild);
WriteDataToFile(t->rChild);
}
else
putc('#',fp);
}

char InputFromKeyboard()
{
return getche();
}

char InputFromFile()
{
return getc(fp);
}

void CreateBintree(BintreeNode **t, char (*InOperation)())
{
char ch;
ch=InOperation();
if(ch=='#')
*t=NULL;
else
{
*t=(BintreeNode*)malloc(sizeof(BintreeNode));
if(!*t)
exit(OVERFLOW);
(*t)->Data=ch;
CreateBintree(&(*t)->lChild,InOperation);
CreateBintree(&(*t)->rChild,InOperation);
}
}

void DeleteB intree(BintreeNode *t)
{
PostOrder(t,DeleteNode);
}

void PreOrder(BintreeNode *t, void (*visit)(BintreeNode *t))
{
if(t)
{
visit(t);
PreOrder(t->lChild,visit);
PreOrder(t->rChild,visit);
}
}
void InOrder(BintreeNode *t, void (*visit)(BintreeNode *t))
{
if(t)
{
InOrder(t->lChild,visit);
visit(t);
InOrder(t->rChild,visit);
}
}

void PostOrder(BintreeNode *t, void (*visit)(BintreeNode *t))
{
if(t)
{
PostOrder(t->lChild,visit);
PostOrder(t->rChild,visit);
visit(t);
}
}

void SetContent(BintreeNode *t, int iOX, int iOY)
{
t->OX=iOX;
t->OY=iOY;
t->Left=iOX-R;
t->Top=iOY-R;
t->Right=iOX+R;
t->Bottom=iOY+R;
}

void DrawLeaves(BintreeNode *t)
{
circle(t->OX,t->OY,R);
char s[2];
s[0]=t->Data;
s[1]='/0';
outtextxy(t->OX-3,t->OY-3,s);
}

void ConnectLeaves(BintreeNode *t1,BintreeNode *t2)
{
line(t1->OX,t1->Bottom,t2->OX,t2->Top);
}

int GetB intreeHeight(BintreeNode *t)
{
if(t==NULL)
   return 0;
else
   return 1+Max(GetB intreeHeight(t->lChild),GetB intreeHeight(t->rChild));
}
void InitQueue(DrawingQueue *qu)
{
qu->pHead=qu->pTail=NULL;
qu->Length=0;
}

void EnQueue(DrawingQueue *qu,BintreeNode *t)
{
LeavesPtrNode *p=NULL;
p=(LeavesPtrNode*)malloc(sizeof(LeavesPtrNode));
p->LeavesPtr=t;
p->Next=NULL;
if(qu->Length==0)
{
  qu->pTail=qu->pHead=p;
} else
{
  qu->pTail->Next=p;
  qu->pTail=qu->pTail->Next;
}
qu->Length++;
}

void DeQueue(DrawingQueue *qu,BintreeNode **t)
{
  LeavesPtrNode *p=qu->pHead;
   if(qu->Length==0)
  {
   *t=NULL;
   return;
  }
   if(qu->Length==1)
    qu->pHead=qu->pTail=NULL;
   else
    qu->pHead=qu->pHead->Next;
  *t=p->LeavesPtr;
  free(p);
  qu->Length--;
}
void DrawTree(BintreeNode *t, int TreeWidth, int RootX, int RootY)
{
   int CurrentLevelLeaves=0,NextLevelLeaves=0,Distance,CurrentLevel=0;
   int NextLevelStartX,NextLevelY;
  BintreeNode *pLeaves;
  DrawingQueue queue;
  InitQueue(&queue);
  EnQueue(&queue,t);
  SetContent(t,RootX,RootY);
  CurrentLevelLeaves++;
  CurrentLevel++;  //CurrentLevel=1;
  while(queue.Length>0)
  {
   Distance=TreeWidth/pow(2,CurrentLevel-1);
   NextLevelY=RootY+2*(2*CurrentLevel)*2*R;
   while(CurrentLevelLeaves>0)
   {
    DeQueue(&queue,&pLeaves);
    DrawLeaves(pLeaves);
//    pr intf(" %c",pLeaves->Data);
     if(pLeaves->lChild!=NULL)
    {
     SetContent(pLeaves->lChild,pLeaves->OX-Distance/2,NextLevelY);
     ConnectLeaves(pLeaves,pLeaves->lChild);
     EnQueue(&queue,pLeaves->lChild);
     NextLevelLeaves++;
    }
     if(pLeaves->rChild!=NULL)
    {
     SetContent(pLeaves->rChild,pLeaves->OX+Distance/2,NextLevelY);
     ConnectLeaves(pLeaves,pLeaves->rChild);
     EnQueue(&queue,pLeaves->rChild);
     NextLevelLeaves++;
    }
    CurrentLevelLeaves--;
   }
   CurrentLevelLeaves=NextLevelLeaves;
   NextLevelLeaves=0;
   CurrentLevel++;
  }
}

void main()
{
int TreeWidth,TreeHeight,LogicalHeight,RootX,RootY,Choice;
int Driver=DETECT,Mode;
BintreeNode *pRoot=NULL;
while(1)
{
printf("/n1.Create Binary Tree from keyboard/n");
printf("2.Create Binary Tree from file/n");
printf("3.Write tree data to file/n");
printf("4.PreOrder travel/n");
printf("5.InOrder travel/n");
printf("6.PostOrder travel/n");
printf("7.Show leaves/n");
printf("8.Display the structure of the binary tree/n");
printf("9.Clear binary tree data/n");
printf("10.Exit/n");
printf("Please select an opertation:");
scanf("%d",&Choice);
switch(Choice)
{
   case 1:
     if(pRoot)
     DeleteBintree(pRoot);
    CreateBintree(&pRoot,InputFromKeyboard);
    printf("Create tree OK/n");
     break;
   case 2:
    printf("Please input the file name:");
    scanf("%s",FileName);
    fp=fopen(FileName,"rt");
     if(!fp)
    {
     printf("Can not open such file/n");
     break;
    }
     if(pRoot)
     DeleteBintree(pRoot);
    CreateBintree(&pRoot,InputFromFile);
    fclose(fp);
    printf("Read file OK/n");
     break;
   case 3:
     if(!pRoot)
    {
     printf("The tree is not created/n");
     break;
    }
    printf("Please input the dest file name:");
    scanf("%s",FileName);
    fp=fopen(FileName,"wt");
     if(!fp)
    {
     printf("Can not open such file/n");
     break;
    }
    WriteDataToFile(pRoot);
    fclose(fp);
    printf("Write file OK/n");
     break;
   case 4:
     if(!pRoot)
    {
     printf("The tree is not created/n");
     break;
    }
    PreOrder(pRoot,Visit);
     break;
   case 5:
     if(!pRoot)
    {
     printf("The tree is not created/n");
     break;
    }
    InOrder(pRoot,Visit);
     break;
   case 6:
     if(!pRoot)
    {
     printf("The tree is not created/n");
     break;
    }
    PostOrder(pRoot,Visit);
     break;
   case 7:
     break;
   case 8:
     if(!pRoot)
    {
     printf("The tree is not created!/n");
     break;
    }
    LogicalHeight=GetBintreeHeight(pRoot);
    TreeWidth=2*R*(pow(2,LogicalHeight-1)*2-1);
    TreeHeight=2*R*(2*LogicalHeight-1);
     if(TreeWidth>639||TreeHeight>479)
    {
     printf("Sorry,the tree is too big to be displayed!/n");
     break;
    }
    initgraph(&Driver,&Mode,"..//bgi");
    RootX=(getmaxx()+1)/2;
    RootY=(getmaxy()+1-TreeHeight)/2;
    DrawTree(pRoot,TreeWidth,RootX,RootY);
    getch();
    closegraph();
     break;
   case 9:
     if(!pRoot)
    {
     printf("The tree is not created/n");
     break;
    }
    DeleteBintree(pRoot);
    pRoot=NULL;
     break;
   case 10:
     if(pRoot!=NULL) DeleteBintree(pRoot);
    exit(0);
}
}
}


   二叉树是一种非常重要的数据结构,几乎任何数据结构都可以用二叉树来表示,二叉树的衍生结构可以应用于很多结构描述上,因此熟练的掌握二叉树的操作方法,对实际程序编写有很大促进,对锻炼自己的算法意识也有好处。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
二叉树是一种非常重要的数据结构,其建立和遍历操作算法的设计和复杂度分析也是非常重要的。下面是二叉树建立和遍历操作算法的分析与设计。 1. 二叉树建立算法 二叉树建立有两种方式:递归法和非递归法。 递归法建立二叉树的过程如下: - 如果当前节点为NULL,则返回NULL。 - 如果当前节点不为NULL,则创建一个新节点,并且为其赋值。 - 递归建立左子。 - 递归建立右子。 - 返回当前节点。 非递归法建立二叉树的过程如下: - 创建一个空栈。 - 读入根节点,将其入栈。 - 如果当前节点不为NULL,则创建一个新节点,并且为其赋值。 - 如果当前节点的左子不为空,则将其入栈。 - 否则,将当前节点弹出栈,并且读入右子。 - 重复步骤3-5,直到栈为空。 二叉树建立算法的时间复杂度是O(n),其中n是二叉树中节点的个数。 2. 二叉树的遍历算法 二叉树的遍历分为三种:前序遍历、中序遍历和后序遍历。 前序遍历的算法如下: - 如果当前节点不为空,则输出当前节点的值。 - 递归遍历左子。 - 递归遍历右子。 中序遍历的算法如下: - 递归遍历左子。 - 如果当前节点不为空,则输出当前节点的值。 - 递归遍历右子。 后序遍历的算法如下: - 递归遍历左子。 - 递归遍历右子。 - 如果当前节点不为空,则输出当前节点的值。 三种遍历算法的时间复杂度都是O(n),其中n是二叉树中节点的个数。 总的来说,二叉树建立和遍历操作算法的设计和复杂度分析是非常重要的基础知识,对于算法和数据结构的学习和应用都有重要的作用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值