【问题标题】:Improving the Performance for inserting elements into Linked List from an Array提高将元素从数组插入链表的性能
【发布时间】:2016-02-22 15:32:09
【问题描述】:

我想将数组的元素插入到链表中。以下是我正在使用的一段代码:

for (int i = 0; i<MAXSIZE; i++)
    {
        Node* n1 = new Node();
        n1->SetData(randArray[i]);
        n1->SetIndex(i);
        n1->SetNext(NULL);

        //checks if NULL
        if (start == NULL) {
            start = n1;
            start->SetNext(NULL);
        }
        else {
            //inserts the values to the end of the node
            Node *p = start;
            while (p->GetNext() != NULL) {
                p = p->GetNext();
            }
            p->SetNext(n1);
        }
    }

这里 randArray[i] 包含 100000 个元素。

现在我希望这个过程执行得更快。目前,50000 个元素需要 13 秒。

有人可以帮忙吗?

【问题讨论】:

  • 好像没有人提到内存池和自定义分配器。
  • @ddriver 一位用户确实推荐了内存池,但随后删除了他们的评论。我猜这些东西超出了 Vamsi 所寻找的范围,尽管它们可能对其他拥有算法合理程序但仍需要它更快的人有用。

标签: c++ arrays data-structures linked-list singly-linked-list


【解决方案1】:

如果你想在最后一个位置添加,你不需要每次都在链表上迭代,你只需保持最后一个节点的引用,它将在下一个节点添加节点。喜欢:-

 Node* head ;
    Node* last= null;
    for (int i = 0; i < MAXSIZE; i++) {

        Node* n1 = new Node();
        n1->SetData(randArray[i]);
        n1->SetIndex(i);
        n1->SetNext(null);
        if(last != null){
             last->SetNext(n1);
        }else{
           head = n1;
        }
        last = n;
    }

【讨论】:

  • 您从未设置任何内容指向您创建的第一个节点。之后你会如何使用这个列表?
  • 请再看一遍代码可能是你没有理解正确。
  • 我仔细查看了它,您没有在任何地方设置指向您创建的第一个节点的指针。算法之后剩下的唯一指针是last。您无法从last 访问任何其他节点,因此它们似乎完全无法访问。在我看来,您已经泄露了其余的节点。我再问你一次,你会如何使用这个列表?
  • 感谢您指出错误我现在明白了您的意思并更正了代码。
【解决方案2】:

您现在每次插入新节点时都在寻找最后一个节点...但是您已经知道最后一个节点在哪里,因为您只是在最后一次迭代中插入了它 - 只要您没有抛出那个信息远。只需将指向它的指针存储在一个变量中,该变量在迭代结束时不会被销毁。另一种方式——这对于单链表来说更典型——是只在列表的前面插入。如果您希望元素与数组中的元素顺序相同,则以相反的顺序迭代数组。

摆脱对 end 的线性搜索可将算法的运行时复杂度从 O(n^2) 降低到 O(n)。

另一个对性能影响较小但会使您的代码更简单的优化:使用 insert-in-front-only-approach 并使用哨兵节点实现您的列表。这样你就不需要在每次迭代中都有一个分支。也就是说,由于易于预测,该分支可能影响不大。您也可以使用记住最后一个节点的方法来摆脱分支,方法是将测试移到循环之外,但这不会简化您的代码。

编辑:毕竟不需要哨兵节点,即使它确实简化了一些其他列表算法。我很无聊,所以我实现了 insert-in-front-only 方法:

Node* head = nullptr;
for (size_t i = MAXSIZE; i --> 0;) {
    Node* n = new Node();
    n->SetData(randArray[i]);
    n->SetIndex(i); // †
    n->SetNext(head);
    head = n;
}

† 如果您真的想将索引存储在节点中,您可能需要重新考虑。当节点稍后从尾部以外的任何其他地方插入或删除时更新它会很慢。

【讨论】:

  • 您好,我从理论上理解了您的答案,但是如何在我的代码中实现它。你能证明一下吗?我对链表主题有点陌生
  • @Vamsi 向我们展示您是如何尝试实现它的,我们可以告诉您出了什么问题。也就是说,m_pOatrix 刚刚为您发布了一个实现。
  • @user2079303 - 您的答案显示节点被插入到列表的开头,但问题示例代码是将节点附加到列表的末尾,这通常使用指向最后一个节点的指针来完成一个列表。
  • @rcgldr 您通常不会在单链表的末尾插入,但当然可以通过将指向节点的指针存储在变量中来实现。正如我在回答中解释的那样,Vamsi 可以做到这一点。插入节点的顺序无关紧要,只要插入后节点的顺序正确即可。我反向迭代数组,所以结果是一样的,但代码要简单得多。
  • @rcgldr forward_list::end 不返回最后一个元素。它将迭代器返回到最后一个元素之后的位置(即最后一个元素指向的位置),就像任何其他标准容器的 end 一样。您只能在单链表中插入 after 元素,并尝试在 forward_list::end 之后插入将是一场灾难。您要做的是在节点 before end 之后插入。如果要在forward_list的末尾插入或拼接,需要自己去跟踪尾部。尾部未存储在forward_list 实例中。
【解决方案3】:

这个例子是在你想要一个实际的追加操作的情况下完成的。 get 和 set 函数阻止您使用指向指针的指针,但这只需要一个 if 语句来检查空列表。

    Node* tail;  // pointer to last node on list (if start != NULL)
    for (int i = 0; i<MAXSIZE; i++)
    {
        Node* n1 = new Node();
        n1->SetData(randArray[i]);
        n1->SetIndex(i);

        //checks if empty list
        if (start == NULL) {
            start = n1;
            tail = n1;
        }
        else {
            tail->SetNext(n1);
            tail = tail->GetNext();
        }
    }
    tail->SetNext(NULL);

【讨论】:

    【解决方案4】:

    应用 user2079303 建议,

    你应该有类似的东西:

    Node *p = start;
    for (int i = 0; i<MAXSIZE; i++)
    {
        Node* n1 = new Node();
        n1->SetData(randArray[i]);
        n1->SetIndex(i);
        n1->SetNext(NULL);
    
        //checks if NULL
        if (start == NULL) 
        {
            start = n1;
            start->SetNext(NULL);
            p = start;
        }
        else 
        {
            //inserts the values to the end of the node
            p->SetNext(n1);
            p = p->GetNext();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-16
      • 1970-01-01
      • 1970-01-01
      • 2018-08-02
      • 2013-02-17
      • 1970-01-01
      • 2016-01-05
      • 2021-08-01
      相关资源
      最近更新 更多