本設計應用折半查尋法的技術思想進行查尋,從本思想出發,可以有兩種數據組織方式:一是應用鏈表進行組織數據,由於折半查尋法的特殊性,所要進行查尋的數據列必須是有序的數據列,這樣要求對數據列進行排序。出於系統實時查尋的考慮,每次對通信錄進行改變後都得進行重新排序,這樣才能保證數據列是實時有序的。這樣當操作量大時,排序所消耗的時間對整個系統有很大的影響。
二是應用二叉排序樹來組織數據,由於二叉排序樹是應用折半查尋法思想進行對數據進行存儲的,所以,其左孩子大於雙親結點、右孩子小於雙親結點(或者左孩子小於雙親結點、右孩子大於雙親結點),這樣就可以應用折半查尋法的思想進行查尋,從而減少對排序時所消耗的時間。
本設計採用第二種方法,即應用二叉排序樹進行組織數據,在此基礎上進行對個人通信錄的各種操作。由於刪除操作是本設計的重點,刪除操作的成功與否直接影響到整個系統的成敗,所以在此進行詳細分析一下刪除操作的實現。
此功能函數主要應用於刪除將要進行刪除的記錄,此操作較其它幾個操作難一點,同時也是此次設計的重點,所以,本函數的成敗可以直接影響到本次設計的成敗,同時,在進行二叉排序樹進行組織時,如果不從系統的整體進行考慮,只想到簡單地實現刪除功能,將會出現錯誤。
在設計初期,由於沒有考慮所有可能的情況,所以在進行刪除最後一個結點時,總會出現內存不能引用的錯誤。最後想到應用浪費一個結點空間的技術進行處理此問題,就是根結點用來保存二叉排序樹的某些信息,而不保存記錄,與我們單鏈表中的頭結點一樣,這樣做解決了上面所說的問題,同時在進行查尋雙親結點時也帶來了很大的方便。
有關二叉排序樹的刪除的有關問題,請讀者參考相關的參考文獻,在此不再進行說明,本節重點在於說明本課程設計中有關刪除的問題。
在本設計中,刪除的首要條件是找到將要進行刪除結點的雙親結點,由於根結點不用於存儲記錄,所以,可以不用進行判斷根結點的情況,進行查尋雙親結點時,從根結點開始,首先進行判斷根結點的左右子樹是否爲空,如果根結點的左右子樹爲空,則返回NULL,如果根結點的左子樹(右子樹)不爲空,則將其左子樹(右子樹)的記錄的學號與將要進行刪除的學號進行比較,如果相等,則返回根結點;否則進行比較,如果左子樹(右子樹)不爲空,且左子樹(右子樹)的學號大於(小於)要進行刪除的學號,則進行遞歸在左子樹(右子樹)中進行查尋,直到查尋到或者當前結點的左右子樹爲空時結束。如果當前結點的學號與要進行刪除的學號不相等,且當前結點的左右子樹爲空,則返回空,結束查尋過程。
經過對雙親結點的查尋,如果沒有此記錄,則進行提示,否則進行刪除操作[1] [5],在進行刪除時,有以下幾種可能,以下操作中假設每次把要進行刪除結點進行刪除後,同時也釋放了此結點所佔用的內存空間,防止內存在運行過程中丟失。
第一:要進行刪除的結點爲葉結點,直接把其從二叉排序樹中進行刪除。
第二:此結點只有左子樹或者右子樹,這種情況下只需將只需把此結點的左子樹或者右子樹替換爲雙親結點的左子樹。
第三:此結點有左子樹同時有也右子樹,此種操作比較複雜,其中有兩種方法進行刪除,本課程設計中應用的方法是從某子樹中找出一個結點(假設爲Temp),將其值代替要進行刪除結點的值,再把Temp結點進行刪除。
這是 本人在大二的時候做的一個課程設計,見到論壇上有很多對二 叉樹,特別是二叉排序樹的不瞭解,所以,把它分享出來,如果需要每個功能模塊的說明,設計文檔,請給我發郵件或者到我的下載頁面去下載,由於本人不在乎資 源分,所以下載頁面所需資源分只1分就可以下載整個設計,包括詳細的設計報告,不過本人把它轉爲PDF文檔。同時,發表顯示與編輯顯示不太一樣,本人對這玩意兒很少用,還是請看原版吧,有需要原版請與我聯繫。
我的 郵箱:[email protected] [email protected]
下面爲詳細代碼,希讀者能看懂,由於本人一直專注於嵌入式底層驅動程序開發,所以,對數據結構與算法只能做爲加強自己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);
- }
- }