如何在 C 中将链接列表解连接为 3 个单独的链接列表?

Posted

技术标签:

【中文标题】如何在 C 中将链接列表解连接为 3 个单独的链接列表?【英文标题】:How can I de-concatenate a Linked List into 3 separate Link Lists in C? 【发布时间】:2021-07-08 09:49:49 【问题描述】:

所以我对数据结构还很陌生,我刚刚被介绍给单链表。我现在的任务是:

    将 3 个链接列表连接成一个链接列表 将大型链接列表解连接回 3x 链接列表。

我已经成功完成了第一步,我创建了 3 个单独的链接列表,然后将它们相互附加。但是我在去连接阶段遇到了一个小问题,我希望有人能解释我做错了什么。首先,这是我的代码...

#include <stdio.h>
#include <stdlib.h>

typedef struct node 
    int data;
    struct node * next;
 node;

node * createLL(int);
void displayLL(node * head);
node * concatenate(node * head1, node * head2, node * head3);
void deconcatenate(node * head1, node * head2, node * head3);

int main() 

struct node * head1 = NULL;
struct node * head2 = NULL;
struct node * head3 = NULL;
printf("Creating #1 Link List.. \n");
head1 = createLL(5);
displayLL(head1);

printf("\nCreating #2 Link List .. \n");
head2 = createLL(5);
displayLL(head2);

printf("\nCreating #3 Link List .. \n");
head3 = createLL(5);
displayLL(head3);

printf("\nConcatenating the Three Link Lists");
head1 = concatenate(head1,head2,head3);
displayLL(head1);

printf("\nDe-Concatenating the Link List into 3 Link Lists");
deconcatenate(head1,head2,head3);

printf("\nList #1\n");
displayLL(head1);
printf("\nList #2\n");
displayLL(head2);
printf("\nList #3\n");
displayLL(head3);



    void deconcatenate(node * head1, node * head2, node * head3) 
struct node * temp1;
struct node * temp2;
struct node * temp3;

int i,j,k;
i = j = k = 0;

temp1 = head1;

while (i < 5) 
    temp1 = temp1->next;
    i++;

head2 = temp1; // 6
temp1 = NULL;

temp2 = head2;

while (j < 5) 
    temp2 = temp2->next;
    j++;

head3 = temp2;
temp2 = NULL;

temp3 = head3;

while (k < 5) 
    temp3 = temp3->next;
    k++;

temp3 = NULL;



void displayLL(node * HEAD) 
    for(node * p = HEAD; p != NULL; p = p->next) 
        printf("%d->",p->data);
    
    printf("\n");


node * concatenate(node * head1, node * head2, node * head3) 
struct node * temp = head1;

while (temp->next != NULL) 
    temp = temp->next;


temp->next = head2;

while (temp->next != NULL) 
    temp = temp->next;


temp->next = head3;

return head1;



node * createLL(int n) 

int i = 0;
struct node * head = NULL;
struct node * temp = NULL;
struct node * p = NULL;

for(i = 0; i < n; i++) 

    temp = (node*)malloc(sizeof(node));
    printf("Enter data in Node #%d",i);
    scanf("%d",&(temp->data));
    temp->next = NULL;

    if (head == NULL) 
        head = temp;
     else 
        p = head;
        while (p->next != NULL) 
            p = p->next;
        
        p->next = temp;
    



return head;


这是输出

如您所见,在 De-Concatenation 之后,LinkList #1 只有“1”节点,而它应该有值 1 到 5 的节点。LinkList #2 的节点比它多应该有。它应该有值 6 到 10 的节点,但它有 6 到 15 的节点。链接列表 #3 是唯一具有准确节点值的节点。

那么我在 deconcatenate Function 中做错了什么?

【问题讨论】:

列表去串联的标准或条件是什么? 链接列表 (head1) 的长度为 15 个节点,我需要将其拆分为 3 个链接列表,每个链接列表有 5 个节点。就是这样。 【参考方案1】:

在我看来,这个作业对于初学者来说太难了。

如果您要通过连接其他三个列表的节点来构建一个列表,则指向三个列表的头节点的指针应通过引用传递,因为这些列表将在函数 concatenate 内更改。

即调用函数后三个列表为空。

在 C 中,通过引用函数来传递对象意味着通过指向它的指针间接传递对象。在这种情况下,该函数将通过取消引用指向该对象的指针来直接访问该对象。

所以函数至少应该像这样声明

node * concatenate(node ** head1, node ** head2, node ** head3); 

同样的考虑也适用于函数deconcatenate。调用函数后,原始列表应该是空的,因为它的元素正在被移动到其他三个列表中。

也就是说函数至少应该声明为

void deconcatenate(node **source_head, node ** head1, node ** head2, node ** head3);

但是这些函数的参数太多了。由于这两个函数都处理指向头节点的三重指针,因此最好声明一个具有三个数据成员的结构,这些数据成员保持指向头节点的指针的指针,并使用此结构的对象作为函数的参数。

例如

typedef struct triple_lists

    node **head1;
    node **head2;
    node **head3;
 triple_lists;

node * concatenate( triple_lists triple );
void deconcatenate( node **head, triple_lists triple );

正如我正确理解的那样,函数deconcatenate 应将源列表拆分为三个其他列表,这样每个列表将包含源列表的相邻元素,并且源列表应分为三个或多或少相等零件。

如果是这样,那么方法可以是以下。您需要三个指向节点的指针,它们将指定三个列表中每个列表的结尾。第一个指针前进一次,第二个指针前进两次,第三个指针前进三次,直到源节点不被耗尽。

这是一个演示程序。

#include <stdio.h>
#include <stdlib.h>

