線性表(三) 鍊錶

2021-08-28 07:35:09 字數 3682 閱讀 1364

鍊錶是由一系列稱為表的結點的物件組成的。它可以動態分配儲存空間,解決了陣列的靜態分配儲存空間的一些弊端。在一些應用中,常採用動態分配靜態化的思想為鍊錶分配儲存空間,這種技術稱為「儲存池」。常見的鍊錶型別有:單鏈表、雙鏈表、迴圈鍊錶,本文將對三者做詳細介紹。

實現乙個鍊錶首先需要定義鍊錶的「零件」——link類

template  class link 

link

(link* nextval =

null

)}

此為單鏈表的link類:包含乙個儲存元素值的element域和乙個儲存表中下一結點指標的next域。它的建構函式有兩種形式,乙個函式有初始化元素的值,另乙個則沒有。

注:看上去link類的資料成員宣告為公有違反了封裝原則,實際上link類作為鍊錶(或棧、佇列)實現的乙個私有類來實現,因此對程式其他部分是不可見的。

下面給出單鏈錶類llist的實現

template  class llist : public list

void

removeall()

}public:

llist

(int size = defaultsize)

~llist()

void

print()

const

;void

clear()

// 關鍵函式實現

void

insert

(const e& it)

void

(const e& it)

e remove()

void

movetostart()

void

movetoend()

void

prev()

//前驅

void

movetopos

(int pos)

void

next()

//後繼

// 鍊錶當前相關引數

intlength()

const

intcurrpost()

const

const e&

getvalue()

const

//return current element

};

注:為了操作的便利性以及考慮對特殊情況的一致性處理,本例的設計考慮了如下兩個策略:

i) 讓curr指標指向當前元素的前乙個元素

ii) 增加特殊的表頭結點cnt存放線性表的長度,對鍊錶的每個修改操作都要更新它們的值。

類llist包含兩個私有成員函式:init和removeall。llist的建構函式、析構函式和clear函式都用到了這兩個函式。

請額外注意體會insertremove的實現。

i) 在鍊錶的當前位置插入乙個新元素包括三個步驟。首先,要建立乙個新的結點;其次,新結點的next域要指向當前結點;最後,重定向curr的next域至新結點。

ii) 從鍊錶刪除乙個元素必須小心。不要「丟失」被刪除結點的記憶體。此記憶體應該返回給儲存器。因此,首先將要刪除的指標指向臨時指標ltemp,然後呼叫delete函式釋放被刪除結點占用的記憶體。

下面給出乙個小結論幫助記憶:修改curr,使用temp指標作為輔助量;修改鍊錶元素,使用curr指標作為輔助量。(分別參考prev和clear函式)

。類似於單鏈表,為了去除一些特殊情況以及簡化操作,雙鏈表的實現使用了不包含任何資料資訊的頭結點和尾結點。它們在雙鏈表初始化時被建立,並用head和tail指標分別指向。

雙鏈表link類:

template  class link 

link

( link* prevp =

null

, link* nextp =

null

)}

雙鏈表關鍵操作:

void

insert

(const e& it)

template

void llist::

(const e& it)

template

e llist::

remove()

template

void llist::

prev()

這裡再給出乙個小結論:雙鏈表增刪操作中,總要重定向原表中兩個指標,且總是先修改"易丟失"的結點的指標(即沒被curr指向的結點),在本示例**中可以直觀的體現為修改的先長後短原則(如下圖)

注意,此結論同樣適用於單鏈表的增刪操作。

思考

考慮一種基於異或的節省空間的方法,用來消除雙鏈表額外的空間需求,儘管它會使實現變得複雜,執行速度稍微減慢。(這種方法是乙個時空權衡的例子)

分析:由 (l^r)^r = l, (l^r)^l = r 可知,給出兩個值,並將它們異或,則其中任何乙個值都可以由另外乙個值與它們異或後的結果再異或而得到。因此,雙鏈表可以通過在乙個指標域中儲存兩個指標值的異或結果來實現。這樣一來,乙個結點的指標值可以由它的前驅結點指標值與該前驅的next域異或得到。因此,只要分解鏈結域就能順著鍊錶走下去,像拉開拉鍊一樣。

注:這種方法的原理值得注意,計算機圖形學中廣泛利用了這一原理。(把螢幕上乙個區域與乙個矩形影象異或,使該區域的影象高亮,再次與矩形影象異或使之復原)

迴圈鍊錶是指煉表中最後那個鏈結點的指標域存放指向鍊錶最前面那個結點的指標,整個鍊錶形成乙個環。

只要給出任何乙個結點的位置,則由此出發就可以訪問表中其他所有結點。

template

void llist::

llist

(const

int sz)

template

void llist::

clear()

tail = curr = head->next = head;

}template

void llist::

(const e& it)

template

void llist::

insert

(const e& it)

template

void llist::

next()

template

void llist::

prev()

通過三種鍊錶的學習,我們可以發現,鍊錶的組成就是乙個個link物件,鍊錶的操作無非為增刪查改,**編寫過程中的需注意的特殊情況主要有是否為空、是否為首尾,刪除時注意記憶體管理防止記憶體洩露。

線性表 鍊錶

線性表的adt list.h 線性表的c 抽象類宣告 templateclass list 單鏈表節點的定義 link.h 單鏈表節點類的定義 template class link link link nextval null 鍊錶的實現宣告 成員函式的是實現 鍊錶的實現宣告 include st...

線性表 鍊錶

include include typedef int elemtype typedef struct node lnode,linklist linklist createlinklist1 頭插法 linklist createlinklist2 尾插法 void lengthlinklist ...

線性表,鍊錶

資料的儲存結構分為鏈式儲存結構,線性儲存結構。不管什麼型別的資料結構,都會以這兩種儲存方式在計算機中儲存。線性儲存結構就是開闢一段連續的記憶體 記憶體大小已經確定 將資料儲存在這段連續記憶體中,這種儲存結構的優點是可以快速地取出元素,時間複雜度為o 1 缺點是插入和刪除需要移動大量的元素,時間複雜度...