我正在为圣诞老人制作一个程序!我的知识是有限的;我迷失在指针和循环等方面,我已经想了几个小时了。
我有一个指向单链表的指针数组。每个数组索引指示0:0-3、1:4-7、2:8-11、3:11-15年龄组的儿童列表。
每个孩子都是一个结构,现在每年之后,我都想浏览所有列表,将他们的年龄增加1,如果他们需要更改年龄组,我必须将节点移动到包含该年龄组的适当列表中。如果子节点超过15岁,则必须删除该节点。我的代码是不完整的,因为我是链接列表的新手,我感到困惑。
我的主要问题是,我在浏览列表时会对列表进行更改,所以如果我检查第一个节点并将其删除,我必须再次检查第一个结点,因为现在它是一个新的结点,所以我一直检查,直到Head正常,这是正确的方法吗?我不确定我的代码是否有效,我还不能测试它。
我的Santa_Claus.h:
/*Structure defining a node of the children list*/
struct child {
int cid; /*The identifier of the child.*/
int age; /*The age of the child.*/
int did; /*The identifier of the child.*/
int present_choices[M]; /*The array in which the preferences of the child for presents are stored*/
struct child *next; /* Singly-linked, sorted by id */
};
Santa_Claus.c 中的部分
#define N 4 /*Number of children's age categories*/
struct child *Age_categories[N];
int new_season(void) {
int i;
struct child *childP = NULL;
struct child *prev = NULL;
struct child *childptr = NULL;
int MaxAges[N] = {3,7,11.15};
//Increment Age Loop
for(i = 0; i < N; i++){
childP = Age_categories[i];
while(childP != NULL){
childP->age = childP->age + 1;
childP = childP->next;
}
}
//Remove or Move Loop
for(i = 0; i < N; i++){
childP = Age_categories[i];
//while the first is still > than the max age of this category
while(childP->age > MaxAges[i]){
if(i != (N-1)){
childP->next = Age_categories[i+1];
Age_categories[i+1] = childP;
}else{
Age_categories[i] = childP->next;
}
childP = childP->next;
}
prev = Age_categories[i];
childP = prev->next;
while(childP != Null){
if(childP->age > MaxAges[i]){
if(i != (N-1)){
prev->next = childP->next;
childP->next = Age_categories[i+1];
Age_categories[i+1] = childP;
}else{
Age_categories[i] = childP->next;
}
}
prev = childP;
childP = childP->next;
}
}
return 1;
}
我的主要问题是,我在浏览列表时会对列表进行更改,所以如果我检查第一个节点并将其删除,我必须再次检查第一个结点,因为现在它是一个新的结点,所以我一直检查,直到Head正常,这是正确的方法吗?
在位编辑会在边缘情况下咬到你。头部和尾部节点会出现问题。如果你移除了头部,那么任何跟踪你头部的东西现在都指向空空间。
简而言之,你只需要小心。有很多方法可以把它搞砸。对于新手来说,我建议你远离C中的指针。强大,但很痛苦。除非你真的需要这个东西来扩展,否则坚持固定的数组。
你不需要重新检查头部,只需要有一个特殊的案例来检查头部,并进行头部安全编辑。此外,检查集合是否为空,以及检查尾部通常是个好主意。你可以尝试想出一些聪明的方法来避免这种事情,并拥有处理这一切的平滑代码。。。但是,聪明的代码往往同样会让你头疼。
我的主要问题是在浏览时对列表进行更改因此,如果我检查第一个节点并将其删除,我必须再次检查第一个节点,因为现在它是一个新节点,所以我保留检查,直到头部正常,这是正确的方法吗?
原则上,这是正确的方法,但不仅要对头部,还要对每个列表中的每个节点都这样做。您的代码并非在所有情况下都有效,例如
//while the first is still > than the max age of this category
while(childP->age > MaxAges[i]){
if(i != (N-1)){
childP->next = Age_categories[i+1];
Age_categories[i+1] = childP;
}else{
Age_categories[i] = childP->next;
}
childP = childP->next;
}
如果假设0岁年龄组的孩子已经4岁了,那么这就构成了一个无休止的循环。
考虑一下这个正确的代码,它更短,因此出错的机会更少:
// Remove or Move Loop
for (i = 0; i < N; i++)
{
struct child **chPA; // address of pointer to node under check
// for each node in age group i
for (chPA = &Age_categories[i]; childP = *chPA; )
if (childP->age > MaxAges[i])
{
*chPA = childP->next; // remove node from this list
if (i != N-1)
{
struct child **chPA; // address of pointer to node in next group
// find where in next group to insert the aged node
for (chPA = &Age_categories[i+1]; childptr = *chPA;
chPA = &childptr->next)
if (childptr->cid > childP->cid) break;
(*chPA = childP)->next = childptr;
}
else
free(childP); // delete the grown out node
}
else
chPA = &childP->next; // proceed to next node
}
(由于您的代码注释,它根据其cid
在下一个较高年龄组中插入一个节点
struct child *next; /* Singly-linked, sorted by id */