如果你學過資料結構,就一定會遇到“堆”,"棧","堆疊",這些對於小白來說有些頭大,下面就來科普一下何謂堆疊?
按照WIKI的定義:
堆疊(英語:stack),是計算機科學中一種特殊的串列形式的抽象資料型別,其特殊之處在於只能允許在連結串列或陣列的一端(稱為堆疊頂端指標,英語:top)進行加入資料(英語:push)和輸出資料(英語:pop)的運算。另外堆疊也可以用一維陣列或連結串列的形式來完成。堆疊的另外一個相對的操作方式稱為佇列。需要記住的是,堆:順序隨意,棧:後進先出(Last-In/First-Out)。
這裡的pop和push到都是什麼意思?其實這是堆疊資料結構使用兩種基本操作:推入(壓棧,push)和彈出(彈棧,pop):
推入:將資料放入堆疊的頂端(陣列形式或串列形式),堆疊頂端top指標加一。
彈出:將頂端資料資料輸出(回傳),堆疊頂端資料減一。
如要了解堆疊,應將之拆開分析。
堆的概念:
堆(英語:Heap)是計算機科學中的一種特別的樹狀資料結構。通常是一個可以被看做一棵樹的陣列物件。若是滿足以下特性,即可稱為堆:“給定堆中任意節點 P 和 C,若 P 是 C 的父節點,那麼 P 的值會小於等於(或大於等於) C 的值”。若父節點的值恆小於等於子節點的值,此堆稱為最小堆(英語:min heap);反之,若父節點的值恆大於等於子節點的值,此堆稱為最大堆(英語:max heap)。在堆中最頂端的那一個節點,稱作根節點(英語:root node),根節點本身沒有父節點(英語:parent node)。
棧的概念
棧(stack)又名堆疊,它是一種運算受限的線性表。其限制是僅允許在表的一端進行插入和刪除運算。這一端被稱為棧頂,相對地,把另一端稱為棧底。棧就是一個桶,後放進去的先拿出來,它下面本來有的東西要等它出來之後才能出來(先進後出)
棧(Stack)是作業系統在建立某個程序時或者執行緒(在支援多執行緒的作業系統中是執行緒)為這個執行緒建立的儲存區域,該區域具有FIFO的特性,在編譯的時候可以指定需要的Stack的大小。
堆疊
其實堆疊本身就是棧,只是換了個抽象的名字。其特性是: 最後一個放入堆疊中的物體總是被最先拿出來,這個特性通常稱為後進先出(LIFO)佇列。堆疊中定義了一些操作。 兩個最重要就是上述提到的PUSH和POP。PUSH操作在堆疊的頂部加入一個元素,POP操作相反,在堆疊頂部移去一個元素,並將堆疊的大小減一。
工作原理
對於工作方式你可能還是一頭霧水,以自助餐托盤為例解釋一下,你就會更加明瞭:
作為堆疊如何工作的一個例子,可以把它看成一個彈簧載入托盤分發器,這種型別經常在自助餐廳中發現。每個托盤上都刻有數字。托盤依次從頂部裝入,每個托盤都放置在已經裝入的托盤上,彈簧進行壓縮,以便在必要時為更多托盤留出空間。例如,在圖中,托盤編號為42、23、2、9,先裝載42個托盤,後裝載9個托盤。
最後一個托盤是9號。因此,“第一個出來”的盤子也是9號。當顧客從托盤堆的頂部取出托盤時,第一個托盤是9號,第二個托盤是2號。然後更多的托盤被新增。這些托盤將不得不在我們裝載第一個托盤之前從堆疊上下來。在托盤堆的任意順序的push和pop出之後,托盤42仍然在底部。只有在42號托盤從堆疊頂部彈出後,堆疊才會再次清空。
而堆疊通常被放置在機器的最上面的地址區域。它們通常從最高的記憶體位置增長到較低的記憶體位置,允許在程式記憶體末端和堆疊“頂部”之間的記憶體使用中獲得最大的靈活性。在我們的討論中,堆疊在記憶體中是“向上”增長還是“向下”增長基本上是不相關的。堆疊的“top”元素是最後被推入並將首先被彈出的元素。堆疊的“底部”元素在刪除時將使堆疊為空。
二者區別
堆是在程式執行時,而不是在程式編譯時,申請某個大小的記憶體空間。即動態分配記憶體,對其訪問和對一般記憶體的訪問沒有區別。它由程式設計師分配和回收。
棧就是一個桶,後放進去的先拿出來,它下面本來有的東西要等它出來之後才能出來。(後進先出)由系統自動分配和回收。
堆疊快取方式
棧使用的是一級快取, 他們通常都是被呼叫時處於儲存空間中,呼叫完畢立即釋放。
堆則是存放在二級快取中,生命週期由虛擬機器的垃圾回收演算法來決定(並不是一旦成為孤兒物件就能被回收)。所以呼叫這些物件的速度要相對來得低一些。棧的優勢是,存取速度比堆要快,僅次於直接位於CPU中的暫存器。
棧:在Windows下,棧是向低地址擴充套件的資料結構,是一塊連續的記憶體的區域。意思是棧頂的地址和棧的最大容量是系統預先規定好的,在 WINDOWS下,棧的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數),如果申請的空間超過棧的剩餘空間時,將提示overflow。因此,能從棧獲得的空間較小。
堆:堆是向高地址擴充套件的資料結構,是不連續的記憶體區域。這是由於系統是用連結串列來儲存的空閒記憶體地址的,自然是不連續的,而連結串列的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬記憶體。由此可見,堆獲得的空間比較靈活,也比較大。
作為“堆”的資料空間,必須是靈活的,因為成千上萬的程式設計師在寫什麼程式是未知的。但可知道的一點,就是他們是跑在確定的某個OS裡面的。因此,也不過就是給系統管理的資料空間起了個名字,叫棧;給程式設計師使用的空間,起了個名,叫堆。