考虑以下功能:
void CustomAppender(int totalNodesToSkip, int totalNodesToCut);
此处totalNodesToSkip
和totalNodesToCut
都是给定的输入。因此,需要从头开始从totalNodesToCut
编号的节点中剪切长度为totalNodesToSkip
的给定链接列表的一部分。
考虑以下列表:
List_1
:a->b->c->d->e->f->g->h->i->j->k
该功能的输入为CustomAppender(2,3)
。
然后在第一遍中,列表应该变为:
List_2
:a->b->f->g->h->i->j->k->c->d->e.
因此,这里部分c-> d-> e移动到尾部。这个过程需要重复,直到我们到达给定列表的末尾。那就是当我们到达列表1的节点'k'时我们需要停止。
要解决问题,简单的方法是根据给定的输入将部分切割为: 在* Marker中为结束点'k'保留一个标记。
* startPTR指向节点c。
* endPTR指向节点e。 (两者都可以使用给定的输入进行迭代。)
接下来将b节点指向endPTR的下一个节点。
'k'节点的下一个指向startPTR。
最后endPTR指向NULL。
上述步骤可以重复,直到我们到达标记。
这很好。
但我的问题是无论如何以任何不同的方式实现它,以便我使用较少的指针和更快的方法。由于此过程花费了O(n ^ 2)运行时间。
请以任何其他方式提出建议。
答案 0 :(得分:3)
你可以在列表的一次通过中完成。
starting at the head of the list, move forward `(skip-1)` nodes. Call this `skip_ptr`.
start another pointer, call it `glue_ptr`. Move it forward `(cut-1)` nodes.
此时,skip_ptr
引用要跳过的最后一个节点,glue_ptr
引用要剪切的最后一个节点。
现在,将它们粘在一起并标记切割清单的末尾。
cut_ptr = skip_ptr.next; // save c->d->e
skip_ptr.next = glue_ptr.next; // attach a->b to f->g ...
glue_ptr.next = null; // mark e as the end of the cut list
现在你有a->b->f->g->h->i->j->k
,cut_ptr
指向c->d->e
。
现在,如果您设置glue_ptr = skip_ptr.next
并将glue_ptr
向前移动到glue_ptr.next == null
,则可以写下:
glue_ptr.next = cut_ptr; // attaches the cut part to the end of the list
你必须跟踪这些碎片。但它只在一次通过中完成操作:O(n)。
如果您必须重复跳过并剪切以便原始列表:
a,b,c,d,e,f,g,h,i,j,k
变为
a,b,f,g,k,c,d,e,h,i,j
您仍然可以通过列表中的一次传递来执行此操作。这是C#代码,展示了它是如何完成的。应该很容易转换为C.
private void CustomAppender(LLNode list, int skip, int cut)
{
LLNode skip_ptr = list;
LLNode cut_list = null;
LLNode cut_ptr = null;
while (skip_ptr.Next != null)
{
// skip over 'skip' items
for (int i = 1; i < skip && skip_ptr.Next != null; ++i)
{
skip_ptr = skip_ptr.Next;
}
// skip_ptr.next is the start of the next group we want to cut.
// move forward to the last node to be cut.
for (int i = 0; i < cut && skip_ptr.Next != null; ++i)
{
LLNode nodeToCut = skip_ptr.Next;
skip_ptr.Next = nodeToCut.Next;
nodeToCut.Next = null;
if (cut_list == null)
{
cut_list = nodeToCut;
}
else
{
cut_ptr.Next = nodeToCut;
}
cut_ptr = nodeToCut;
}
if (skip_ptr.Next != null)
skip_ptr = skip_ptr.Next;
}
// So now we have two lists.
// skip_ptr points to the last node in the list.
// Append cut_list to the end.
skip_ptr.Next = cut_list;
}
答案 1 :(得分:0)
我首先计算元素的总数。因为我们必须将elemenys分成3个链。现在从总数中减去跳过的数字。分裂链即
a->b c->d->e->f-g->h->i->j->k
现在,我们还剩下这个号码。现在取rehein数的模数。如果模块为0,那么在计数之后不做任何其他事情的数字将从最后分割开来。
如上所述你已经采取了3因此不需要任何操作来改善事物,但在2中分裂出来的是:
a->b c->d->e->f-g->h->i->j k
现在更改最后一个元素链2秒元素链:
a->b k c->d->e->f-g->h->i->j
现在将它们结合起来
a->b->k->c->d->e->f-g->h->i->j