c語言基礎 堆疊佇列鍊錶

2022-03-01 16:17:41 字數 2735 閱讀 6827

堆則是一種經過排序的樹形資料結構,常用來實現優先佇列,他的特點在於形成某種優先的結構。在計算機經常用到,比如優先佇列,或者是優先程序管理。

堆(也叫二叉堆)的性質:

1、任何乙個節點,都不大於他的父親節點。

2、必須是一顆完全二叉樹

在資料結構中,棧是一種可以實現「先進後出」(或者稱為「後進先出」)的儲存結構。假設給定棧 s=(a0,a1,…,an-1),則稱 a0 為棧底,an-1 為棧頂。進棧則按照 a0,a1,…,an-1 的順序進行進棧;而出棧的順序則需要反過來,按照「後存放的先取,先存放的後取」的原則進行,則 an-1 先退出棧,然後 an-2 才能夠退出,最後再退出 a0。

在實際程式設計中,可以通過兩種方式來實現:使用陣列的形式來實現棧,這種棧也稱為靜態棧;使用鍊錶的形式來實現棧,這種棧也稱為動態棧。

佇列是一種資料結構,其特點是先進先出,後進後出;佇列的儲存方式可以使用線性表進行儲存,也可以使用鍊錶進行儲存。

鍊錶是一種資料的儲存方式,其儲存的資料在記憶體中是不連續的,採用指針對資料進行訪問。鍊錶都有乙個頭指標,一般以head來表示,存放的是乙個位址。鍊錶中的節點分為兩類頭結點一般節點頭結點沒有資料域的。鍊錶中每個節點都分為兩部分,乙個資料域,乙個是指標域

在 c 語言中,記憶體分配方式不外乎有如下三種形式:

從靜態儲存區域分配:它是由編譯器自動分配和釋放的,即內存在程式編譯的時候就已經分配好,這塊內存在程式的整個執行期間都存在,直到整個程式執行結束時才被釋放,如全域性變數與 static 變數。

在棧上分配:它同樣也是由編譯器自動分配和釋放的,即在執行函式時,函式內區域性變數的儲存單元都可以在棧上建立,函式執行結束時這些儲存單元將被自動釋放。需要注意的是,棧記憶體分配運算內置於處理器的指令集中,它的執行效率一般很高,但是分配的記憶體容量有限。

從堆上分配:也被稱為動態記憶體分配,它是由程式設計師手動完成申請和釋放的。即程式在執行的時候由程式設計師使用記憶體分配函式(如 malloc 函式)來申請任意多少的記憶體,使用完之後再由程式設計師自己負責使用記憶體釋放函式(如 free 函式)來釋放記憶體。也就是說,動態記憶體的整個生存期是由程式設計師自己決定的,使用非常靈活。需要注意的是,如果在堆上分配了記憶體空間,就必須及時釋放它,否則將會導致執行的程式出現記憶體洩漏等錯誤。

1) 分配與釋放方式

棧記憶體是由編譯器自動分配與釋放的,它有兩種分配方式:靜態分配和動態分配。

而堆記憶體則不相同,它完全是由程式設計師手動申請與釋放的,程式在執行的時候由程式設計師使用記憶體分配函式(如 malloc 函式)來申請任意多少的記憶體,使用完再由程式設計師自己負責使用記憶體釋放函式(如 free 函式)釋放記憶體,如下面的**所示:

/*

分配堆記憶體

*/char *p1 = (char *)malloc(4

);… …

/*釋放堆記憶體

*/free

(p1);

p1=null;

對棧記憶體的自動釋放而言,雖然堆上的資料只要程式設計師不釋放空間就可以一直訪問,但是,如果一旦忘記了釋放堆記憶體,那麼將會造成記憶體洩漏,導致程式出現致命的潛在錯誤。

記憶體中的棧區主要用於分配區域性變數空間,處於相對較高的位址,其棧位址是向下增長的;而堆區則主要用於分配程式設計師申請的記憶體空間,堆位址是向上增長的。

