起因:
老师上课的时候说了一个题:
牛长到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
...
总结:
主要还是思路,没有难的地方,发出来和大家分享下,希望大家多多多提意见,就写这些吧。
本文介绍了如何使用C语言解决一个细胞分裂问题,即一头牛3岁开始每年生一头小牛,9岁后去世。通过建立树结构模拟牛的生育过程,展示了一种用树实现的算法,尽管效率较低但直观地反映了问题的本质。文章给出了前39年的结果,并邀请读者分享意见。
1358

被折叠的 条评论
为什么被折叠?



