1. 程式人生 > >二叉排序樹與檔案的操作(C、C++)

二叉排序樹與檔案的操作(C、C++)

/*
功能要求:
(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;
        }
    }
}