資料結構基礎溫故 1 線性表(上)

2021-08-02 16:41:27 字數 4027 閱讀 6136

開篇:線性表是最簡單也是在程式設計當中使用最多的一種資料結構。例如,英文本母表(a,b,c,d...,z)就是乙個線性表,表中的每乙個英文本母都是乙個資料元素;又如,成績單也是乙個線性表,表中的每一行是乙個資料元素,每個資料元素又由學號、姓名、成績等資料項組成。

順序表和煉表作為線性表的兩種重要的存在形式,它們是堆疊、佇列、樹、圖等資料結構的實現基礎。

線性表:零個或多個資料元素的有限序列。線性表中的元素在位置上是有序的,類似於儲戶去銀行排隊取錢,人們依次排著隊,排在前面的先取,排在後面的則後取。這種位置上的有序性就是一種線性關係。由此可以看出:線性表的前後兩個元素存在一一對應關係

ps:需要注意的是,這種前後關係是邏輯意義上而非物理意義上的,就好比如果銀行做了改革,使用排隊機進行排隊,所有儲戶分散在銀行的各個角落,他們取錢的順序是根據儲戶從排隊機獲取的紙條上的號碼來決定的。

線性表的順序儲存結構是指【用一塊位址連續的儲存空間依次儲存線性表中的資料元素】。就好像我們剛剛提到的改革之前的銀行,需要在業務視窗前排隊等候辦理。由此可以看出:在順序表中,邏輯上相鄰的元素在物理上也是相鄰的

相比順序表需要預先占用一塊事先分配好的儲存空間,鍊錶就靈活一些。鍊錶中邏輯上相鄰的元素在物理上可以不相鄰。這就好像改革之後的銀行,人們辦理業務的順序是由手上的小紙條的號碼來決定。在某些特定場合,鍊錶的使用優先於順序表。

在日常程式設計中,在處理一組資料時,最常使用的資料型別就是陣列。它是線性表的順序儲存結構在程式語言中最直接的表現形式

陣列是最基礎也是訪問速度最快的一種集合型別,在.net中它是引用型別,也就是說它所需的記憶體空間會在託管堆上分配,一旦陣列被建立,其中的所有元素會被初始化為它們的預設值。

ps:另外需要注意的是,當陣列元素為值型別時,陣列物件存放的是值型別物件本身。而當元素為引用型別時,陣列物件存放的則是物件的引用(指標)。

(1)陣列元素為值型別時:

int arrint = new int[5];

arrint[2] = 5;

arrint[4] = 3;

下圖展示了上面的陣列arrint在記憶體(這裡如未說明都指在.net中的記憶體分配)中的分配形式,可以看到值型別陣列在被建立的同時就擁有了預設值0。

(2)陣列元素為引用型別時:

// system.windows.forms.control

control arrctrl = new control[5];

arrctrl[0] = new button();

arrctrl[3] = new label();

下圖則展示了上面的陣列arrctrl在記憶體中的分配,可以看到在託管堆中劃分了一塊能夠存放5個指標的記憶體區域,並且每個元素都被初始化為null。如果某個元素被賦值,那麼會存放乙個指向實際物件儲存區域的指標。

總結:陣列優點很多,缺點也很明顯:在實際程式設計中,無法動態改變集合的大小

如果需要動態地改變陣列所占用的記憶體空間的大小,則需要以陣列為基礎做進一步的抽象以實現這個功能。在c#中,arraylist被稱為動態陣列,它的儲存空間可以被動態地改變,同時還有新增、刪除元素的功能。

①add-新增新元素

// 在陣列末尾順序新增指定元素

public virtual int add(object value)

this._items[this._size] = value;

return this._size++;

}

可以看到,在新增新元素時會進行陣列容量的判斷,如果達到最大值則會呼叫方法動態調整陣列大小。

②removeat-移除指定元素

// 移除指定索引的元素

public virtual void removeat(int index)

// 插入位置後的元素向前移動一位

for (int i = index + 1; i < this._size; i++)

this._size--;

this._items[this._size] = null; // 最後一位空出的元素置為空

}

可以看到,在移除老元素時會進行大量的元素移動操作。這裡的arraylist採用的元素型別是object,所以最後將空出的元素置為null。

③ensurecapacity-動態調整陣列大小

// 動態調整陣列空間大小

private void ensurecapacity(int min)

// 調整陣列空間大小

this.capacity = num;}}

事實上,記憶體空間一旦分配是沒有辦法更改大小的。arraylist其實使用「搬家」的方法來實現這個功能的,即當房子住不下這麼多人的時候,那麼換乙個更大的新房子就行了。這裡,arraylist需要擴容時,會在記憶體空間中開闢一塊新區域,容量為原來的2倍,並把所有元素都複製到新記憶體空間中。

由於arraylist實際存放的是object物件(在.net中object是萬物之宗,即所有型別的父類),在進行訪問操作時需要進行大量的裝箱和拆箱操作(如果你不知道裝箱和拆箱,那麼請閱讀.net中六個重要的概念),降低程式效能。於是,從.net 2.0開始出現了泛型版本的list,它完美取代了arraylist。

listintnumlist = new list();

intnumlist.add(1);

intnumlist.add(2);

int num1 = intnumlist[0];

int num2 = intnumlist[1];

可以看到,在集合建立的時候就把元素型別限定為int型別,它是安全的,並且還避免了裝箱和拆箱操作。因此,在實際程式設計中一般都會使用list。

在.net中已經為我們提供了兩個強有力的順序表結構型別,我們可以通過reflector來檢視其具體實現。

通過檢視原始碼,其關鍵就在於ensurecapacity方法動態地調整陣列大小。

通過檢視原始碼,其關鍵就在於使用了泛型,而其他的方法如add、remove以及ensurecapacity都和arraylist沒有多大區別。

(1)程杰,《大話資料結構》

(2)陳廣,《資料結構(c#語言描述)》

(3)段恩澤,《資料結構(c#語言版)》

出處:

資料結構(1) 線性表(上)

1 文字定義 具有相同資料型別的n n 0 個資料元素的有限序列。2 相關術語 n表長 n 0空表 a1表頭元素 an表尾元素 除了表頭元素,線性表中每個元素有且僅有乙個直接前驅 除了表尾元素,線性表中每個元素有且僅有乙個直接後繼。3 代數表示 l a1,a2,an 4 特點 元素個數有限 元素具有...

資料結構線性表 上

鍊錶 鍊錶是一種有序的列表,鍊錶的內容通常是存貯於記憶體中分散的位置上。而鍊錶串聯的方式有兩種 0 1 2 3 4 5 6 7 8 9 isdata this aarray 6 8 1 39 不過這種鍊錶最大的缺點在於放入或刪除元素,常常要大量的移動其他元素,而且陣列的大小是固定的,缺乏使用彈性。2...

資料結構線性表1

include include include struct arr 定義了乙個資料型別,該資料型別的名字是struct arr void init arr struct arr parr,int length bool insert arr struct arr parr,int pos,int ...