1. 程式人生 > >資料結構(C#版)筆記(一)

資料結構(C#版)筆記(一)

1.資料結構邏輯結構(Data Structure) 資料結構是相互之間存在一種或多種特定關係的資料元素的集合。在任何問 題中,資料元素之間都不是孤立的,而是存在著一定的關係,這種關係稱為結構 (Structure)。根據資料元素之間關係的不同特性,通常有 4 類基本資料結構: (1) 集合(Set):該結構中的資料元素除了存在“同屬於一個集 合”的關係外,不存在任何其它關係。 (2) 線性結構(Linear Structure):該結構中的資料元素存在著一對一的關係。 (3) 樹形結構(Tree Structure):該結構中的資料元素存在著一對多的關係。 (4) 圖狀結構(Graphic Structure):該結構中的資料元素存在著多對多的關係。

2.資料的儲存結構(物理結構) 包括順序儲存結構和鏈式儲存結構兩種

3.演算法的特性 一個演算法應該具備以下 5 個特性: 1、有窮性(Finity):一個演算法總是在執行有窮步之後結束,即演算法的執行時間是 有限的。 2、 確定性(Unambiguousness):演算法的每一個步驟都必須有確切的含義,即無二 義,並且對於相同的輸入只能有相同的輸出。 3、 輸入(Input):一個演算法具有零個或多個輸入。它即是在演算法開始之前給出的 量。這些輸入是某資料結構中的資料物件。 4、 輸出(Output):一個演算法具有一個或多個輸出,並且這些輸出與輸入之間存 在著某種特定的關係。 5、 能行性(realizability:演算法中的每一步都可以通過已經實現的基本運算的有 限次執行來實現。

4.評價演算法優劣的主要標準 1、正確性(Correctness)。演算法的執行結果應當滿足預先規定的功能和效能的要求, 這是評價一個演算法的最重要也是最基本的標準。演算法的正確性還包括對於輸入、 輸出處理的明確而無歧義的描述。 2、 可讀性(Readability)。演算法主要是為了人閱讀和交流,其次才是機器的執行。 所以,一個演算法應當思路清晰、層次分明、簡單明瞭、易讀易懂。即使演算法已轉 變成機器可執行的程式,也需要考慮人能較好地閱讀理解。同時,一個可讀性強 的演算法也有助於對演算法中隱藏錯誤的排除和演算法的移植。 3、 健壯性(Robustness)。一個演算法應該具有很強的容錯能力,當輸入不合法的數 據時,演算法應當能做適當的處理,使得不至於引起嚴重的後果。健壯性要求表明 演算法要全面細緻地考慮所有可能出現的邊界情況和異常情況,並對這些邊界情況 和異常情況做出妥善的處理,儘可能使演算法沒有意外的情況發生。 4、 執行時間(Running Time)。執行時間是指演算法在計算機上執行所花費的時間, 它等於演算法中每條語句執行時間的總和。對於同一個問題如果有多個演算法可供選 擇,應儘可能選擇執行時間短的演算法。一般來說,執行時間越短,效能越好。 5、 佔用空間(Storage Space)。佔用空間是指演算法在計算機上儲存所佔用的儲存空 間,包括儲存演算法本身所佔用的儲存空間、演算法的輸入及輸出資料所佔用的儲存 空間和演算法在執行過程中臨時佔用的儲存空間。算法佔用的儲存空間是指演算法執 行過程中所需要的最大儲存空間,對於一個問題如果有多個演算法可供選擇,應盡 可能選擇儲存量需求低的演算法。實際上,演算法的時間效率和空間效率經常是一對 矛盾,相互抵觸。我們要根據問題的實際需要進行靈活的處理,有時需要犧牲空 間來換取時間,有時需要犧牲時間來換取空間。

5.階乘函式 階乘函式 n!是指從 1 到 n 之間所有整數的連乘

6.遞迴 如果一個演算法直接呼叫自己或間接地呼叫自己,就稱這個演算法是遞迴

7.泛型的概念 通過泛型可以定義型別安全的並且對效能或工作效率無損害的類。泛型類的 定義如下: public class className<T> 它在普通類的定義後面增加了一個型別引數 T,該引數用一對分隔符“ <>” 括起來。型別引數表示對資料型別的抽象,可以把它理解為一個替換標記或者是 一個佔位符。它在類的定義程式碼中的每次出現都表示一個非特定的資料型別

8.泛型的好處 泛型使程式碼可以重用,型別和內部資料可以在不導致程式碼膨脹的情況下更 改,而不管是值型別還是引用型別。可以一次性地開發、測試和部署程式碼,通過 任何型別(包括將來的型別)來重用它,並且全部具有編譯器支援和型別安全。 因為泛型程式碼不會強行對值型別進行裝箱和取消裝箱,或者對引用型別進行向下 強制型別轉換,所以效能得到顯著提高。

9.線性表的定義 線性表(List)是由 n(n≥0)個相同型別的資料元素構成的有限序列 在計算機內,儲存線性表最簡單、最自然的方式,就是把表中的元素一個接 一個地放進順序的儲存單元,這就是線性表的順序儲存(Sequence Storage)。線性 表的順序儲存是指在記憶體中用一塊地址連續的空間依次存放線性表的資料元素, 用這種方式儲存的線性表叫順序表(Sequence List)

10.倒置方法在順序表類 SeqList 中的實現

public class SeqList<T> : IListDS<T> {

public void Reverse()
{
T tmp = Default(T);
int len = GetLength();
for (int i = 0; i<= en/2; ++i)
{
tmp = data[i];
data[i] = data[len - i];
data[len - i] = tmp;
}
}
}

11.從表中刪除相同資料元素的演算法的 C#實現如下: public SeqList<int> Purge(SeqList<int> La) { SeqList<int> Lb = new SeqList<int>(La.Maxsize); //將a表中的第1個數據元素賦給b表 Lb.Append(La[0]); //依次處理a表中的資料元素 for (int i=1; i<=La.GetLength()-1; ++i) { int j = 0; //檢視b表中有無與a表中相同的資料元素 for (j = 0; j<=Lb.GetLength()-1; ++j) { //有相同的資料元素 if (La[i].CompareTo(Lb[j]) == 0) { break; } } //沒有相同的資料元素,將a表中的資料元素附加到b表的末尾。 if(j>Lb.GetLength()-1) { Lb.Append(La[i]); } } return Lb; } 演算法的時間複雜度是 O(m+n), m 是 La 的表長, n 是 Lb 的表長

12.單鏈表 順序表是用地址連續的儲存單元順序儲存線性表中的各個資料元素,邏輯上 相鄰的資料元素在物理位置上也相鄰。因此,在順序表中查詢任何一個位置上的 資料元素非常方便,這是順序儲存的優點。但是,在對順序表進行插入和刪除時, 需要通過移動資料元素來實現,影響了執行效率。本節介紹線性表的另外一種存 儲結構——鏈式儲存(Linked Storage),這樣的線性表叫連結串列(Linked List)。連結串列不 要求邏輯上相鄰的資料元素在物理儲存位置上也相鄰,因此,在對連結串列進行插入 和刪除時不需要移動資料元素,但同時也失去了順序表可隨機儲存的優點。

13.單鏈表定義 在儲存資料元素時,除 了儲存資料元素本身的資訊外,還要儲存與它相鄰的資料元素的儲存地址資訊。 這兩部分資訊組成該資料元素的儲存映像(Image),稱為結點(Node)。把儲存據元 素本身資訊的域叫結點的資料域(Data Domain),把儲存與它相鄰的資料元素的存 儲地址資訊的域叫結點的引用域(Reference Domain)。 如果結點的引用域只儲存該結點直接後繼結點的儲存地址,則該連結串列叫單鏈 表(Singly Linked List)。把該引用域叫 next。

14.單鏈表的倒置 解決辦法是依次取單鏈表中的每個結點插入到新連結串列中去。並且, 為了節省記憶體資源,把原連結串列的頭結點作為新連結串列的頭結點。 儲存整數的單鏈表的倒置的演算法實現如下:

public void ReversLinkList(LinkList<int> H)
{
Node<int> p = H.Next;
Node<int> q = new Node<int>();
H.Next = null;
while (p != null)
{
q = p;
p = p.Next;
q.Next = H.Next;
H.Next = q;
}
}

將正在訪問的節點插入到連結串列頭部。

15.例子:有資料型別為整型的單鏈表 Ha 和 Hb,其資料元素均按從小到大的升 序排列,編寫一個演算法將它們合併成一個表 Hc,要求 Hc 中結點的值也是升序排列。 演算法思路:把 Ha 的頭結點作為 Hc 的頭結點,依次掃描 Ha 和 Hb 的結點, 比較 Ha 和 Hb 當前結點資料域的值,將較小值的結點附加到 Hc 的末尾,如此直 到一個單鏈表被掃描完,然後將未完的那個單鏈表中餘下的結點附加到 Hc 的末 尾即可。

將兩表合併成一表的演算法實現如下:

public LinkList<int> Merge(Linklist<int> Ha, LinkList<int> Hb)
{
LinkList<int> Hc = new LinkList<int>();
Node<int> p = Ha.Next;
Node<int> q = Hb.Next;
Node<int> s = Node<int>();
Hc = Ha;
Hc.Next = null;
while (p != null && q != null)
{
if (p.Data < q.Data)
{
s = p;
p = p.Next;
}
else
{
s = q;
q = q.Next;
}
Hc.Append(s);
}
if (p == null)
{
p = q;
}

while (p != null)
{
s = p;
p = p.Next;
Hc.Append(s);
}
return Hc;
}