你将如何迭代这个2D链表?
typedef struct _NODE
{
char *pszName;
unsigned long ulIntVal;
char *pszString;
struct _NODE *pNext;
struct _NODE *pDown;
} NODE;
我可以做这样的事情......
NODE *pHEad;
while (pHead != NULL) {
printf("%s", pHead->pDown->pszName);
pHead = pHead->pNext;
}
..但它只会给我每个下一个节点下的一个节点。如果又是那个节点下的另一个节点怎么办?又在那个下?或者如果pNext
附加了pDown
?
答案 0 :(得分:3)
在最简单的情况下,您可以使用类似以下递归函数的内容:
void processNode(NODE *current) {
if (current != NULL) {
printf("%s", current->pszName);
processNode(current->pNext);
processNode(current->pDown);
}
}
int main(void) {
NODE *pHead;
/* ... Do something to fill your list ... */
processNode(pHead);
/* ... */
}
另请注意,这可能会导致函数调用的深层嵌套,具体取决于您处理的列表。因此,如果您使用的是具有有限堆栈大小的嵌入式系统,或者如果您正在处理大型列表,则可能会耗尽堆栈。在这种情况下,您应该找到另一种处理方法。
请注意,这将首先处理pNext-list,然后开始处理最后一个节点的pDown-list的第一个节点。因此,假设以下结构(右边是pNext,向下是pDown):
pHead -> p1 -------> p2
|- p1_1 |- p2_1 -> p2_1_1
\- p1_2 |- p2_2
\- p2_3 -> p2_3_1
它应按以下顺序打印节点:
pHead, p1, p2, p2_1, p2_1_1, p2_2, p2_3, p2_3_1, p1_1, p1_2
答案 1 :(得分:0)
看看这个答案。不要被代码量淹没。我添加了足够的评论来帮助您继续。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Node{
char data[100]; // Assume that this linked list will contain only 100 chars of data
struct Node* next;
} NODE;
// Global Variables are bad, but oh well.
NODE* head = NULL;
// Function to create a node
NODE* createNode(char* str)
{
// First allocate memory for struct
NODE* newNode = malloc(sizeof(NODE));
if(newNode == NULL)
{
printf("Unable to create a new node.");
}
else
{
// Use strcpy or strncpy or memcpy instead of doing something like newNode -> data = str, which changes the pointer, but doesn't copy the contents
// That is do not do newNode -> data = "hello" or something
strncpy(newNode -> data, str, strlen(str));
newNode -> next = NULL;
}
return newNode;
}
void addNode(char* str)
{
// Returns a node which contains str, but points to NULL
NODE* newNode = createNode(str);
// If the linked list is empty, then we make this node itself as the first node(or head)
if(head == NULL)
{
head = newNode;
}
// Else if the linked list is not empty, then we add this node at the start of the linked list
else
{
newNode -> next = head;
head = newNode;
}
}
int main()
{
// Example Linked List Generated(say you already have it in some form)
addNode("This");
addNode("Is");
addNode("Linked List");
// Now let's print the linked list
// Temporary NODE pointer ptr is used in order to not mess with the original NODE pointer head.
NODE* ptr = head;
// Traverse through the linked list starting from head and at the same time printing the corresponding data, until ptr is null
// This ptr != NULL check is exactly what you are looking for. This is your way of stopping the traversal of Linked List once you
// are at the end of it. You don't have to know the number of nodes to stop the traversal this way.
while(ptr != NULL)
{
printf("%s ", ptr -> data);
ptr = ptr -> next;
}
}
但请注意,输出将以相反的顺序打印,因为在链接列表的这个实现中,我们正在向后添加内容。只需尝试运行程序并从main
函数开始阅读程序。我已将代码分成单独的函数,以便您更容易理解。只需先运行代码即可掌握所发生的事情。
答案 2 :(得分:0)
如果你想避免堆栈溢出的可能性,你可以通过添加队列来使用迭代而不是递归 - 尽管这会使用更多的堆内存,并且仍然存在可能耗尽的风险堆内存,如果您有一个大型列表或者您是否在内存受限的系统上运行。最重要的部分是最后的print_list
功能;其他的东西只是我提供的(大部分)自我管理队列实现:
typedef struct node_queue NodeQueue;
struct node_queue {
NODE *n;
NodeQueue *next;
};
/*
* Add an item to the end of the queue.
*
* If the item could not be added, 0 is returned.
* Otherwise, a nonzero value is returned.
*/
int enqueue(NodeQueue **headp, NodeQueue **endp, NODE *n)
{
NodeQueue *old_end = *endp;
NodeQueue *new_end;
new_end = malloc(sizeof *new_end);
if (new_end == NULL) {
return 0;
}
new_end->n = n;
new_end->next = NULL;
if (old_end != NULL) {
old_end->next = new_end;
}
if (*headp == NULL) {
*headp = new_end;
}
*endp = new_end;
return 1;
}
/*
* Remove an item from the head of the queue,
* storing it in the object that "nret" points to.
*
* If no item is in the queue, 0 is returned.
* Otherwise, a nonzero value is returned.
*/
int dequeue(NodeQueue **headp, NodeQueue **endp, NODE **nret)
{
NodeQueue *old_head = *headp;
NodeQueue *new_head;
if (old_head == NULL) {
return 0;
}
if (nret != NULL) {
*nret = old_head->n;
}
new_head = old_head->next;
free(old_head);
if (new_head == NULL) {
*endp = NULL;
}
*headp = new_head;
return 1;
}
void print_list(NODE *start)
{
NodeQueue *head = NULL;
NodeQueue *end = NULL;
NODE *current;
current = start;
/* Iterate all `pNext` nodes, then pop each `pDown` node and repeat. */
for (;;) {
/* Add the "down" node to the node queue. */
if (current->pDown != NULL) {
if (!enqueue(&head, &end, current->pDown)) {
perror("warning: could not add node to queue");
}
}
printf("%s", current->pszNode);
/*
* Move to the "next" node.
* If there is no next node, get the first "down" node from the queue.
* If there is no "down" node, break the loop to end processing.
*/
current = current->pNext;
if (current == NULL) {
if (!dequeue(&head, &end, ¤t)) {
break;
}
}
}
}
这将迭代所有pNext
项目,然后转移到pDown
项目。以下二维列表将打印为A B C D E F G H I J K L M N O P Q
:
A
|
B--C
|
D--E-----------F
| |
G-----H I-----J
| | | |
K--L M--N O P
|
Q
您可以通过在其中pDown
和pNext
进行交换来反转print_list
/ pNext
pDown
功能的优先级,因此pNext
项目被添加到队列中,pDown
项目将被迭代,直到用尽为止,这将更改项目打印的顺序为A B D C E G K F I O H M Q L J P N
,除非您更改列表的结构。
您可以使用上面的代码和https://repl.it/NjyV/1上面的第一个示例2-D链接列表查看示例,但我更改了NODE
的定义以使代码使用其字段简单。