typedef struct node 

    int data;
    struct node *next;
 node;

typedef struct triple_lists

    node **head1;
    node **head2;
    node **head3;
 triple_lists;

int append( node **head, int data )

    node *new_node = malloc( sizeof( *new_node ) );
    int success = new_node != NULL;
    
    if ( success )
    
        new_node->data = data;
        new_node->next = NULL;
        
        while ( *head ) head = &( *head )->next;
        
        *head = new_node;
    
    
    return success;


FILE * display( const node *head, FILE *fp )

    for ( ; head != NULL; head = head->next )
    
        fprintf( fp, "%d -> ", head->data );
    
    
    fputs( "null", fp );
    
    return fp;


node * concatenate( triple_lists triple )

    node *head = NULL;
    node **current = &head;
    
    *current = *triple.head1;
    *triple.head1 = NULL;
    
    while ( *current != NULL ) current = &( *current )->next;
    
    *current = *triple.head2;
    *triple.head2 = NULL;

    while ( *current != NULL ) current = &( *current )->next;
    
    *current = *triple.head3;
    *triple.head3 = NULL;
    
    return head;


void deconcatenate( node **head, triple_lists triple )

    *triple.head1 = *head;
    *triple.head2 = *head;
    *triple.head3 = *head;
    
    triple_lists tails  =  head, head, head ;

    while ( *tails.head3 != NULL )
    
        for ( size_t i = 0; *tails.head1 != NULL && i < 1; i++ )
        
            tails.head1 =  &( *tails.head1 )->next; 
        
        
        for ( size_t i = 0; *tails.head2 != NULL && i < 2; i++ )
        
            tails.head2 =  &( *tails.head2 )->next; 
        
        
        for ( size_t i = 0; *tails.head3 != NULL && i < 3; i++ )
        
            tails.head3 =  &( *tails.head3 )->next; 
        
    

    *head = NULL;
    
    *triple.head2 = *tails.head1;
    *tails.head1 = NULL;
    
    *triple.head3 = *tails.head2;
    *tails.head2 = NULL;


int main(void) 

    node *head1 = NULL;
    node *head2 = NULL;
    node *head3 = NULL;
    
    int i = 0;
    while ( i < 10 )
    
        append( &head1, i++ );
    
    
    while ( i < 15 )
    
        append( &head2, i++ );
    
    
    while ( i < 18 )
    
        append( &head3, i++ );
    
    
    printf( "list1: " );
    putc( '\n', display( head1, stdout ) );
    
    printf( "list2: " );
    putc( '\n', display( head2, stdout ) );
    
    printf( "list3: " );
    putc( '\n', display( head3, stdout ) );
    
    putchar( '\n' );
    
    triple_lists triple =  &head1, &head2, &head3 ;
    
    node *head0 = concatenate( triple );
    
    printf( "list0: " );
    putc( '\n', display( head0, stdout ) );
    
    printf( "list1: " );
    putc( '\n', display( head1, stdout ) );
    
    printf( "list2: " );
    putc( '\n', display( head2, stdout ) );
    
    printf( "list3: " );
    putc( '\n', display( head3, stdout ) );
    
    putchar( '\n' );
    
    deconcatenate( &head0, triple );
    
    printf( "list0: " );
    putc( '\n', display( head0, stdout ) );
    
    printf( "list1: " );
    putc( '\n', display( head1, stdout ) );
    
    printf( "list2: " );
    putc( '\n', display( head2, stdout ) );
    
    printf( "list3: " );
    putc( '\n', display( head3, stdout ) );
    
    return 0;

程序输出是

list1: 0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> null
list2: 10 -> 11 -> 12 -> 13 -> 14 -> null
list3: 15 -> 16 -> 17 -> null

list0: 0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 13 -> 14 -> 15 -> 16 -> 17 -> null
list1: null
list2: null
list3: null

list0: null
list1: 0 -> 1 -> 2 -> 3 -> 4 -> 5 -> null
list2: 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> null
list3: 12 -> 13 -> 14 -> 15 -> 16 -> 17 -> null

我没有花时间编写一个清除列表以释放所有已分配内存的函数。希望你自己能写出这样的函数。

【讨论】:

【参考方案2】:

void deconcatenate() 中的 while 循环不应该是 less than 而不是 equal to?此外,您不需要循环遍历最后一个列表,只需将最后一个元素的 next 指针设置为 NULL,因为您在创建第一个链表时已经这样做了。

【讨论】:

是的,我将条件从 i == 5 替换为 i @VenoM 在您的 while 循环中,当 i == 4 并且代码运行后, temp1 指向第 6 个节点。因此,通过将 head2 分配给 temp1 的下一个节点,您实际上将 head2 分配为指向第 7 个节点。您现在可以只执行 head2 = temp1 或减少循环数,有很多方法可以做到这一点。正如我上面所说,您不需要遍历最后一个列表。 更新了原始帖子中的代码,但仍然没有提供所需的输出。输出为: Link #1: 1 to 15 Link #2: 6 to 15 Link #3: 11 to 15 @VenoM 这是因为您将 temp1 设置为 NULL 而 temp1 只是临时变量。您应该将第 5 个节点的 next 设置为 NULL。然后,正确终止第 5 个节点末尾的第一个链表。

以上是关于如何在 C 中将链接列表解连接为 3 个单独的链接列表?的主要内容,如果未能解决你的问题,请参考以下文章

如何在Dart中将列表转换为地图

在 linux 中编译/链接多个 c++ 库

是否可以在实体框架中将表FK链接到另外两个PK?

“从链接列表中删除循环”中的运行时错误

扩展解包不在列表中创建单独的项目

在 Postgres 中将多个值链接在一起