簡體   English   中英

單鏈接列表刪除

[英]Singly-Linked List remove

我當時正在執行單鏈列表,並且我記得Linus Torvalds在這里談論它。

在單鏈列表中,為了刪除節點,我們應該有權訪問前一個節點,然后更改其當前指向的節點。

像這樣 在此處輸入圖片說明

因此,我們應該可以使用任何方式訪問上一個節點。

但是萊納斯·托瓦爾茲(Linus Torvalds)通過使用C語言中的地址概念來刪除特殊情況。因此,頭也具有“先前的事物”,即頭的地址指向頭。 因此,他使用了C的指針和地址功能來刪除特殊情況。

特殊情況下的普通代碼 在此處輸入圖片說明

特殊情況下的代碼變成普通情況 在此處輸入圖片說明

我認為單鏈列表中的這種特殊情況下的刪除無法在python中完成,因為我們沒有指針的概念(因此,我將無法走到前面)。 我對嗎 ?

當然,您可以在Python中執行此操作。 他的意思是,您具有一些數據結構,該數據結構表示列表本身並指向列表的開頭,並且您在處理第一個列表項時就像在列表項中使用指針一樣對其進行操作。

現在,Python不是C,因此實現會有所不同,但是原理仍然適用。 列表本身與第一個項目不是同一對象,並且列表項不應該與整個列表具有相同的方法,因此有必要為它們使用不同種類的對象。

但是,它們兩者都可以使用相同名稱的屬性(例如next )來指向下一項。 因此,當您遍歷列表時,您位於第一個項目上,“上一個”項目就是列表本身,如果您需要刪除第一個項目,則需要操縱它的next屬性。

當然,在現實世界中,除非作為練習,否則您永遠不會編寫自己的Python鏈表類。 內置list更加有效。

您不能在Python中使用Linus的特定技巧,因為眾所周知,Python沒有指針(這樣)或地址運算符。 但是,您仍然可以通過為列表賦予虛擬頭節點來消除列表頭的特殊情況。 您可以將其作為列表設計的固有部分來執行,也可以僅通過創建一個額外的節點並將其引用為第一個數據承載節點作為下一個節點來進行。 無論哪種方式,您可能要刪除的所有節點都是內部節點,而不是特殊情況。

在閱讀您的問題時,我的第一個想法是:為什么要在python中建立一個單鏈表? Python提供了很多集合類型,您可以使用它們而不必擔心它們是作為單鏈表,雙鏈表還是某些非遞歸數據結構(通常更易於處理)實現的。

但是,您的問題的答案是:Python當然允許構建單鏈列表。 例如,以下代碼就是這樣做的:

class Node:
    def __init__(self, x, next):
        self.x = x
        self.next = next

    def __str__(self):
        return "<{}, {!s}>".format(self.x, self.next)

n = Node(1, None)
n = Node(2, n)
n = Node(3, n)
print(n)  # output: <3, <2, <1, None>>>

n.next.next = n.next.next.next
print(n)  # output: <3, <2, None>>

與C的不同之處在於:我們不需要malloc()或使用指針,因為python為我們處理了內存。 Python有引用而不是指針,它們很相似,但更安全,更易於使用。

但是,在實現鏈接列表之前,您應該考慮對集合的要求,也許您可​​以從內置插件或集合模塊中選擇一個合適的集合。

您需要按照Linus的建議進行兩級間接操作,但是您可能可以在Python中做到這一點,也許是通過對對象的引用來存儲對象的引用或此類對象(索引的索引?)。 。 也就是說,我認為它不能如此優雅或高效地映射到Python,並且僅使用一個對象來表示鏈接結構中的單個鏈接可能會非常浪費。

在Python的情況下,我只需要執行額外的分支來檢查您是否要從頭部移開,除非我缺少一些技巧。

至於自己實現鏈表,我實際上發現了很多用例,其中標准庫不足以滿足需求。 這是一個例子:

在此處輸入圖片說明

...網格可能有10,000個單元格。 標准庫提供的大多數鏈表都沒有經過優化,無法以每個列表32位索引的大小存儲10,000+個鏈表,因為它們試圖提供允許隔離使用鏈表的接口(而不是使用單獨的后備數據結構,以像數組一樣存儲)。 通常,最有效地使用鏈表是不擁有內存或管理任何資源的鏈表。 它只是以已經在另一數據結構中分配和管理的輔助方式鏈接數據,例如對於n元樹中的128位(16字節)樹節點的鏈接,其中元素可以存儲在層次結構的任何級別:

struct TreeNode
{
     int32 parent;       // parent index or -1 for no parent
     int32 first_child;  // first child of this node or -1
     int32 next_sibling; // next child for the parent node or -1
     int32 element;      // element data stored in this node or -1
                         // if no data is associated
};

因此,有很多用例可以實現自己的鏈接列表和其他鏈接結構,對於更狹窄適用的用例(網格數據結構,八叉樹,四叉樹,圖等),它們的效率要高得多。不要以為您不能在不容易允許您使用兩個或多個級別的指針間接性的語言中使用此技巧。 Python本質上只為對象提供一個-與Java和C#相同。 您需要類似“對對象的引用的引用” 對對象索引的索引”“對對象的對對象引用的索引”之類的東西

此外,鏈表通常在不允許您管理所有內容存儲在哪里的語言中用處不大,因為您最終可能會在鏈表中反復遍歷緩存,從而導致高速緩存未命中,否則,如果每個列表節點通常都分散在內存中,例如,在GC周期之后,例如,要使鏈接列表真正有效,就像在Linux內核中那樣,則您必須能夠對每個節點在內存中的位置進行真正的控制,以便在大多數情況下可以遍歷列表不完全是,只是遍歷連續的內存塊。 否則,您通常最好使用小型數組,即使這意味着線性時間刪除和從中間插入/從中間插入也是如此。

暫無
暫無

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

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