二叉树的建立及相关操作 |
|
二叉树的建立及其相关的操作是数据结构学科当中相当重要的一个内容,也是应用非常广泛的一种经典结构,本文力图通过五个大模块向大家分别介绍:建立二叉树,三序遍历二叉树,给出叶子结点,显示二叉树,销毁二叉树。的全过程。希望大家对这部分只是有一个深入的理解。 我们在文章中设计实现了一个抽象数据类型二叉树的演示程序。对程序的功能定义是这样的: 设计实现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); } } } 二叉树是一种非常重要的数据结构,几乎任何数据结构都可以用二叉树来表示,二叉树的衍生结构可以应用于很多结构描述上,因此熟练的掌握二叉树的操作方法,对实际程序编写有很大促进,对锻炼自己的算法意识也有好处。 |