数据结构学习

该代码段使用C语言构建了一个家谱的二叉树结构,包括创建、显示、查找节点以及输出祖先等功能。程序首先定义了家谱记录的数据结构,然后通过递归方式创建家谱二叉树,并提供了输出括号表示法的二叉树、查找指定人员的儿子和祖先等操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

家谱


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MaxSize 30            //栈的最大元素个数
#define NAMEWIDTH 10        //姓名的最多字符个数
typedef struct fnode
{
    char father[NAMEWIDTH];    //父
    char wife[NAMEWIDTH];    //母
    char son[NAMEWIDTH];    //子
} FamType;                    //家谱文件的记录类型
typedef struct tnode
{
    char name[NAMEWIDTH];
    struct tnode *lchild,*rchild;
} BTree;                    //家谱二叉树结点树类型
int n;                        //家谱记录个数
FamType fam[MaxSize];        //家谱记录数组
//----家谱二叉树操作算法-----------------------------------
BTree *CreateBTree(char *root)    //从fam(含n个记录)递归创建一棵二叉树
{
    int i=0,j;
    BTree *b,*p;
    b=(BTree *)malloc(sizeof(BTree));            //创建父亲结点
    strcpy(b->name,root);
    b->lchild=b->rchild=NULL;
    while (i<n && strcmp(fam[i].father,root)!=0) 
        i++;
    if (i<n)                                    //找到了该姓名的记录
    {
        p=(BTree *)malloc(sizeof(BTree));        //创建母亲结点
        p->lchild=p->rchild=NULL;
        strcpy(p->name,fam[i].wife);
        b->lchild=p;
        for (j=0;j<n;j++)                        //找所有儿子
            if (strcmp(fam[j].father,root)==0)    //找到一个儿子
            {
                p->rchild=CreateBTree(fam[j].son);
                p=p->rchild;
            }
    }
    return(b);
}
void DispTree(BTree *b)    //以括号表示法输出二叉树
{
    if (b!=NULL)
    {
        printf("%s",b->name);
        if (b->lchild!=NULL || b->rchild!=NULL)
        {
            printf("(");
            DispTree(b->lchild);
            if (b->rchild!=NULL) 
                printf(",");
            DispTree(b->rchild);
            printf(")");
        }
    }
}
BTree *FindNode(BTree *b,char xm[]) //采用先序递归算法找name为xm的结点
{
    BTree *p;
    if (b==NULL) 
        return(NULL);
    else
    {
        if (strcmp(b->name,xm)==0)
            return(b);
        else
        {
            p=FindNode(b->lchild,xm);
            if (p!=NULL) 
                return(p);
            else 
                return(FindNode(b->rchild,xm));
        }
    }
}
void FindSon(BTree *b)        //输出某人的所有儿子
{
    char xm[NAMEWIDTH];
    BTree *p;
    printf("  >>父亲姓名:");
    scanf("%s",xm);
    p=FindNode(b,xm);
    if (p==NULL)
        printf("  >>不存在%s的父亲!\n",xm);
    else
    {
        p=p->lchild;
        if (p==NULL)
            printf("  >>%s没有妻子\n",xm);
        else
        {
            p=p->rchild;
            if (p==NULL)
                printf("  >>%s没有儿子!\n",xm);
            else
            {
                printf("  >>%s的儿子:",xm);
                while (p!=NULL)
                {
                    printf("%10s",p->name);
                    p=p->rchild;
                }
                printf("\n");
            }
        } 
    }
}
int Path(BTree *b,BTree *s)        //采用后序非递归遍历方法输出从根结点到s结点的路径
{
    BTree *St[MaxSize];
    BTree *p;
    int i,top=-1;                    //栈指针置初值
    bool flag;
    do
    {
        while (b)                     //将b的所有左下结点进栈
        {    
            top++;
            St[top]=b;
            b=b->lchild;
        }
        p=NULL;                       //p指向当前结点的前一个已访问的结点
        flag=true;                    //flag为真表示正在处理栈顶结点
        while (top!=-1 && flag)
        {    
            b=St[top];              //取出当前的栈顶元素
            if (b->rchild==p)        //右子树不存在或已被访问,访问之
            {    if (b==s)            //当前访问的结点为要找的结点,输出路径
                {    
                    printf("  >>所有祖先:");
                    for (i=0;i<top;i++) 
                           printf("%s ",St[i]->name);
                    printf("\n");
                       return 1;
                }
                else
                {    
                    top--;
                       p=b;            //p指向则被访问的结点
                }
            }
            else
            {    
                b=b->rchild;        //b指向右子树
                flag=false;         //表示当前不是处理栈顶结点
            }
        }
    } while (top!=-1);                //栈不空时循环
    return 0;                        //其他情况时返回0
}
void Ancestor(BTree *b)                //输出某人的所有祖先
{
    BTree *p;
    char xm[NAMEWIDTH];
    printf("  >>输入姓名:");
    scanf("%s",xm);
    p=FindNode(b,xm);
    if (p!=NULL)
        Path(b,p);
    else
        printf("  >>不存在%s\n",xm);
}
void DestroyBTree(BTree *b)        //销毁家谱二叉树
{
    if (b!=NULL)
    {
        DestroyBTree(b->lchild);
        DestroyBTree(b->rchild);
        free(b);
    }
}
        
