C语言实现penna模型
一年前写的代码,偶然翻出来。发现自己当时水平还不赖吗。
1 # include <stdio.h>
2 # include <stdlib.h>
3 # include <time.h>
4 # include <stdbool.h>
5 # include <windows.h>
6
7 # define N0 1000 //初始时刻种群数量为1000
8 # define Nmax 100000 //种群最大数量为100000
9 # define R 6 //最低繁殖年龄为8
10 # define B 32 //老死年龄即位串长度为32
11 # define b 1 //每次繁殖子代个数为1
12 # define T 4 //最大疾病次数为2
13 # define M 2 //突变强度为2
14 # define LEN sizeof(GENE) //宏替换一个结构体的大小
15 clock_t start, finish;
16 double duration;
17 int t;
18 typedef struct Gene
19 {
20 bool Gene[B]; //用布尔类型数组表示位串
21 int Age; //年龄
22 int SickNum; //患病次数
23 struct Gene *next; //存放一个连接链表的节点指针
24 }GENE;
25 int Nt = N0; //定义一个全局变量,表示t时刻种群的数量
26 double M_rate = (double)M/B; //M_rate表示基因遗传突变率
27 GENE *pHead = NULL, *pFore = NULL, *pNext = NULL, *p = NULL, *pTail = NULL;
28 //定义五个指针:pHead指向头节点pFore为节点的前驱指针,pNext建立新节点,p游标指针,pTail尾节点指针
29 GENE Gene_Str; //定义一个GENE类型的结构体Gene_Str
30
31 void Initialize(void) //构造链表及种群初始状态
32 {
33 pHead = (GENE *)malloc(LEN);//为头节点指针分配空间
34 p = pHead; //头节点指针赋值给游标指针
35 for (int i=1; i<N0; i++)
36 {
37 p->Age = 0; //初始时刻年龄为0(t=0)
38 p->SickNum = 0; //患病次数为0
39 for (int j=0; j<B; j++)
40 {
41 p->Gene[j] = (rand()%2); // 对第一代个体基因随机规定
42 }
43 pNext = (GENE *)malloc(LEN); //为新节点开辟存储空间
44 p->next = pNext; //将前驱节点指向下一结构体地址
45 p = pNext; //将新节点赋值给游标指针
46 }
47 pTail = p;
48 pNext = p = NULL;
49 pTail->next = NULL; //尾节点下一指向为空
50 }
51 void Aging(void) //执行年龄增长机制,每次调用,所有个体年龄加一
52 {
53 p = pHead; //游标指针指向头指针
54 while (p != NULL) //遍历每个个体
55 {
56 if (p->Gene[p->Age] == 1)
57 {
58 p->SickNum++;
59 } //如果该年龄位置为坏基因,则患病次数加一
60 p->Age++; //每个个体年龄加一
61 p = p->next; //游标指针指向下一个体
62 }
63 }
64 void Die(void) //执行死亡机制,每次调用,满足条件的个体死去,链表节点删除
65 {
66 pFore = p = pHead; //游标指针指向头指针,并创建一个和游标指针同步的前驱指针
67 while (p != NULL) //遍历每个个体
68 {
69 double RandOfLive = (double)rand()/(double)RAND_MAX; //构造一个随机概率
70 if (p->SickNum>=T || p->Age>=(B-1) || RandOfLive>=(1-(double)Nt/Nmax))
71 //满足三种情况之一即死亡:年龄到达老死年龄,达到最大患病次数,因环境压力随机死亡
72 {
73 Nt--; //每次死亡导致种群数量减一
74 if (p == pHead)//当p为头节点
75 {
76 pHead = p->next;
77 free(p); //节点删除后释放占用的空间
78 pFore = p = pHead;
79 p = p->next; //重新初始化
80 }
81 else if (p->next == NULL)//当p为尾节点
82 {
83 pFore->next = NULL; //将前一个节点设置为尾节点
84 free(p); //释放删除后的节点
85 p = NULL;
86 }
87 else //既不是头节点又不是尾节点
88 {
89 pFore->next = p->next; //跳过p节点,前后相连接
90 free(p); //释放删除了的节点
91 p = pFore;
92 pFore = p;
93 p = p->next; //重新初始化
94 }
95 }
96 else //如果个体不满足死亡条件
97 {
98 pFore = p;
99 p = p->next; //指针向下一节点移动并始终存储前一节点以备删除中间节点
100 }
101 } //结束后p == NULL,是尾节点的节点指针
102 pNext = NULL;
103 pFore = NULL; //遍历之后将这两个指针置为空,防止错误调用
104 }
105 void RePreduction(void) //执行繁殖机制
106 {
107 p = pHead; //p指向链表的头指针
108 while (p != NULL) //遍历每个个体
109 {
110 double RandOfChange = (double)rand()/(double)RAND_MAX; //构造一个随机数
111 if (p->Age >= R) //如果年龄达到最低繁殖年龄
112 {
113 pNext = p; //为了方便操作,将每一个新生个体对应的节点连在尾节点后
114 while (pNext->next != NULL)
115 pNext = pNext->next; //此时pNext为尾节点
116
117 for (int k=0; k<b; k++) //每次繁殖将产生b个新个体
118 {
119 while (pNext->next != NULL)
120 pNext = pNext->next;
121
122 pTail = (GENE *)malloc(LEN); //开辟一个存储空间
123 pNext->next = pTail; //尾节点的next指向该存储空间
124 pTail->next = NULL; //将这个新节点设为尾节点
125 for (int i=0; i<B; i++)
126 {
127 if (RandOfChange < M_rate) //达到要求则发生突变
128 pTail->Gene[i] = !p->Gene[i];
129 else //否则执行拷贝复制
130 pTail->Gene[i] = p->Gene[i];
131 }
132 pTail->Age = 0;
133 pTail->SickNum = 0; //新生个体的这两项也要初始化,开始一直忘了!!!!!!!!
134 Nt+=1; //个体数加一
135 }
136 p = p->next;
137 }
138 else
139 p = p->next; //执行完继续下一个体
140 }
141 }
142
143 int main(void)
144 {
145 FILE* fp = fopen("resultr6.txt", "w");
146 if (fp == NULL)
147 printf("error\n");
148 Sleep(2000); //挂起两秒钟
149 srand((unsigned)time(NULL)); //随机种子
150 Initialize(); //对初始个体进行初始化操作
151 for (t=0; t<1000; t++) //种群在该机制下演化一千个时间步
152 {
153 Aging(); //执行年龄增长机制
154 Die(); //执行死亡机制
155 RePreduction(); //执行繁殖机制
156 printf("A");
157 fprintf(fp, "%d\t", Nt);
158 }
159 fclose(fp);
160 return 0;
161 }
View Code
附图

