改进从数组向链表中插入元素的性能

Improving the Performance for inserting elements into Linked List from an Array

本文关键字:插入 元素 性能 链表 数组      更新时间:2023-10-16

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

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秒。

有人能帮忙吗?

现在,每次插入新节点时,都要查找最后一个节点。。。但是您可能已经知道最后一个节点在哪里了,因为您刚刚在最后一次迭代中插入了它——如果您没有扔掉这些信息就好了。只需将指向它的指针存储在一个变量中,该变量在迭代结束时不会被破坏。另一种方法是只在列表的前面插入,这对于单链接列表来说更为典型。如果希望元素的顺序与数组中的顺序相同,请按相反的顺序迭代数组。

取消对结束的线性搜索可以将算法的运行时复杂性从O(n^2)降低到O(n)。

另一个对性能影响较小,但会使代码更简单的优化:使用仅在前面插入的方法,并使用sentinel节点实现列表。这样,您就不需要在每次迭代中都有一个分支。也就是说,由于易于预测,该分支可能收效甚微。通过将测试移到循环之外,您也可以使用记住最后一个节点的方法来消除分支,但这不会简化代码。

EDIT:哨兵节点毕竟是不需要的,尽管它确实简化了其他一些列表算法。我很无聊,所以我实现了只在前面插入的方法:

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;
}

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

应用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();
    }
}

这个例子是在您想要实际追加操作的情况下完成的。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);

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

 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;
    }