//----家谱文件操作算法---------------------------------------------
void DelAll()                    //清除家谱文件全部记录
{
    FILE *fp;
    if ((fp=fopen("fam.dat","wb"))==NULL) 
    {    
        printf("  >>不能打开家谱文件\n");
        return;
    }
    n=0;
    fclose(fp);
}
void ReadFile()                //读家谱文件存入fam数组中
{
    FILE *fp;
    long len;
    int i;
    if ((fp=fopen("fam.dat","rb"))==NULL) 
    {
        n=0;
        return;
    }
    fseek(fp,0,2);                //家谱文件位置指针移到家谱文件尾
    len=ftell(fp);                //len求出家谱文件长度
    rewind(fp);                    //家谱文件位置指针移到家谱文件首
    n=len/sizeof(FamType);         //n求出家谱文件中的记录个数
    for (i=0;i<n;i++)
        fread(&fam[i],sizeof(FamType),1,fp);//将家谱文件中的数据读到fam中
    fclose(fp);
}
void SaveFile()                    //将fam数组存入数据家谱文件
{
    int i;
    FILE *fp;
    if ((fp=fopen("fam.dat","wb"))==NULL) 
    {    
        printf("  >>数据家谱文件不能打开\n");
        return;
    }
    for (i=0;i<n;i++)
        fwrite(&fam[i],sizeof(FamType),1,fp);
    fclose(fp);
}
void InputFam()                    //添加一个记录
{
    printf("  >>输入父亲、母亲和儿子姓名:");
    scanf("%s%s%s",fam[n].father,fam[n].wife,fam[n].son);
    n++;
}
void OutputFile()                //输出家谱文件全部记录
{
    int i;
    if (n<=0)
    {
        printf("  >>没有任何记录\n");
        return;
    }
    printf("         父亲     母亲      儿子\n");
    printf("       ------------------------------\n");
    for (i=0;i<n;i++)
        printf("  %10s%10s%10s\n",fam[i].father,fam[i].wife,fam[i].son);
    printf("       ------------------------------\n");
}
//---------------------------------------------------------------------
void Fileop()        //家谱文件操作
{
    int sel;
    do 
    {
        printf(" >1:输入 2:输出 9:全清 0:存盘返回 请选择:");
        scanf("%d",&sel);
        switch(sel)
        {
        case 9:
            DelAll();
            break;
        case 1:
            InputFam();
            break;
        case 2:
            OutputFile();
            break;
        case 0:
            SaveFile();
            break;
        } 
    } while (sel!=0);
}
void BTreeop()        //家谱二叉树操作
{
    BTree *b;
    int sel;
    if (n==0) return;                //家谱记录为0时直接返回
    b=CreateBTree(fam[0].father);
    do 
    {
        printf(" >1:括号表示法 2.找某人所有儿子 3.找某人所有祖先 0:返回 请选择:");
        scanf("%d",&sel);
        switch(sel)
        {
        case 1:
            printf("  >>");DispTree(b);printf("\n");
            break;
        case 2:
            FindSon(b);
            break;
        case 3:
            printf("  >>");Ancestor(b);
            break;
        } 
    } while (sel!=0);
    DestroyBTree(b);        //销毁家谱二叉树
}
int main()
{
    BTree *b;
    int sel;
    ReadFile();
    do
    {    
        printf("*1.文件操作 2:家谱操作 0:退出 请选择:");
        scanf("%d",&sel);
        switch(sel)
        {
        case 1:
            Fileop();
            break;
        case 2:
            BTreeop();
            break;
        }
    } while (sel!=0);
    return 1;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值