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 }
附图