一种函数实现,用于剪切链接列表的一部分并将其附加到列表的末尾

时间:2014-02-27 19:07:18

标签: c algorithm data-structures linked-list

考虑以下功能:

void CustomAppender(int totalNodesToSkip, int totalNodesToCut);

此处totalNodesToSkiptotalNodesToCut都是给定的输入。因此,需要从头开始从totalNodesToCut编号的节点中剪切长度为totalNodesToSkip的给定链接列表的一部分。

考虑以下列表:

List_1a->b->c->d->e->f->g->h->i->j->k

该功能的输入为CustomAppender(2,3)

然后在第一遍中,列表应该变为:

List_2a->b->f->g->h->i->j->k->c->d->e. 因此,这里部分c-> d-> e移动到尾部。这个过程需要重复,直到我们到达给定列表的末尾。那就是当我们到达列表1的节点'k'时我们需要停止。

要解决问题,简单的方法是根据给定的输入将部分切割为: 在* Marker中为结束点'k'保留一个标记。

  1. * startPTR指向节点c。

  2. * endPTR指向节点e。 (两者都可以使用给定的输入进行迭代。)

  3. 接下来将b节点指向endPTR的下一个节点。

  4. 'k'节点的下一个指向startPTR。

  5. 最后endPTR指向NULL。

  6. 上述步骤可以重复,直到我们到达标记。

  7. 这很好。

    但我的问题是无论如何以任何不同的方式实现它,以便我使用较少的指针和更快的方法。由于此过程花费了O(n ^ 2)运行时间。

    请以任何其他方式提出建议。

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->kcut_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