本设计应用折半查寻法的技术思想进行查寻,从本思想出发,可以有两种数据组织方式:一是应用链表进行组织数据,由于折半查寻法的特殊性,所要进行查寻的数据列必须是有序的数据列,这样要求对数据列进行排序。出于系统实时查寻的考虑,每次对通信录进行改变后都得进行重新排序,这样才能保证数据列是实时有序的。这样当操作量大时,排序所消耗的时间对整个系统有很大的影响。
二是应用二叉排序树来组织数据,由于二叉排序树是应用折半查寻法思想进行对数据进行存储的,所以,其左孩子大于双亲结点、右孩子小于双亲结点(或者左孩子小于双亲结点、右孩子大于双亲结点),这样就可以应用折半查寻法的思想进行查寻,从而减少对排序时所消耗的时间。
本设计采用第二种方法,即应用二叉排序树进行组织数据,在此基础上进行对个人通信录的各种操作。由于删除操作是本设计的重点,删除操作的成功与否直接影响到整个系统的成败,所以在此进行详细分析一下删除操作的实现。
此功能函数主要应用于删除将要进行删除的记录,此操作较其它几个操作难一点,同时也是此次设计的重点,所以,本函数的成败可以直接影响到本次设计的成败,同时,在进行二叉排序树进行组织时,如果不从系统的整体进行考虑,只想到简单地实现删除功能,将会出现错误。
在设计初期,由于没有考虑所有可能的情况,所以在进行删除最后一个结点时,总会出现内存不能引用的错误。最后想到应用浪费一个结点空间的技术进行处理此问题,就是根结点用来保存二叉排序树的某些信息,而不保存记录,与我们单链表中的头结点一样,这样做解决了上面所说的问题,同时在进行查寻双亲结点时也带来了很大的方便。
有关二叉排序树的删除的有关问题,请读者参考相关的参考文献,在此不再进行说明,本节重点在于说明本课程设计中有关删除的问题。
在本设计中,删除的首要条件是找到将要进行删除结点的双亲结点,由于根结点不用于存储记录,所以,可以不用进行判断根结点的情况,进行查寻双亲结点时,从根结点开始,首先进行判断根结点的左右子树是否为空,如果根结点的左右子树为空,则返回NULL,如果根结点的左子树(右子树)不为空,则将其左子树(右子树)的记录的学号与将要进行删除的学号进行比较,如果相等,则返回根结点;否则进行比较,如果左子树(右子树)不为空,且左子树(右子树)的学号大于(小于)要进行删除的学号,则进行递归在左子树(右子树)中进行查寻,直到查寻到或者当前结点的左右子树为空时结束。如果当前结点的学号与要进行删除的学号不相等,且当前结点的左右子树为空,则返回空,结束查寻过程。
经过对双亲结点的查寻,如果没有此记录,则进行提示,否则进行删除操作[1] [5],在进行删除时,有以下几种可能,以下操作中假设每次把要进行删除结点进行删除后,同时也释放了此结点所占用的内存空间,防止内存在运行过程中丢失。
第一:要进行删除的结点为叶结点,直接把其从二叉排序树中进行删除。
第二:此结点只有左子树或者右子树,这种情况下只需将只需把此结点的左子树或者右子树替换为双亲结点的左子树。
第三:此结点有左子树同时有也右子树,此种操作比较复杂,其中有两种方法进行删除,本课程设计中应用的方法是从某子树中找出一个结点(假设为Temp),将其值代替要进行删除结点的值,再把Temp结点进行删除。
这是 本人在大二的时候做的一个课程设计,见到论坛上有很多对二 叉树,特别是二叉排序树的不了解,所以,把它分享出来,如果需要每个功能模块的说明,设计文档,请给我发邮件或者到我的下载页面去下载,由于本人不在乎资 源分,所以下载页面所需资源分只1分就可以下载整个设计,包括详细的设计报告,不过本人把它转为PDF文档。同时,发表显示与编辑显示不太一样,本人对这玩意儿很少用,还是请看原版吧,有需要原版请与我联系。
我的 邮箱:sw_2006.1230@163.com 443120079@qq.com
下面为详细代码,希读者能看懂,由于本人一直专注于嵌入式底层驱动程序开发,所以,对数据结构与算法只能做为加强自己C语言的一个途径,也许在算法上与数据结构的组织上不太合理,请原谅。
- /**********************************************************************************
- * 基于二叉排序树的个人通信录
- *
- *
- *
- *
- *
- * 文 件: 基于二叉排序树树的个人通信录.C
- * 作 者: soon
- * 部 门: 长沙理工大学
- * 编写日期: 2009.9.10
- * 模块版本:
- * 修改记录:
- * ================================================================================
- * 版 本| 日 期 | 修改人 |
- * ================================================================================
- * | | |
- * | | |
- * | | |
- * ================================================================================
- *
- *
- *
- **********************************************************************************/
- #include <stdio.h>
- #include <stdlib.h>
- #include <assert.h>
- #include <string.h>
- FILE *input; /*定认读取文件指针*/
- FILE *output; /*定义保存文件指针*/
- /********************定义个人记录结构**********************/
- typedef struct Node
- {
- char name[30]; /*用于保存姓名*/
- char code[30]; /*用于保存学号*/
- int age; /*用于保年龄*/
- }NODE;
- /************************定义二叉树结构体******************/
- typedef struct Tree
- {
- NODE *student; /*个人通信记录*/
- struct Tree *lchild;
- struct Tree *rchild;
- }TREE;
- static int TREESIZE=sizeof(TREE); /*进行求二叉树所占的内存空间*/
- static int NODESIZE=sizeof(NODE); /*进行求个人记录结构的内存空间*/
- TREE *Create_Tree(void ); /*声明创建空二叉树的函数*/
- void Insert_Information(TREE *root,NODE *node); /*声明进行插入函数*/
- void Look_Through_Information(TREE *root); /*声明浏览函数*/
- void Save_Information(TREE *root); /*声明保存函数*/
- int Find_Information(TREE *root,char *code); /*声明查寻函数*/
- int Rework_Information(TREE *root,char *code); /*声明修改函数*/
- void Menu(void ); /*声明界面函数*/
- TREE *Find_Father_Node(TREE *root,char *code); /*声明查寻双亲结点的函数*/
- void Delete_Information(TREE *root,char *code); /*声明删除函数*/
- void Free_EMS_memory(TREE *root); /*声明释放内存空间函数*/
- /**********************主函数******************************/
- void main(void )
- {
- TREE *root;
- NODE *node;
- TREE *temp;
- char b[30];
- int a;
- printf("*************************基于排序二叉树的个人通信录*****************************/n/n/n");
- root = Create_Tree();
- input = fopen("shuwen.txt","r"); /*打开文件*/
- assert(input != NULL);
- if(!feof(input)) /*文件不空,进行读取一条记录*/
- {
- node = (NODE *)malloc(NODESIZE);
- assert(node != NULL);
- fscanf(input,"%s %s %d",node->code,node->name,&node->age);/*进行读取*/
- temp=(TREE *)malloc(TREESIZE);
- assert(temp != NULL);
- temp->rchild = NULL;
- temp->lchild = NULL;
- temp->student = node;
- root->lchild = temp;
- }
- node = (NODE *)malloc(NODESIZE);
- assert(node != NULL);
- while((fscanf(input,"%s %s %d",node->code,node->name,&node->age))!=EOF)/*读取文件中所有的记录,只到文件为空*/
- {
- Insert_Information(root->lchild,node); /*将读取的文件进行插入*/
- node=(NODE *)malloc(NODESIZE);
- assert(node!=NULL);
- }
- fclose(input); /*关闭读取文件指针*/
- while(1)
- {
- Menu();
- /*输入选择*/
- printf("/n");
- printf("请进行选择:");
- scanf("%d",&a);
- printf("/n/n");
- switch(a) /*进行选择*/
- {
- case 1: /*插入*/
- {
- printf("请输入要进行添加信息的学号,姓名,年龄/n");
- node=(NODE *)malloc(NODESIZE);
- assert(node!=NULL);
- scanf("%s %s %d",node->code,node->name,&node->age);
- if(root->lchild==NULL) /*如果记录为空时*/
- {
- temp=(TREE *)malloc(TREESIZE);
- assert(temp!=NULL);
- temp->rchild=NULL;
- temp->lchild=NULL;
- temp->student =node;
- root->lchild =temp;
- }
- else /*记录不为空*/
- {
- Insert_Information(root->lchild,node); /*进行插入*/
- }
- printf("/n/n添加成功/n");
- }break;
- case 2: /*浏览*/
- {
- if(root->lchild ==NULL) /*为空不能进行浏*/
- printf("记录为空,不能进行浏览!/n");
- else /*进行浏览*/
- {
- Look_Through_Information(root->lchild);
- }
- }break;
- case 3: /*保存*/
- {
- if(root->lchild ==NULL) /*记录为空不能进行保存*/
- printf("记录为空,不能进行保存!/n");
- else
- {
- output=fopen("shuwen.txt","w");/*打开文件*/
- Save_Information(root->lchild); /*进行保存*/
- printf("保存成功!");
- fclose(output); /*关闭文件*/
- }
- }break;
- case 4: /*查寻*/
- {
- if(root->lchild==NULL) /*为空不能进行查寻*/
- printf("记录为空,不能进行查寻!/n");
- else
- {
- printf("请输入你要进行查找的学号:");
- scanf("%s",b);
- printf("/n/n");
- if((Find_Information(root->lchild ,b))==0)/*没有找到进行提示*/
- printf("没有找到你要进行查找的记录!/n");
- }
- }break;
- case 5: /*修改*/
- {
- if(root->lchild==NULL) /*为空不能进行修改*/
- printf("记录为空,不能进行修改!/n");
- else /*进行查寻*/
- {
- printf("请输入你要进行修改的学号:");
- scanf("%s",b);
- printf("/n/n");
- if((Rework_Information(root->lchild ,b))==0)/*没有查寻到提示*/
- printf("没有找到你要进行修改的记录!/n");
- }
- }break;
- case 6: /*删除*/
- {
- if(root->lchild ==NULL) /*为空不能进行删除*/
- printf("记录为空,不能进行删除");
- else
- {
- printf("请输入你要进行删除的学号:");
- scanf("%s",b);
- Delete_Information(root,b); /*进行删除*/
- }
- }break;
- case 7: exit(0);break;
- }
- printf("/n/n");
- }
- Free_EMS_memory(root);
- }
- /**********************************************************************************
- * 菜单函数
- *描述:该函数用于对屏幕进行初始化。
- *
- *参数: 无
- *
- *返回值:无
- *
- *注意事项:
- **********************************************************************************/
- void Menu(void )
- {
- printf("************* 1 添加 *************/n");
- printf("************* 2 浏览 *************/n");
- printf("************* 3 保存 *************/n");
- printf("************* 4 查寻 *************/n");
- printf("************* 5 修改 *************/n");
- printf("************* 6 删除 *************/n");
- printf("************* 7 结束 *************/n");
- }
- /**********************************************************************************
- * 创建空二叉树函数
- *描述:该函数用于创建空二叉树。
- *
- *参数: 无
- *
- *返回值:根结点
- *
- *注意事项:该结点不进行保存数据。
- **********************************************************************************/
- TREE *Create_Tree(void )
- {
- /*根结点不进行保存记录,只用于做为真正的根结点*/
- TREE *root;
- root=(TREE *)malloc(TREESIZE);
- assert(root !=NULL);
- root->student=NULL;
- root->rchild=NULL;
- root->lchild=NULL;
- return root;
- }
- /**********************************************************************************
- * 插入个人信息函数
- *描述:该函数用于插入个人信息。
- *
- *参数: 根结点、记录有个人信息的结点
- *
- *返回值:无
- *
- *注意事项:
- **********************************************************************************/
- void Insert_Information(TREE *root,NODE *node)
- {
- TREE *Node;
- if((strcmp(root->student->code,node->code))>0)/*插入到左子树*/
- {
- if(root->lchild==NULL) /*左孩子为空,直接插入*/
- {
- Node=(TREE *)malloc(TREESIZE);
- assert(Node !=NULL);
- Node->rchild=NULL;
- Node->lchild=NULL;
- Node->student=node;
- root->lchild=Node;
- }
- else /*进行递归插入*/
- Insert_Information(root->lchild,node);
- }
- else /*插入到右子树*/
- {
- if(root->rchild==NULL) /*为空直接插入*/
- {
- Node=(TREE *)malloc(TREESIZE);
- assert(Node!=NULL);
- Node->rchild=NULL;
- Node->lchild=NULL;
- Node->student=node;
- root->rchild=Node;
- }
- else /*递归插入*/
- Insert_Information(root->rchild,node);
- }
- }
- /**********************************************************************************
- * 浏览函数
- *描述:该函数用于进行浏览所有的个人记录。
- *
- *参数: 根结点
- *
- *返回值:无
- *
- *注意事项:
- **********************************************************************************/
- void Look_Through_Information(TREE *root) /*中序遍历法输出*/
- {
- if(root!=NULL)
- {
- Look_Through_Information(root->lchild);
- printf("%s %s %d/n",root->student->code,root->student->name,root->student->age);
- Look_Through_Information(root->rchild);
- }
- }
- /**********************************************************************************
- * 保存函数
- *描述:该函数用于将所要进行保存的记录进行保存。
- *
- *参数: 根结点
- *
- *返回值:无
- *
- *注意事项:本处应用前序遍历法进行遍历二叉树,防止再次进行初始化时产生斜树
- **********************************************************************************/
- void Save_Information(TREE *root)
- {
- if(root!=NULL)
- {
- fprintf(output,"%s %s %d/n",root->student->code,root->student->name,root->student->age);
- Save_Information(root->lchild);
- Save_Information(root->rchild);
- }
- }
- /**********************************************************************************
- * 查寻函数
- *描述:该函数用于进行查寻记录。
- *
- *参数: 根结点、学号
- *
- *返回值:是否找到进行查寻的记录
- * 1:表找到 0:表没有找到
- *
- *注意事项:
- **********************************************************************************/
- int Find_Information(TREE *root,char *code)
- {
- if(root==NULL)
- return 0;
- else if((strcmp(root->student ->code ,code))==0)/*找到*/
- {
- printf("找到你要进行查录的记录,记录如下/n");
- printf("%s %s %d/n",root->student ->name ,root->student ->code ,root->student ->age );
- return 1;
- }
- else if((strcmp(root->student ->code ,code))>0)/*在左子树中进行查找*/
- Find_Information(root->lchild ,code);
- else /*在右子树中进行查寻*/
- Find_Information(root->rchild,code);
- }
- /**********************************************************************************
- * 修改函数
- *描述:该函数用于修改要进行修改的记录。
- *
- *参数: 根结点、学号
- *
- *返回值:是否修改成功
- * 1:修改成功 0:没有该记录
- *
- *注意事项:
- **********************************************************************************/
- int Rework_Information(TREE *root,char *code)
- {
- if(root==NULL) /*没有找到要进行修改的结点*/
- return 0;
- else if((strcmp(root->student ->code ,code))==0)/*找到*/
- {
- char name[30];
- int age;
- printf("请输入你要进行修改的姓名,年龄:");
- scanf("%s %d",name,&age);
- /*进行修改*/
- root->student ->age =age;
- strcpy(root->student ->name ,name);
- printf("修改成功/n");
- return 1;
- }
- else if((strcmp(root->student ->code ,code))>0)/*在左子树中进行查寻*/
- Rework_Information(root->lchild ,code);
- else /*在右子树中进行查寻*/
- Rework_Information(root->rchild ,code);
- }
- /**********************************************************************************
- * 查寻要进删除结点的双亲结点
- *描述:该函数用于查寻将要进行删除结点的双亲结点。
- *
- *参数: 根结点、学号
- *
- *返回值:双亲结点
- *
- *注意事项:
- **********************************************************************************/
- TREE *Find_Father_Node(TREE *root,char *code)
- {
- if(root->rchild==NULL && root->lchild==NULL) /*没有找到*/
- return NULL;
- else if((root->lchild!=NULL)&&((strcmp(root->lchild->student ->code,code))==0))/*找到为左结点*/
- return root;
- else if((root->rchild!=NULL) &&((strcmp(root->rchild->student ->code,code))==0))/*找到为右结点*/
- return root;
- else
- {
- if((root->lchild!=NULL) &&((strcmp(root->student ->code,code))>0))/*在左子树中进行查寻*/
- return (Find_Father_Node(root->lchild,code));
- else if((root->rchild!=NULL) &&((strcmp(root ->rchild->student ->code,code))<0))/*在右子树中进行查寻*/
- return (Find_Father_Node(root->rchild,code));
- else
- return NULL;
- }
- }
- /**********************************************************************************
- * 删除个人记录
- *描述:该函数用于删除个人记录。
- *
- *参数: 根结点、学号
- *
- *返回值:无
- *
- *注意事项:
- **********************************************************************************/
- void Delete_Information(TREE *root,char *code)
- {
- TREE *node;
- TREE *per;
- TREE *p;
- TREE *s;
- if((strcmp(root->lchild ->student ->code ,code))==0) /*是根结点情况*/
- {
- if(root->lchild ->lchild ==NULL && root->lchild ->rchild ==NULL)
- {
- node=root->lchild ;
- root->lchild =NULL;
- free(node);
- }
- else if(root->lchild ->lchild ==NULL && root->lchild ->rchild !=NULL)
- {
- node=root->rchild ;
- root->lchild=root->lchild ->rchild ;
- free(node);
- }
- else if(root->lchild ->rchild ==NULL && root->lchild ->lchild !=NULL)
- {
- node=root->lchild ;
- root->lchild=root->lchild ->lchild ;
- free(node);
- }
- else
- {
- node=root->lchild ;
- s=node ->rchild ;
- if(s->lchild ==NULL)
- node->rchild =s->rchild ;
- else
- {
- per=node;
- while(s->lchild !=NULL)
- {
- per=s;
- s=s->lchild ;
- }
- per->lchild =s->rchild ;
- }
- node->student =s->student ;
- free(s);
- }
- printf("删除成功!");
- }
- else
- {
- node=Find_Father_Node(root->lchild ,code); /*得到要进行删除结点的父结点*/
- if(node==NULL) /*没有找到*/
- printf("没有找到你要进行删除的数据!/n");
- else
- {
- if(node->lchild!=NULL && (strcmp(node->lchild->student ->code,code))==0)/*在父结点的左子树*/
- {
- p=node->lchild;
- if(p->lchild ==NULL && p->rchild ==NULL)/*叶子情况*/
- {
- node->lchild=NULL;
- free(p);
- }
- else if(p->lchild !=NULL && p->rchild ==NULL)/*只有左孩子*/
- {
- node->lchild =p->lchild ;
- free(p);
- }
- else if(p->rchild !=NULL && p->lchild ==NULL)/*只有右孩子*/
- {
- node->lchild =p->rchild ;
- free(p);
- }
- else /*有左右孩子*/
- {
- per=p;
- s=p->rchild ;
- while(s->lchild !=NULL)
- {
- per=s;
- s=s->lchild ;
- }
- p->student =s->student ;
- if(per==s)
- per->rchild =s->rchild ;
- else
- per->lchild =s->rchild ;
- free(s);
- }
- }
- else /*在右子树*/
- {
- p=node->rchild;
- if(p->lchild ==NULL && p->rchild ==NULL)
- {
- node->rchild=NULL;
- free(p);
- }
- else if(p->lchild !=NULL && p->rchild ==NULL)
- {
- node->rchild =p->lchild ;
- free(p);
- }
- else if(p->rchild !=NULL && p->lchild ==NULL)
- {
- node->rchild =p->rchild ;
- free(p);
- }
- else
- {
- per=p;
- s=p->rchild ;
- while(s->lchild !=NULL)
- {
- per=s;
- s=s->lchild ;
- }
- p->student =s->student ;
- if(per==s)
- per->rchild =s->rchild ;
- else
- per->lchild =s->rchild ;
- free(s);
- }
- }
- printf("删除成功!");
- }
- }
- }
- /**********************************************************************************
- * 释放内存函数
- *描述:该函数用于释放内存。
- *
- *参数: 根结点
- *
- *返回值:无
- *
- *注意事项:
- **********************************************************************************/
- void Free_EMS_memory(TREE *root)
- {
- if(root!=NULL)
- {
- Free_EMS_memory(root->lchild);
- Free_EMS_memory(root->rchild);
- free(root);
- }
- }