C语言实现之牛的数量(细胞分裂问题)(利用树实现)

本文介绍了如何使用C语言解决一个细胞分裂问题,即一头牛3岁开始每年生一头小牛,9岁后去世。通过建立树结构模拟牛的生育过程,展示了一种用树实现的算法,尽管效率较低但直观地反映了问题的本质。文章给出了前39年的结果,并邀请读者分享意见。

起因:

    老师上课的时候说了一个题:

        牛长到3岁可以生小牛,长到9岁后去世,每年可以生一头小牛,最初牛圈中只有一头牛,经过X年后,牛圈里有几头牛?

    当我听完之后第一反应,9年以内是一头牛,九年之后就没牛了,有的话也只剩尸体了大笑。牛是哺乳动物,有性生殖,一头牛怎么生啊?我更喜欢称这个问题叫细胞分裂问题,比如说蛙的红细胞就是通过无丝分裂增殖的。不多扯了,还是用牛吧,我们先分析一下问题。

分析:

    牛一年生一头,从三岁开始能生小牛,他总共能活九年,最后一年它怎么这把最后一头牛生下来再死吧(YY:可能是难产死的)。这样这题就是说一头牛活九年,从三岁开始到死,总共能生7头牛。

    我们可以用什么方法解决这个问题来?

    (1)找出一个数量关系的公式,直接计算。

    (2)模拟这个生长的数量关系,(a)循环+数组,(b)循环+递归+树,(c)递归。

    小弟不才,没找出数量关系的公式。所以只能模拟,那这个牛数量的存储用什么实现?老师说用数组,但是我向大家第一个想到的应该是用树来实现吧,类似家谱。我决定用树来实现(当然题目就是这个尴尬)。

    利用树实现的缺点:当然这个确实是最符合思维的一种方法,但是缺点显而易见,效率比较低,相比数组,吃内存也比较多。

思路:

    我是这样想的,将牛看做树上的节点,便利一次就是一年,年龄0-2岁不作处理,只给他增长年龄,3-9岁没便利一次,在此节点之下创建新的结点,年龄是1的话就让全局计数的变量增长1,表示有新牛出生,年龄到达10的话就已经死了,所以就让全局计数的变量减少1,表示有一头牛死了。所以有几年,就这样遍历几次这个树,最后的计数变量就是现在牛圈中还活着的牛的数量。

    那么这个节点的结构体需要包含两部分,一个是这个节点的年龄,另一个是,指向它的子节点的7个指针。

▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
▕ago▕ node_0▕node_1▕ node_2▕ node_3▕node_4▕ node_5▕ node_6▕
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔

实现:

#include <stdio.h>
#include <stdlib.h>

#define DIETIME 9                                   //死亡时间
#define INCREASETIME 3                              //开始繁殖时间
#define COUNTINCREASE DIETIME - INCREASETIME + 1    //总繁殖时间

//节点
typedef struct OXnode{
    int age;                                        //年龄
    struct OXnode * nextOX[COUNTINCREASE];          //子(小牛)节点
}OX;

int countOX = 0;                                    //记录牛的总数


/**********************************
* 函  数:OX * createNode()        *
* 参  数:无                       *
* 功  能:创建一个牛的节点           *
* 返  回:创建好的节点的指针         *
**********************************/
OX * createNode()
{
    int loop = COUNTINCREASE;
    OX * node = (OX *)malloc(sizeof(OX));      //申请内存空间

    //判断内存申请是否不成功
    if(node == NULL)
    {
        puts("not have enough memory.");
        exit(0);                                //退出程序
    }
    node->age = 0;                              //初始化年龄

    //循环初始化节点
    while(loop--)
    {
        node->nextOX[loop] = NULL;
    }
    return node;                               //返回创建的节点
}

/**********************************
* 函  数:void traversal(OX * ox)  *
* 参  数:无                       *
* 功  能:遍历结点                  *
* 返  回:无                       *
***********************************/
void traversal(OX * ox)
{
    //判断年龄是否还需要增加(防止不必要的增加)
    if(ox->age  <= DIETIME)
    {
        ox->age++;                       //年龄增加
    }

    //判断年龄状况
    switch(ox->age)
    {
        case 1:                         //1岁说明是新牛
            countOX++;                   //总数增加1
            break;
        case DIETIME:                   //9岁说明是将要死去的牛
            countOX--;                   //总数减少1
            break;
    }

    //判断牛是否到达繁衍的年龄
    if(ox->age >= INCREASETIME)
    {
        int loop = 0;
        int age = ox->age == DIETIME + 1 ? DIETIME : ox->age ;  //计算当前年龄

        //循环他的子节点(即亲生的小牛节点)
        for(; loop < (age - INCREASETIME + 1); loop++)
        {
            //判断节点是否为NULL(即此小牛刚出生)
            if(ox->nextOX[loop] == NULL)
            {
                ox->nextOX[loop] = createNode();                //创建新生的小牛节点
            }

            traversal(ox->nextOX[loop]);                        //遍历此小牛节点
        }
    }
}


/*********************************
* 函  数:int main()              *
* 参  数:无                      *
* 功  能:主函数                   *
* 返  回:0                       *
**********************************/
int main()
{
    int year;
    puts("years:");
    scanf("%d",&year);

    OX * firstOX = createNode();        //创建首节点

    //年数循环遍历全部节点
    while(year--)
    {
        traversal(firstOX);             //遍历
    }

    printf("count : %d\n",  countOX);

    return 0;
}

结果:

这是前39年的结果:
    current year: 1, count: 1
    current year: 2, count: 1
    current year: 3, count: 2
    current year: 4, count: 3
    current year: 5, count: 5
    current year: 6, count: 8
    current year: 7, count: 13
    current year: 8, count: 21
    current year: 9, count: 33
    current year: 10, count: 53
    current year: 11, count: 85
    current year: 12, count: 136
    current year: 13, count: 218
    current year: 14, count: 349
    current year: 15, count: 559
    current year: 16, count: 895
    current year: 17, count: 1433
    current year: 18, count: 2295
    current year: 19, count: 3675
    current year: 20, count: 5885
    current year: 21, count: 9424
    current year: 22, count: 15091
    current year: 23, count: 24166
    current year: 24, count: 38698
    current year: 25, count: 61969
    current year: 26, count: 99234
    current year: 27, count: 158908
    current year: 28, count: 254467
    current year: 29, count: 407490
    current year: 30, count: 652533
    current year: 31, count: 1044932
    current year: 32, count: 1673299
    current year: 33, count: 2679533
    current year: 34, count: 4290863
    current year: 35, count: 6871162
    current year: 36, count: 11003117
    current year: 37, count: 17619812
    current year: 38, count: 28215439
    current year: 39, count: 45182718
    ...

总结:

主要还是思路,没有难的地方,发出来和大家分享下,希望大家多多多提意见,就写这些吧。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值