【问题标题】:Splitting a linked list拆分链表
【发布时间】:2010-09-24 08:56:48
【问题描述】:

为什么在这个程序中拆分列表总是空的? (它源自链接列表上Wikipedia 页面上的代码。)

/* 
    Example program from wikipedia linked list article
    Modified to find nth node and to split the list
*/

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

typedef struct ns
{
    int data;
    struct ns *next; /* pointer to next element in list */
} node;

node *list_add(node **p, int i)
{
    node *n = (node *)malloc(sizeof(node));
    if (n == NULL)
        return NULL;

    n->next = *p; //* the previous element (*p) now becomes the "next" element */
    *p = n;       //* add new empty element to the front (head) of the list */
    n->data = i;

    return *p;
}

void list_print(node *n)
{
    int i=0;
    if (n == NULL)
    {
        printf("list is empty\n");
    }
    while (n != NULL)
    {
        printf("Value at node #%d = %d\n", i, n->data);
        n = n->next;
        i++;
    }
}

node *list_nth(node *head, int index) {
    node *current = head;
    node *temp=NULL;
    int count = 0; // the index of the node we're currently looking at
    while (current != NULL) {
        if (count == index)
            temp = current;
        count++;
        current = current->next;
    }
    return temp;
}
/* 
This function is to split a linked list:
Return a list with nodes starting from index 'int ind' and
step the index by 'int step' until the end of list.
*/
node *list_split(node *head, int ind, int step) {
    node *current = head;
    node *temp=NULL;
    int count = ind; // the index of the node we're currently looking at
    temp = list_nth(current, ind);
    while (current != NULL) {
        count = count+step;
        temp->next = list_nth(head, count);
        current = current->next;
    }

    return temp; /* return the final stepped list */
}

int main(void)
{
    node *n = NULL, *list1=NULL, *list2=NULL, *list3=NULL, *list4=NULL;
    int i;
    /* List with 30 nodes */
    for(i=0;i<=30;i++){
        list_add(&n, i);
    }
    list_print(n);

    /* Get 1th, 5th, 9th, 13th, 18th ... nodes of n etc */ 

    list1 = list_split(n, 1, 4);

    list_print(list1);

    list2 = list_split(n, 2, 4); /* 2, 6, 10, 14 etc */   
    list_print(list2);

    list3 = list_split(n, 3, 4); /* 3, 7, 11, 15 etc */   
    list_print(list3);

    list3 = list_split(n, 4, 4); /* 4, 8, 12, 16 etc */   
    list_print(list4);

    getch();
    return 0;
}

【问题讨论】:

  • 这似乎是一个任务......
  • 你有 list3 = 你的意思是 list4 = 在 main() 中。另外,为了可移植性,使用 getchar(),而不是 getch()。此外,由于 list_add 是向后的,您可能需要 for(i=30;i>=0;--i)

标签: c data-structures linked-list


【解决方案1】:
 temp = list_nth(current, ind);

 while (current != NULL) {
        count = count+step;
        temp->next = list_nth(head, count);
        current = current->next;
    }

您正在找到开始拆分的正确项目,但看看从那时起 temp 会发生什么......您只分配给 temp->next。

您需要跟踪拆分列表的头部和插入新项目的尾部。

【讨论】:

    【解决方案2】:

    实际上,这个程序有不止一个问题。

    • 索引不是处理链表内容的本机方式。通常,使用指向节点的指针或迭代器(它们是指向节点的伪装指针)。使用索引,访问节点具有线性复杂度 (O(n)),而不是常量 O(1)

    • 请注意,list_nth 返回指向列表中“活动”节点的指针,而不是副本。通过在list_split 中分配给temp-&gt;next,您正在重新连接原始列表,而不是创建一个新列表(但可能是故意的?)

    • list_split 内,temp 永远不会被推进,因此循环只会将节点连接到头部而不是尾部。

    • 由于使用 list_nth 通过从头开始遍历整个列表来查找节点,list_split 具有二次时间 (O(n**2)) 而不是线性时间。最好重写函数以遍历列表一次并在传递所需节点时复制(或重新附加)所需节点,而不是调用list_nth。或者,您可以写current = list_nth(current, step)

    • [编辑]忘了说。由于您正在重新连接原始列表,因此编写 list_nth(head, count) 是不正确的:它将通过“short-cirquited”列表,而不是未修改的列表。

    【讨论】:

    • list_nth 不是问题,因为它只是在列表中前进。如何使用是问题。
    • ysth 是正确的;我已经编辑了第 4 个项目符号以使其更精确。
    【解决方案3】:

    您对 list_split 应该返回的内容的描述非常清楚,但不清楚应该对原始列表发生什么(如果有的话)。假设它不应该改变:

    node *list_split(node *head, int ind, int step) {
        node *current = head;
        node *newlist=NULL;
        node **end = &newlist;
        node *temp = list_nth(current, ind);
    
        while (temp != NULL) {
            *end = (node *)malloc(sizeof(node));
            if (*end == NULL) return NULL;
            (*end)->data = temp->data;
            end = &((*end)->next);
            temp = list_nth(temp, step);
        }
    
        return newlist; /* return the final stepped list */
    }
    

    (您可能希望将一个 list_insert 例程从中插入一个新的 给定位置的节点。 list_add 不是很有用,因为它总是添加到 列表的开头。)

    【讨论】:

      【解决方案4】:

      我还注意到,当您计算 list_nth 时,您似乎跳过了列表中的第一条记录。请记住 C 我们通常从零开始计数。

      画出一个链表图并按照你的逻辑:

      [0]->[1]->[2]->[3]->[4]->[5]->[6]->[7]->[8]->[9]->...->[10]->[NULL]
      

      【讨论】:

      • 我没有看到这样的跳过。再看一遍?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-28
      • 2020-12-12
      相关资源
      最近更新 更多