#include <stdio.h>
#include <time.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
static unsigned long int next = 1; /* 种子*/
struct GNode //节点结构体
{
int tag; //是否有孩子
int id; //id 唯一,用于标记这头牛
int gend; //性别 0:male,1:female
int son_num; //儿子数量
int offset; //相对于页面的偏移量
int level; //标记这头牛在族谱图中的位置
int width; //以本头牛为根节点的树的宽度,用于控制输出
struct GNode * sublist; //子节点链表头
struct GNode * next; //下一个节点
};
struct level //用于存储一层的牛的信息的链表的结构体
{
struct GNode * data;
struct level * next;
};
int rand1 (void) //生成随机数,用于赋值id
{
/* 产生伪随机数癿魔术般癿公弅 */
next = next * 1103515245 + 12345;
return (unsigned int ) (next / 65536) % 32768;
}
void srand1 (unsigned int seed)
{
next = seed;
}
int getRandom (void)
{
if(next == 1)
srand1 ((unsigned int) time(0)); /* 初始化种子 */
return rand1();
}
bool id_ava(int id,int list[]) //查看ID是否已被用过
{
bool flag=true;
for(int i=0;i<sizeof(list);i++)
{
if(id==list[i])
flag=false;
}
return flag;
}
struct GNode * getCow(int n)
{
struct GNode * head = malloc(sizeof(struct GNode)); //链表头,没有内容
struct GNode * currcow ;
struct GNode * cow_g[n]; //用于存储公牛的数组
struct GNode * cow_m[n]; //用于存储母牛的数组
int num_g = 0;
int num_m = 0;
int num_tot=0; //当前已经生产的牛数量
int idList[n]; //已用id 列表
int index_f;
int index_m;
for(int i=0;i<n;i++)
{
struct GNode * newcow = malloc(sizeof(struct GNode));
int temp = getRandom();
while(num_tot!=0&&!id_ava(temp,idList))
{
temp = getRandom();
}
idList[i] = temp;
num_tot++;
newcow->id = temp; //结构体初始化
newcow->tag = 0;
newcow->son_num=0;
newcow->next = NULL;
newcow->offset=0;
newcow->gend = (getRandom())%2; //随机赋值性别
if(num_g&&num_m) //如果在这之前已有公牛和母牛,则随机制定父母
{
index_f=getRandom()%num_g;
index_m=getRandom()%num_m;
if(index_f>n||index_m>n)
printf("KKKKKKKKKKKKKKKKKKKKKKKKKKK\n");
cow_g[index_f]->tag=1;
if(cow_g[index_f]->son_num==0)
cow_g[index_f]->sublist = newcow; //将其添加到指定父亲节点的子节点链表的末尾,母亲节点则不存储
else
{
struct GNode * bro_temp = cow_g[index_f]->sublist;
while(bro_temp->next)
{
bro_temp=bro_temp->next;
}
bro_temp->next= newcow;
}
(cow_g[index_f]->son_num)++;
cow_m[index_m]->tag=1;
cow_m[index_m]->son_num++;
newcow->level = (cow_g[index_f]->level+1);
printf("~~id=[%d]~~father=[%d]~~~~~\n",newcow->id,cow_g[index_f]->id);
}
else
{
newcow->level = 1; //如果在这之前,没有公牛或者没有母牛,就不能指定父亲母亲,只能将其放到第一层
if(i==0)
{
head->next=newcow;
currcow = newcow;
}
else
{
currcow->next=newcow;
currcow = newcow;
}
}
if(newcow->gend==0) //如果把“==”写成"=",则该判别式始终为0
{
cow_g[num_g]=newcow; //如果是公牛,则添加到公牛数组中
num_g++;
}
else
{
cow_m[num_m]=newcow; //如果是母牛....
num_m++;
}
newcow = NULL; //释放指针
}
return head;
}
struct level * getdepth(struct GNode * cow,int dep) //获取cow节点之下的第dep层的节点列表,这里其实只用到dep=2 的情况
{
struct GNode * tmp;
struct GNode * fath;
struct level * lev_head = malloc(sizeof(struct level)); //
lev_head->next = NULL;
lev_head->data = NULL;
struct level * lev_curr = lev_head;
fath = cow;
while(fath)
{
if(fath->gend==0)
{
tmp = fath;
int i;
for(i=1;(tmp->sublist)&&(i<dep);i++)
{
tmp = tmp->sublist;
}
if((i==dep)&&tmp)
{
struct level * newmem = malloc(sizeof(struct level));
newmem->data = tmp;
newmem->next = NULL;
if(lev_head->next==NULL)
{
lev_head->next=newmem;
lev_curr = newmem;
}
else
{
lev_curr->next = newmem;
lev_curr = newmem;
}
}
}
fath = fath->next;
}
return lev_head;
}
struct level * getNextLev(struct level * head) //根据这一层的节点列表,获取下一层的节点列表
{
struct level * res = malloc(sizeof(struct level));
res->data=NULL;
res->next=NULL;
struct level * curbro;
if(head->next==NULL)
{
printf("NULL POINTER !\n");
return NULL;
}
struct level * bros = head->next;
struct GNode * bro_data ;
int i = 0;
while(bros)
{
bro_data = bros->data;
while(bro_data)
{
if(bro_data->tag!=0&&(bro_data->sublist))
{
struct GNode *test = bro_data->sublist;
while(test)
{
test = test->next;
}
struct level * newbro = malloc(sizeof(struct level));
newbro->data=bro_data->sublist;
if(res->next==NULL)
{
res->next=newbro;
curbro = newbro;
}
else
{
newbro->next=curbro->next;
curbro->next = newbro;
curbro = newbro ;
}
}
bro_data = bro_data->next;
}
bros = bros->next;
}
return res;
}
int getWid(struct GNode * node) //这里是用的迭代的办法,其实不想用的,最后没办法才用的,还希望大神可以指点一下,应该有其他办法
{
int wid = 3;
struct GNode * node_tmp;
if(node->sublist==NULL)
{
return 8;
}
else
{
node_tmp = node->sublist;
while(node_tmp)
{
wid += getWid(node_tmp);
node_tmp = node_tmp->next;
}
}
return wid;
}
void printLevel(struct GNode * head)
{
char * extra ;
int wid;
int space = 0;
printf("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&\n");
if(head->next==NULL)
{
printf("Empty list!\n");
return;
}
struct GNode * first_level = head->next; //先把第一层打印出来,第一层和下面的层不一样,不打印连接符
while (first_level)
{
wid = getWid(first_level);
if(first_level->id < 1000) extra = " ";
if(first_level->id>999&&first_level->id<10000) extra = " ";
if(first_level->id > 9999) extra = "";
first_level->offset = space;
if(first_level->gend==0)
{
printf("[%d%s] %*s",first_level->id,extra,wid-8,wid==8?"":" "); //控制每个id以及中括号一共7个字符宽度
if(first_level->sublist)
first_level->sublist->offset=first_level->offset+3;
}
else
{
printf("(%d%s) ",first_level->id,extra); //公牛打印中括号,母牛打印圆括号
}
space += wid;
first_level = first_level->next;
}
printf("\n");
struct level * cur_level = getdepth(head,2); //先获取第二层的所有牛,放在一个链表里面,再依次往下获取
struct level * bros;
struct GNode * bro_data;
while(cur_level->next) //依次循环各层
{
bros = cur_level->next;
space = 0;
while(bros) //依次循环各层内的各个level结构体
{
bro_data = bros->data;
int index = 0;
while(bro_data) //依次循环各个level结构体中的GNode结构体
{
wid = getWid(bro_data);
if(bro_data->id < 1000)
extra = " ";
else if(bro_data->id>999&&bro_data->id<10000)
extra = " ";
else if(bro_data->id > 9999)
extra = "";
if(index == 0) //一头公牛的所有子牛都是放在一个链表里面的,第一头子牛前面是“L”,用index来判断
{
if((bro_data->offset)<space)
{
printf("S"); //之前版本会出现这种情况,把getwid()函数写成迭代后,就不会出现这种情况了,但是保险起见还是放在这,没删去
}
printf("%*s",(bro_data->offset)-space,((bro_data->offset)-space)==0?"":" ");
printf("L");
space = (bro_data->offset) + 1;
}
else
{
bro_data->offset = space;
printf("-");
space += 1;
}
if(bro_data->gend==0) //公牛id打印完,需要打印占位符"-",跟后面的兄弟连起来
{
if(bro_data->sublist)
{
bro_data->sublist->offset = bro_data->offset+3;
}
printf("[%d%s]",bro_data->id,extra);
if(bro_data->next) //如果后面还有兄弟的话,就打印'-',没有的话打印空格
{
for(int i=0 ;i<wid-8 ;i++)
{
printf("%c",'-');
}
}
else
{
for(int i=0 ;i<wid-8 ;i++)
{
printf("%c",' ');
}
}
}
else
{
printf("(%d%s)",bro_data->id,extra);
}
space += wid-1;
bro_data = bro_data->next;
index++;
}
bros = bros->next;
}
printf("\n");
cur_level = getNextLev(cur_level);
}
printf("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&\n");
}
int main(int argc , char * argv[])
{
int cow_num = atoi(argv[1]);
struct GNode * cows = getCow(cow_num);
printLevel(cows);
return 0;
}
执行语句:
gcc -std=c99 PED.c -o ped
./ped 100 > test.txt
打印在txt中的显示效果(由于长度原因,这里只截取到左边一部分):