如何";摘录;C中两个索引之间的链表中的节点?

如何";摘录;C中两个索引之间的链表中的节点?,c,linked-list,C,Linked List,我想编写一个函数,在索引x和索引y之间提取注释,并可以选择不修改原始列表或修改原始列表,以便删除提取的节点。该函数用于返回包含提取节点的列表 我目前的策略是使用helper函数复制链表,然后使用delete函数void delete(struct node*head,int x,int y)对两个列表(原始列表和要返回的列表)执行所需的删除 这是一个好策略还是效率太低?如果可能的话,我正在寻找O(n),但这看起来像O(n^2) 结构实现: struct node { int value;

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

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

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

结构实现:

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)

我认为这是一种可怕的方法,尤其是在复杂性方面。
你能告诉我如何处理这个问题的正确方向吗?

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

如果你真的需要索引,你能考虑使用数组吗?在这种情况下,一个memmove()就可以解决数组的问题 如果你想坚持链表,你能考虑使用不同于索引的东西吗?一个简单的例子是使用一个指向起始链接列表元素的指针,以及一个指向结束链接列表元素的指针,该元素将替换您建议的实现中的x和y索引
您使用的两个概念在您的方法中是相互排斥的。通常,在使用链表时,不需要索引。使用数组时需要索引。在您的方法中,您使用的是链表,但您也在使用索引,就像链表是一个数组一样,因此它带来了更大的复杂性

如果你真的需要索引,你能考虑使用数组吗?在这种情况下,一个memmove()就可以解决数组的问题 如果你想坚持链表,你能考虑使用不同于索引的东西吗?一个简单的例子是使用一个指向起始链接列表元素的指针,以及一个指向结束链接列表元素的指针,该元素将替换您建议的实现中的x和y索引
使用指针对指针将简化问题。它还允许您剪切链中的第一个节点(没有虚拟节点或反向指针)

  • 不进行复制,子链将被物理删除
  • 回来了

/*提取链接列表的一部分。
**skip是要跳过的节点数(skip==0表示:还将提取第一个节点)
**停止是节点*在*提取零件之后的位置
**(因此:skip=0,stop=1将提取一个节点:第一个)
*/
struct-llist*llist\u提取(struct-llist**pp,无符号跳过,无符号停止)
{
未签名pos;
struct-llist*result=NULL,**rpp;
如果(下一步停止){
如果(位置>=跳过)中断;
pos++;
}
/*现在,*pp指向要删除的第一个节点,
**这也是返回链的开始。
**和:*pp是重新连接ll尾部的位置
*/
结果=*pp;
对于(rpp=pp;*rpp;rpp=&(*rpp)->下一步){
如果(pos++>=停止)中断;
}
*pp=*rpp;/*将余数附加到初始部分*/
*rpp=NULL;/*终止提取的零件*/
返回结果;
}

试验台:

#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;
}
#包括
#包括
结构主义者{
struct-llist*next;
字符*有效载荷;
};
结构列表[]=
{{lists+1,“one”}
,{lists+2,“two”}
,{lists+3,“三”}
,{lists+4,“four”}
,{lists+5,“five”}
,{lists+6,“six”}
,{lists+7,“seven”}
,{lists+8,“八”}
,{lists+9,“nine”}
,{NULL,“十”}
};
int main(int argc,字符**argv)
{
struct-llist*root,*tmp;
无符号开始=0,停止=0;
如果(argc>=2)sscanf(argv[1]、“%u”、&start);
如果(argc>=3)sscanf(argv[2]、“%u”、&stop);
根=列表;
fprintf(stdout,“##%s\n”,“首字母:”);
对于(tmp=root;tmp;tmp=tmp->next){
fprintf(标准输出,“%s\n”,tmp->有效负载);
}
fprintf(标准输出,“##提取(%u..%u)\n)”,开始、停止;
tmp=llist_提取(根、开始、停止(&R));
对于(;tmp;tmp=tmp->next){
fprintf(标准输出,“%s\n”,tmp->有效负载);
}
fprintf(stdout,“##%s\n”,“Rest.”);
对于(tmp=root;tmp;tmp=tmp->next){
fprintf(标准输出,“%s\n”,tmp->有效负载);
}
fprintf(标准输出,“##%s\n”,“完成”);
返回0;
}

使用指针到指针将简化问题。它还允许您剪切链中的第一个节点(没有虚拟节点或反向指针)

  • 不进行复制,子链将被物理删除
  • 回来了

/*提取链接列表的一部分。
**skip是要跳过的节点数(skip==0表示:还将提取第一个节点)
**停止是节点*在*提取零件之后的位置
**(因此:skip=0,stop=1将提取一个节点:第一个)
*/
struct-llist*llist\u提取(struct-llist**pp,无符号跳过,无符号停止)
{
未签名pos;
struct-llist*result=NULL,**rpp;
如果(下一步停止){
如果(位置>=跳过)中断;
pos++;
}
/*现在,*pp指向要删除的第一个节点,
**这也是返回链的开始。
**和:*pp是重新连接ll尾部的位置
*/
结果=*pp;
对于(rpp=pp;*rpp;rpp=&(*rpp)->下一步){
如果(pos++>=停止)中断;
}
*pp=*rpp/*
#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;
}