我正在经历一个应该“压扁”链接列表的程序。 要看看flatten的意思,这里是链接的代码 http://www.geeksforgeeks.org/flattening-a-linked-list/
#include <stdio.h>
#include <stdlib.h>
// A Linked List Node
typedef struct Node
{
int data;
struct Node *right;
struct Node *down;
} Node;
/* A utility function to insert a new node at the begining
of linked list */
void push (Node** head_ref, int new_data)
{
/* allocate node */
Node* new_node = (Node *) malloc(sizeof(Node));
new_node->right = NULL;
/* put in the data */
new_node->data = new_data;
/* link the old list off the new node */
new_node->down = (*head_ref);
/* move the head to point to the new node */
(*head_ref) = new_node;
}
/* Function to print nodes in the flattened linked list */
void printList(Node *node)
{
while(node != NULL)
{
printf("%d ", node->data);
node = node->down;
}
}
// A utility function to merge two sorted linked lists
Node* merge( Node* a, Node* b )
{
// If first list is empty, the second list is result
if (a == NULL)
return b;
// If second list is empty, the second list is result
if (b == NULL)
return a;
// Compare the data members of head nodes of both lists
// and put the smaller one in result
Node* result;
if( a->data < b->data )
{
result = a;
result->down = merge( a->down, b );
}
else
{
result = b;
result->down = merge( a, b->down );
}
return result;
}
// The main function that flattens a given linked list
Node* flatten (Node* root)
{
// Base cases
if ( root == NULL || root->right == NULL )
return root;
// Merge this list with the list on right side
return merge( root, flatten(root->right) );
}
// Driver program to test above functions
int main()
{
Node* root = NULL;
/* Let us create the following linked list
5 -> 10 -> 19 -> 28
| | | |
V V V V
7 20 22 35
| | |
V V V
8 50 40
| |
V V
30 45
*/
push( &root, 30 );
push( &root, 8 );
push( &root, 7 );
push( &root, 5 );
push( &( root->right ), 20 );
push( &( root->right ), 10 );
push( &( root->right->right ), 50 );
push( &( root->right->right ), 22 );
push( &( root->right->right ), 19 );
push( &( root->right->right->right ), 45 );
push( &( root->right->right->right ), 40 );
push( &( root->right->right->right ), 35 );
push( &( root->right->right->right ), 20 );
// Let us flatten the list
root = flatten(root);
// Let us print the flatened linked list
printList(root);
return 0;
}
我的问题是,在合并列表时,NULL指针永远不会在结果链接列表的末尾附加,所以当我们调用printList()
时,程序不应该崩溃,因为链接列表不会最后有一个NULL?
答案 0 :(得分:1)
没有。这段代码看起来相当不错。
让我们这样看待它。我们知道每个Node
对象都是有效的。两个列表中的最后一个列表中的最后一个列表为last->down == NULL
。当我们执行merge()
时,我们永远不会更改新last->down
的值,因此它会保留正确的NULL值。
为了更清楚一点,我们只在有两个节点时更改node->down
的值,并且每次只更改其中一个节点。所以merge()
的最后一次迭代,我们将传递一个指向节点的指针,以及一个指向NULL的指针。在这种情况下,我们将单独保留最终节点(并且它必须指向NULL,或者指向最终指向NULL的元素链)。
答案 1 :(得分:0)
merge
函数预先检测到NULL指针:
if (a == NULL)
return b;
if (b == NULL)
return a;
在递归调用merge()
时分配这些返回值:
result->down = merge( a->down, b );
…
result->down = merge( a, b->down );
flatten()
函数担心使用right
指针。但是,AFAICS,没有重置正确的指针。 printList()
函数不会查看它们,但如果您使用正确的指针进行打印,那么您会发现行为中存在一些怪癖。试试这个经过修改的printList()
:
void printList(Node *node)
{
while(node != NULL)
{
printf(" %d", node->data);
if (node->right != NULL)
{
putchar('[');
printList(node->right);
putchar(']');
}
node = node->down;
}
putchar('\n');
}
输出结果为:
5[ 10[ 19[ 20 20 22 30 35 40 45 50
] 20 20 22 30 35 40 45 50
] 19[ 20 20 22 30 35 40 45 50
] 20 20 22 30 35 40 45 50
] 7 8 10[ 19[ 20 20 22 30 35 40 45 50
] 20 20 22 30 35 40 45 50
] 19[ 20 20 22 30 35 40 45 50
] 20 20 22 30 35 40 45 50
所以,代码并不完美,但没有 - 我不希望它崩溃。