我想编写一个函数来提取索引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);
行
我认为这是一种可怕的方法,特别是在复杂性方面。 你能否指导我如何处理这个问题?
答案 0 :(得分:3)
您正在使用两种在您的方法中互斥的概念。通常,使用链表时,您不需要索引。使用数组时需要索引。在您的方法中,您正在使用链接列表,但您也使用索引,就好像链接列表是一个数组一样,因此它带来了更多的复杂性。
答案 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;
}