2) 分配的碎片問題

對堆來說,頻繁分配和釋放(malloc / free)不同大小的堆空間勢必會造成記憶體空間的不連續,從而造成大量碎片,導致程式效率降低;而對棧來講,則不會存在這個問題。

3) 分配的效率

大家都知道,棧是機器系統提供的資料結構,計算機會在底層對棧提供支援,例如,分配專門的暫存器存放棧的位址,壓棧出棧都有專門的執行指令,這就決定了棧的效率比較高。一般而言,只要棧的剩餘空間大於所申請空間,系統就將為程式提供記憶體,否則將報異常提示棧溢位。

而堆則不同,它是由 c/c++ 函式庫提供的,它的機制也相當複雜。例如,為了分配一塊堆記憶體,首先應該知道作業系統有乙個記錄空閒記憶體位址的鍊錶,當系統收到程式的申請時,會遍歷該鍊錶,尋找第乙個空間大於所申請空間的堆節點,然後將該節點從空閒節點鍊錶中刪除,並將該節點的空間分配給程式。而對於大多數系統,會在這塊記憶體空間的首位址處記錄本次分配的大小,這樣,**中的 delete 語句才能正確釋放本記憶體空間。另外,由於找到的堆節點的大小不一定正好等於申請的大小,系統會自動將多餘的那部分重新放入空閒鍊錶中。很顯然,堆的分配效率比棧要低得多。

4) 申請的大小限制

由於作業系統是用鍊錶來儲存空閒記憶體位址(記憶體區域不連續)的,同時鍊錶的遍歷方向是由低位址向高位址進行的。因此,堆記憶體的申請大小受限於計算機系統中有效的虛擬記憶體。

而棧則不同,它是一塊連續的記憶體區域,其位址的增長方向是向下進行的,向記憶體位址減小的方向增長。由此可見,棧頂的位址和棧的最大容量一般都是由系統預先規定好的,如果申請的空間超過棧的剩餘空間時,將會提示溢位錯誤。由此可見,相對於堆,能夠從棧中獲得的空間相對較小。

5) 儲存的內容

對棧而言,一般用於存放函式的引數與區域性變數等。例如,在函式呼叫時,第乙個進棧的是(主函式中的)呼叫處的下一條指令(即函式呼叫語句的下一條可執行語句)的位址,然後是函式的各個引數,在大多數 c 編譯器中,引數是由右往左入棧的,最後是函式中的區域性變數(注意 static 變數是不入棧的)。

堆,棧,佇列,沒有鍊錶。

1 堆 什麼是堆?又該怎麼理解呢?堆通常是乙個可以被看做一棵樹的陣列物件。堆總是滿足下列性質 堆中某個節點的值總是不大於或不小於其父節點的值 堆總是一棵完全二叉樹。將根節點最大的堆叫做最大堆或大根堆,根節點最小的堆叫做最小堆或小根堆。常見的堆有二叉堆 斐波那契堆等。堆是在程式執行時,而不是在程式編譯...

陣列 鍊錶 堆疊 佇列

1 陣列 陣列是使用一塊連續的記憶體空間儲存資料,儲存的資料的個數在分配記憶體的時候就是確定的 訪問陣列中第 n 個資料的時間花費是 o 1 但是要在陣列中查詢乙個指定的資料則是 o n 陣列應用場景 1 資料比較少 2 經常做的運算是按序號訪問資料元素 3 構建線性表較穩定 4 陣列更容易實現,任...

陣列 鍊錶 堆疊和佇列

資料結構 是指相互之間存在一種或多種特定關係的資料元素的集合。聽起來是不是很抽象,簡單理解 資料結構就是描述物件間邏輯關係的學科。比如 佇列就是一種先進先出的邏輯結構,棧是一種先進後出的邏輯結構,家譜是一種樹形的邏輯結構!初學資料結構的時候很不理解為什麼有 棧 這個東西 佇列很容易理解 無論購物就餐...