C 如何遍历链表中的子节点?
我正在开发以下程序:C 如何遍历链表中的子节点?,c,pointers,linked-list,nodes,C,Pointers,Linked List,Nodes,我正在开发以下程序: ... typedef struct node_tag{ int id; char pLabel[10]; struct node_tag *pNext; struct node_tag *pInner; }NODE; ... int main(int argc, char** argv) { NODE *list = create_node("start"); add_node(&list,
...
typedef struct node_tag{
int id;
char pLabel[10];
struct node_tag *pNext;
struct node_tag *pInner;
}NODE;
...
int main(int argc, char** argv)
{
NODE *list = create_node("start");
add_node(&list, "MUSIC");
add_node(&list, "VIDEOS");
add_node(&list, "PICTURES");
create_sub_node( &list, "2015" ); // sub node of PICTURES
create_sub_node( &list, "Trip" ); // sub node of 2015
print_nodes(list);
return (EXIT_SUCCESS);
}
输出:
|
|-> [ID:4] PICTURES
| |-> [ID:40] 2015
| | |-> [ID:400] Trip
|
|-> [ID:3] VIDEOS
|
|-> [ID:2] MUSIC
|
|-> [ID:1] start
|
从输出中可以看出,到目前为止,一切都按照我的要求工作。但是,我想实现创建子节点的不同方法。我现在得到的是非常有限的,因为它只能创建2个子节点的深度,但我希望有无限的深度:
void create_sub_node( NODE **handle, char* label )
{
NODE *new = malloc( sizeof(NODE) );
new->pNext = NULL;
new->pInner = NULL;
strncpy( new->pLabel , label , strlen(label) +1 );
if( (*handle)->pInner == NULL )
{
new->id = (*handle)->id * 10;
(*handle)->pInner = new;
}
else if( (*handle)->pInner->pInner == NULL )
{
new->id = (*handle)->pInner->id * 10;
(*handle)->pInner->pInner = new;
}
}
我尝试实现while循环,该循环可以遍历内部节点,直到找到空节点,然后创建新节点。我遇到的问题是,当我遍历节点时,指针地址发生了变化,留下了一个不再工作的大烂摊子
我尝试复制内部节点的所有地址,但之后无法再次重新分配它们
问题是,我必须将子节点添加到列表中,这样我就可以更改各种指针地址,但要做到这一点,我需要一份列表的副本,在那里我可以使用它,这样原始地址就不会更改
如何迭代子节点并创建新节点,以便不必硬编码一堆IF语句?我的C有点生疏,但是:
NODE* tail(NODE* list) {
if (list == NULL) return NULL;
NODE* current = list;
while (current->pInner != NULL) { current = current->pInner; }
return current;
}
然后,您的函数变成:
void create_sub_node( NODE **handle, char* label )
{
NODE *new = malloc( sizeof(NODE) );
new->pNext = NULL;
new->pInner = NULL;
strncpy( new->pLabel , label , strlen(label) +1 );
NODE* last = tail((*handle));
new->id = last->id * 10;
last->pInner = new;
}
您的链接列表更像一棵树:
|-> MUSIC
| |-> Punk
| |-> Funk
|-> VIDEOS
| |-> Cats
| |-> Cars
| |-> Parties
|-> PICTURES
| |-> 2014
| | |-> Skiing
| | |-> Trip
| | |-> Thksgvg
| |-> 2015
| | |-> Birthday
| | |-> Wedding
您可以通过pNext
进入垂直线上的下一个节点(下一个最年长的兄弟节点),并通过pInner
进入更深一层(最年长的孩子)。可以通过节点指针访问节点的所有兄弟姐妹和所有子节点。你也可以把一个指针指向巴拉特河,这样你就可以向上走,而不仅仅是向下走
如果您具有创建节点和子节点并返回新节点的函数,则可以轻松构建这样的树:
int main(int argc, char **argv)
{
NODE *list = NULL; // list head
NODE *p; // first-generation child
NODE *q; // second-generation child
p = add_node(&list, "MUSIC");
create_sub_node(p, "Punk");
create_sub_node(p, "Funk");
p = add_node(&list, "VIDEOS");
create_sub_node(p, "Cats");
create_sub_node(p, "Cars");
create_sub_node(p, "Parties");
p = add_node(&list, "PICTURES");
q = create_sub_node(p, "2014");
create_sub_node(q, "Skiing");
create_sub_node(q, "Trip");
create_sub_node(q, "Thksgvg");
q = create_sub_node(p, "2015");
create_sub_node(q, "Birthday");
create_sub_node(q, "Wedding");
print_nodes(list);
return (EXIT_SUCCESS);
}
构建树时,必须为新节点的最小同级更改pNext
,该节点的pNext
为NULL
。确保仅在附加第一个节点时才更改列表的标题。同样,仅当添加第一个子节点时才更改节点的pInner
通常必须区分两种情况:第一个节点和后续节点。结合这些情况的一种技术是使用指向节点指针的指针遍历列表。该指针首先指向列表或子列表的头部,然后指向节点“pNext
”,如果有任何节点,即
这里有两个与上述main
一起使用的函数:
NODE *add_node(NODE **head, const char *label)
{
NODE **p = head;
// walk to the end
while (*p) p = &(*p)->pNext;
// append new node
*p = malloc(sizeof(**p));
(*p)->pInner = NULL;
(*p)->pNext = NULL;
snprintf((*p)->pLabel, sizeof((*p)->pLabel), "%s", label);
return (*p);
}
NODE *create_sub_node(NODE *node, const char *label)
{
NODE **p = &node->pInner;
// walk to the end
while (*p) p = &(*p)->pNext;
// append new node
*p = malloc(sizeof(**p));
(*p)->pInner = NULL;
(*p)->pNext = NULL;
snprintf((*p)->pLabel, sizeof((*p)->pLabel), "%s", label);
return *p;
}
你能告诉我们你试过什么吗?我想你的问题是你试着用
(*handle)=(*handle)->pInner
这样的东西迭代,你应该在那里做tmp=*handle编码>并在循环中使用tmp=tmp->pInner
。但是我真的说不出来,因为我没有看到你的代码。你确定你的create\u sub\u node
函数应该是这样工作的吗?在创建图片
节点后,如果要创建音乐
的子节点,该怎么办?如果add\u node
返回一个节点,然后将该节点传递到create\u sub\u node
,则If更有意义,而不是让它遍历您的节点。@Groo这是一个有趣的观察结果,但稍后我想修改create\u sub\u node
函数,使其在我将传递ID的节点下创建子节点。我想如果我朝那个方向走的话,返回节点的整个业务将在主代码中变得混乱。这比我拥有的更少,但我已经尝试了你的代码(我将函数调用中的代码直接添加到create\u sub\u node
中,它解决了我的问题!也许我的大脑因为花了太多时间而融化了一点,我可能遗漏了什么。还有一个问题:current=current->pInner
为什么不修改列表的原始内容?我的意思是我知道它是指针的副本,但它仍然指向某个对象,看起来某个对象被修改了,但不在原始列表中。这是为什么?@ShadyProgrammer:current
只是一个局部变量,它访问列表中的节点,但不修改它们。但在我的函数结束时,我这样做了current->pInner=new;
哪个更新了我的原始列表,而根据你说的不应该做的?我很困惑。@ShadyProgrammer在while循环的末尾,current
将包含链接列表中的最后一个元素。current->pInner
在这种情况下将是NULL
,因此你正在使current
指向它的内部po连接到您创建的新节点。还要注意->
操作符,该操作符取消引用指针以修改内容(因为当前节点是节点*
)谢谢你的上述建议。我明白你的意思,但是你不认为给函数create\u sub\u node
一个要在其下创建子节点的节点ID,而不是为子节点创建和返回变量要干净得多吗?当然,你可以为ID和节点保留一个单独的查找表。(它应该是一个散列或类似的函数。)如果你有一个函数node\u from\u id()
插入可以用相同的函数完成:create\u sub\u node(node\u from\u是(99),“Mexico”)
。使用最后一个节点的优点是,您不必查找它;您已经拥有了它。仅供参考,我放弃了将列表视为一个整体并使用复杂循环遍历它的原始方法,而是将头、第1代、第2代等视为彼此链接的单独列表呃,看来我得用一些动态的指针数组来跟踪新一代和新列表。哦,天哪,这会让人毛骨悚然……再次感谢你的建议:)