如何在C中的两个索引之间的链表中“提取”节点?

时间:2016-12-22 13:02:30

标签: c linked-list

我想编写一个函数来提取索引x和索引y之间的注释,并且可以选择不修改原始列表或修改它以便删除提取的节点。该函数用于返回列出的列表以及提取的节点。

我目前的策略是使用辅助函数复制链接列表,然后使用删除函数void delete (struct node * head, int x, int y);在两个列表上执行所需的删除(原始列表和要返回的列表)。

这是一个好策略还是效率太低?如果可能,我正在寻找O(n),但这看起来像是O(n ^ 2)。

struct implementaiton:

struct node {
    int value;
    struct node *next;
    struct node *head;
    struct node *last;
}

我想写的两个函数是:

struct node *extract1(struct node *head, int x, int y);
// extract1 modifies original list.
struct node *extract2(struct node *head, int x, int y);
// extract2 does not modify original list.

我上面提到的删除功能已经过测试,可以根据需要运行。

struct node *extract1 (struct node *head, int x, int y){
    int currPos = 0;
    int len = length(head);
    struct node *curr = head;

    // I removed error checked for out of range indices for brevity

    struct node *copy = duplicate(stuct node *head);

    delete(curr, x, y); // modify original list

    // modify new list

    struct node *curr = copy;

    while (curr != NULL && currPos != x){ // traverse to x index
        delete(curr, 0, x);
        curr = curr->next;
        currPos++;
    }

    while (curr != NULL && currPos != y){ // traverse to x index
        delete(curr, y, len-1);
        curr = curr->next;
        currPos++;
    }

    return copy;
}

extract2类似,但缺少第delete(curr, x, y);

我认为这是一种可怕的方法,特别是在复杂性方面。 你能否指导我如何处理这个问题?

2 个答案:

答案 0 :(得分:3)

您正在使用两种在您的方法中互斥的概念。通常,使用链表时,您不需要索引。使用数组时需要索引。在您的方法中,您正在使用链接列表,但您也使用索引,就好像链接列表是一个数组一样,因此它带来了更多的复杂性。

  1. 如果你真的需要索引,你能考虑使用数组吗?在这种情况下,单个 memmove()将解决您的数组问题。
  2. 如果您想坚持使用链接列表,您是否可以考虑使用与索引不同的内容?一个例子就是使用指向启动linked_list_element 的指针,以及指向结束linked_list_element 的指针,它将取代 x y 您提议的实施中的索引。

答案 1 :(得分:1)

使用指针到指针将简化问题。我还将允许您剪切链中的第一个节点(没有虚节点或后投影)

  • 没有复制,子链被物理移除
  • 并返回
        /* Extract part of a linked list.
        **      skip is the number of nodes to skip (skip==0 means: the first node is also extracted)
        **      stop is position of the node *after* extracted part
        **      (so: skip=0,stop=1 will extract one node: the first)
        */
struct llist *llist_extract(struct llist **pp, unsigned skip, unsigned stop)
{
unsigned pos;
struct llist *result = NULL, **rpp;

if (stop <= skip) return NULL;

        /* Advance pointer2p `skip` positions  */
for (pos= 0; *pp; pp= &(*pp)->next) {
        if (pos >= skip ) break;
        pos++;
        }

        /* Now, *pp points to the first node to delete,
        ** it is also the start of the chain to return.
        ** And: *pp is the place to re-attach the trailing part of the ll
        */
result = *pp;
for ( rpp = pp; *rpp; rpp = &(*rpp)->next) {
        if (pos++ >= stop ) break;
        }
*pp = *rpp ;    /* append remainder to initial part */
*rpp = NULL;    /* terminate the extracted part */
return result;
}

试验台:

#include <stdio.h>
#include <string.h>

struct llist {
        struct llist *next;
        char *payload;
        };

struct llist lists[] =
{{ lists+1, "one" }
,{ lists+2, "two" }
,{ lists+3, "three" }
,{ lists+4, "four" }
,{ lists+5, "five" }
,{ lists+6, "six" }
,{ lists+7, "seven" }
,{ lists+8, "eight" }
,{ lists+9, "nine" }
,{ NULL, "ten" }
        };

int main(int argc, char **argv)
{
struct llist *root,*tmp;
unsigned start=0, stop=0;

if (argc >=2) sscanf(argv[1], "%u", &start);
if (argc >=3) sscanf(argv[2], "%u", &stop);

root = lists;
fprintf(stdout, "## %s\n", "initial:" );
for (tmp=root; tmp; tmp=tmp->next) {
        fprintf(stdout, "%s\n", tmp->payload);
        }

fprintf(stdout, "## extract(%u..%u)\n", start,stop );
tmp = llist_extract(&root, start, stop);

for (; tmp; tmp=tmp->next) {
        fprintf(stdout, "%s\n", tmp->payload);
        }

fprintf(stdout, "## %s\n", "Rest." );
for (tmp=root; tmp; tmp=tmp->next) {
        fprintf(stdout, "%s\n", tmp->payload);
        }
fprintf(stdout, "## %s\n", "done." );

return 0;
}