二叉排序樹與檔案的操作(C、C++)
阿新 • • 發佈:2019-01-06
/* 功能要求: (1)從鍵盤輸入一組學生記錄建立二叉排序樹; (2)二叉排序樹存檔; (3)由檔案恢復記憶體的二叉排序樹; (4)中序遍歷二叉排序樹; (5)求二叉排序樹深度; (6)求二叉排序樹的所有節點數和葉子節點數; (7)向二叉排序樹插入一條學生記錄; (8)從二叉排序樹中刪除一條學生記錄; (9)從二叉排序樹中查詢一條學生記錄; (10)以廣義表的形式輸出二叉排序樹 等功能。 注:第十個廣義表我沒做,不會T_T */ #include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <iomanip> #include <fstream> #include <math.h> using namespace std; int sum; //定義學生記錄型別 struct student { char num[20];//學號 int grade;//成績 }; //定義二叉排序樹節點值的型別為學生記錄型別 typedef struct student ElemType; //定義二叉排序樹的節點型別 typedef struct bnode { ElemType data; struct bnode *lchild; struct bnode *rchild; }BNode,*BiTree; /*在根指標T所指的二叉排序樹中遞迴地查詢某關鍵字為key的資料元素, 如果查詢成功,則指標p只想該資料元素結點並返回1,否則p指向查詢路 徑上訪問的最後一個結點並返回0,指標f指向T的雙親,初值為NULL。*/ int searchBST(BiTree T,ElemType key,BiTree f,BiTree &p) { if(!T) //如果根指標為空,即查詢失敗,p置空,返回0 { p=f; return 0; } else if(strcmp(key.num,T->data.num)==0&&key.grade==T->data.grade) //如果根指標所指結點的值就是要查詢的值,p就等於T,返回1 { p=T; return 1; } else if(key.grade<T->data.grade) //如果要查的值比根節點小,就到T的左子樹去找 return searchBST(T->lchild,key,T,p); else return searchBST(T->rchild,key,T,p); //如果要查的值比根節點大,就到T的左子樹去找 } /*當二叉排序樹T中不存在關鍵字e時,插入e並返回1,否則返回0*/ int InsertBST(BiTree &T,ElemType e) { BiTree p,s; //p為查詢關鍵字e路徑上最後一個結點的指標,或者是指向關鍵字e的指標 //s為插入新結點所需要開闢的空間首地址 if(!searchBST(T,e,NULL,p)) //如果查詢失敗,說明要進行插入操作 { s=(BiTree)malloc(sizeof(BNode)); s->data.grade=e.grade; strcpy(s->data.num,e.num); s->lchild=s->rchild=NULL; //s肯定是沒有孩子的 if(!p) //如果p為空,說明T就是一顆空樹,直接讓s當根就好了 T=s; else if(e.grade<p->data.grade) //如果e比p->data小,說明要插到p的左子樹上 p->lchild=s; else if(e.grade>p->data.grade) //如果e比p->data大,說明要插到p的右子樹上 p->rchild=s; return 1; } else //說明查詢成功!那麼就沒有插入的必要了,直接返回0即可 return 0; } void inorder(BiTree bt) { if(bt) { inorder(bt->lchild); printf("學號:%s 成績:%d\n",bt->data.num,bt->data.grade); inorder(bt->rchild); } } int Depth(BiTree bt) { int depthval,depthleft,depthright; if(!bt) depthval=0; else { depthleft=Depth(bt->lchild); depthright=Depth(bt->rchild); depthval=1+(depthleft>depthright?depthleft:depthright); } return depthval; } void count_all_nodes(BiTree bt,int &count) { if(bt) { count++; count_all_nodes(bt->lchild,count); count_all_nodes(bt->rchild,count); } } void count_all_leaves(BiTree bt,int &count) { if(bt) { if(bt->lchild==NULL&&bt->rchild==NULL) count++; count_all_leaves(bt->lchild,count); count_all_leaves(bt->rchild,count); } } int Delete(BiTree &p) { BiTree q,s; if(!p->rchild) { q=p; p=p->lchild; free(q); } else if(!p->lchild) { q=p; p=p->rchild; free(q); } else { q=p; s=p->lchild; while(s->rchild) { q=s; s=s->rchild; } p->data=s->data; if(q!=p) q->rchild=s->lchild; else q->lchild=s->lchild; free(s); } return 1; } int DeleteBST(BiTree &T,ElemType key) { if(!T) return 0; else { if(key.grade==T->data.grade&&strcmp(key.num,T->data.num)==0) return Delete(T); else if(key.grade<T->data.grade) return DeleteBST(T->lchild,key); else return DeleteBST(T->rchild,key); } } void inorder_save(BiTree bt,char num[][20],int grade[10]) { static int x=0; if(bt) { strcpy(num[x],bt->data.num); grade[x]=bt->data.grade; x++; inorder_save(bt->lchild,num,grade); inorder_save(bt->rchild,num,grade); } } void menu() { printf("\n1.從鍵盤輸入一組學生記錄建立二叉排序樹並存盤\n"); printf("2.二叉排序樹存檔\n"); printf("3.由檔案恢復記憶體的二叉排序樹\n"); printf("4.中序遍歷二叉排序樹\n"); printf("5.求二叉排序樹深度\n"); printf("6.求二叉排序樹的所有節點數和葉子節點數\n"); printf("7.向二叉排序樹插入一條學生記錄\n"); printf("8.從二叉排序樹中刪除一條學生記錄\n"); printf("9.從二叉排序樹中查詢一條學生記錄\n"); printf("10.以廣義表的形式輸出二叉排序樹\n"); printf("11.退出系統\n"); } BiTree search_num(BiTree bt,char nu[]) //通過生日找到結點並返回 { BiTree l_result,r_result; if(!bt) return NULL; if(strcmp(bt->data.num,nu)==0) return bt; else { l_result=search_num(bt->lchild,nu); r_result=search_num(bt->rchild,nu); return l_result?l_result:(r_result?r_result:NULL); } } int main() { int n,i,k,m,grade[10],depthval,count1,count2; ElemType stu[20],st; char str[20],nu[20],num[20][20]; BiTree bt=NULL,p; printf("歡迎來到二叉排序樹管理系統!\n"); LL1:menu(); printf("\n請輸入你的選擇:\n"); scanf("%d",&m); switch(m) { case 1: { printf("請輸入學生的個數:\n"); scanf("%d",&n); sum=n; printf("請輸入%d個學生的學號和成績,中間用空格隔開:\n",n); ofstream fout("bst.txt"); memset(num,0,sizeof(num)); for(i=0;i<sum;i++) { scanf("%s%d",stu[i].num,&stu[i].grade); fout<<stu[i].num<<" "<<stu[i].grade<<endl; strcpy(num[i],stu[i].num); grade[i]=stu[i].grade; InsertBST(bt,stu[i]); } goto LL1; break; } case 2: { ofstream fout("bst.txt"); inorder_save(bt,num,grade); for(i=0;i<sum;i++) fout<<num[i]<<" "<<grade[i]<<endl; fout.close(); printf("從檔案讀取的結果為:\n"); ifstream fin("bst.txt"); for(i=0;i<sum;i++) { fin>>str>>k; cout<<str<<" "<<k<<endl; } fin.close(); goto LL1; break; } case 3: { bt=NULL; ifstream fin("bst.txt"); printf("請輸入學生的個數:\n"); scanf("%d",&sum); printf("檔案裡的內容為:\n"); for(i=0;i<sum;i++) { fin>>str>>k; strcpy(st.num,str); st.grade=k; printf("學號:%s 成績:%d\n",st.num,st.grade); InsertBST(bt,st); } printf("\n二叉排序樹的中序遍歷為:\n"); inorder(bt); goto LL1; break; } case 4: { printf("二叉排序樹的中序遍歷為:\n"); inorder(bt); goto LL1; break; } case 5: { depthval=Depth(bt); if(depthval) printf("二叉排序樹的深度為:%d\n",depthval); else printf("二叉排序樹為空!\n"); goto LL1; break; } case 6: { count1=count2=0; count_all_nodes(bt,count1); count_all_leaves(bt,count2); printf("二叉排序樹中所有結點個數為:%d\n",count1); printf("二叉排序樹中所有葉子結點個數為:%d\n",count2); goto LL1; break; } case 7: { printf("請輸入新增學生的個數:\n"); scanf("%d",&n); sum+=n; printf("請輸入%d個學生的學號和成績,中間用空格隔開:\n",n); for(i=0;i<n;i++) { scanf("%s%d",stu[i].num,&stu[i].grade); InsertBST(bt,stu[i]); } printf("二叉排序樹的中序遍歷為:\n"); inorder(bt); goto LL1; break; } case 8: { sum--; printf("請輸入你想刪除的那個人的學號和成績:\n"); scanf("%s%d",st.num,&st.grade); DeleteBST(bt,st); printf("二叉排序樹的中序遍歷為:\n"); inorder(bt); goto LL1; break; } case 9: { printf("請輸入你想查詢的學號\n"); scanf("%s",nu); p=search_num(bt,nu); if(!p) printf("error!\n"); printf("你查詢的這個人的資訊為:\n"); printf("學號:%s\n",p->data.num); printf("分數:%d\n",p->data.grade); goto LL1; break; } case 10: { goto LL1; break; } case 11: { printf("謝謝你的使用,寨見!\n"); exit(0); } default: { printf("你的輸入有誤,請重新輸入!\n"); goto LL1; break; } } }