簡體   English   中英

使用雙指針在鏈接列表中插入節點

[英]Inserting a Node in a linked list using double pointers

我最近看到了一種使用雙指針從單個鏈接列表中刪除節點的實現。 除了使代碼更漂亮以外,此實現在效率方面也沒有任何好處。 另外,如何實現將節點插入鏈表的類似方法(無需跟蹤先前的Node)。 我真的很好奇是否有更好的算法可以實現這一目標

Node* Delete(Node *head, int value)
{
    Node **pp = &head; /* pointer to a pointer */
    Node *entry = head;
    while (entry ) 
    {
        if (entry->value == value)
        {
            *pp = entry->next;
        }
        pp = &entry->next;
        entry = entry->next;
    }
    return head;
}

為了插入僅包含頭而沒有尾的列表的后面(這意味着可以接受線性時間插入的小列表),可以通過引入額外的指針間接性來消除特殊情況,從而做到這一點:

簡單版本(指向節點的指針)

void List::push_back(int value)
{
    // Point to the node link (pointer to pointer to node), 
    // not to the node.
    Node** link = &head;

    // While the link is not null, point to the next link.
    while (*link)
        link = &(*link)->next;

    // Set the link to the new node.
    *link = new Node(value, nullptr);
}

...您可以簡化為:

void List::push_back(int value)
{
    Node** link = &head;
    for (; *link; link = &(*link)->next) {}
    *link = new Node(value, nullptr);
}

相反,說:

復雜版本(指向節點的指針)

void List::push_back(int value)
{
    if (head)
    {
        // If the list is not empty, walk to the back and
        // insert there.
        Node* node = head;
        while (node->next)
             node = node->next;
        node->next = new Node(value, nullptr);
    }
    else
    {
        // If the list is empty, set the head to the new node.
        head = new Node(value, nullptr);
    }
}

為了公平起見,刪除評論:

void List::push_back(int value)
{
    if (head)
    {
        Node* node = head;
        for (; node->next; node = node->next) {}
        node->next = new Node(value, nullptr);
    }
    else
        head = new Node(value, nullptr);
}

簡單版本沒有特殊情況

第一個版本不需要特殊情況下的空列表的主要原因是因為如果我們想象head為null:

Node** link = &head; // pointer to pointer to null
for (; *link; link = &(*link)->next) {}
*link = new Node(value, nullptr);

然后for循環條件立即為false,然后將新節點分配給head 當我們使用指針指向指針時,我們不必在循環外單獨檢查這種情況。

插入排序

如果要進行插入排序,而不是簡單地插入到后面,則可以執行以下操作:

void List::insert_sorted(int value)
{
    Node** link = &head;
    for (; *link && (*link)->value < value; link = &(*link)->next) {}

    // New node will be inserted to the back of the list
    // or before the first node whose value >= 'value'.
    *link = new Node(value, *link);
}

性能

至於性能,不確定是否要消除多余的分支,但這肯定會使代碼更加緊湊並降低了循環復雜性。 Linus認為這種樣式“好口味”的原因是因為在C語言中,您經常不得不編寫鏈表邏輯,因為它不那么容易,而且值得歸納鏈表,因為我們那里沒有類模板,因此值得一概而論,例如,便於使用更小巧,更優雅,更不易出錯的方式編寫這些內容。 此外,它還表明您對指針非常了解。

除了使代碼更漂亮以外,此實現還沒有任何效率方面的好處。

沒有什么可比擬的,很難說,但這與從鏈表中刪除節點一樣有效。 請注意,函數名稱Delete將比Remove更准確,因為它實際上並未清除從列表中刪除的節點。

另外,如何實現將節點插入鏈表的類似方法(無需跟蹤先前的Node)。

一種方法是向前看。 最好在一個示例中以刪除功能的格式顯示。

void insert(Node *head, int value)
{
    Node *entry = head;
    while (entry)
    {
        if (entry->next == NULL)
        {
            entry->next = new Node(NULL, value);
            return;
        }
        else if (value < entry->next->value)
        {
            entry->next = new Node(entry->next, value);
            return;
        }
        entry = entry->next;
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM