數據結構與算法概述

程序與計算機工作的本質是對外界的信息抽象成數據然後通過一系列指令對數據進行操作,以期達到想要的目的。這裏有幾個概念。

1.數據:數據是個籠統的抽象名詞,數據是指所有能輸入到計算機並被計算機程序處理的符號的介質的總稱,是用於輸入計算機進行處理,具有一定意義的數字、字母、符號和模擬量等的通稱。

2.數據元素:數據元素是數據的基本單位,在計算機程序中通常作爲一個整體考慮。一個數據元素可以由若干個數據項組成。數據項是數據的不可分割的最小單位。有兩類數據元素:一類是不可分割的原子型數據元素。另一類是由多個款項構成的數據元素,其中每個款項被稱爲一個數據項

 

3.數據結構:這個東東至今沒有明確的定義,一般書上都是這樣簡單定義的:數據結構是一種或多種特定關係的數據元素的集合。一般認爲,一個數據結構是由數據元素依據某種邏輯聯繫組織起來的。對數據元素間邏輯關係的描述稱爲數據的邏輯結構;數據必須在計算機內存儲,數據的存儲結構是數據結構的實現形式,是其在計算機內的表示;此外討論一個數據結構必須同時討論在該類數據上執行的運算纔有意義。數據結構的內容包括數據元素本身以及數據之間的關係。可以從兩個方面來描述數據結構:

 

一是數據結構的物理/存儲結構:

數據結構在計算機中的表示(映像)稱爲數據的物理(存儲)結構。它包括數據元素的表示和關係的表示。數據元素之間的關係有兩種不同的表示方法:順序映象和 非順序映象,並由此得到兩種不同的存儲結構:順序存儲結構和鏈式存儲結構。順序存儲方法:它是把邏輯上相鄰的結點存儲在物理位置相鄰的存儲單元裏,結點間 的邏輯關係由存儲單元的鄰接關係來體現,由此得到的存儲表示稱爲順序存儲結構。順序存儲結構是一種最基本的存儲表示方法,通常藉助於程序設計語言中的數組 來實現。鏈接存儲方法:它不要求邏輯上相鄰的結點在物理位置上亦相鄰,結點間的邏輯關係是由附加的指針字段表示的。由此得到的存儲表示稱爲鏈式存儲結構,鏈式存儲結構通常藉助於程序設計語言中的指針類型來實現。索引存儲方法:除建立存儲結點信息外,還建立附加的索引表來標識結點的地址。散列存儲方法:就是根據結點的關鍵字直接計算出該結點的存儲地址。

 

一是邏輯結構:這是我們對數據結構進行分類的標準,依照數據元素之間的關係可分爲四種基本結構:(1)集合:結構中的數據元素之間沒有關係,只是同屬於一個結合而已,這是一種最鬆散的數據結構,跟數學中的結構概念基本一致(2)線性結構:這應該是一種使用最多的數據結構,在線性結構中數據元素之間有着一對一的順序關係(3)樹形結構:結構中的數據元素有着一對多的關係(4)圖狀或網狀結構:由上可知這肯定是數據元素之間有着多對多的關係。

4.算法:算法是對解決一個或一類問題的過程的描述。其本質是一個對過程的描述,至於描述方式可以有多種,這個描述可以是純文本的,可以是圖形的,可以是僞代碼,也可以用一種程序語言進行描述等等。

算法有5個重要的特性:(1)有窮性:算法是要解決問題的,如果一個算法在時間上無窮的這個算法肯定無法解決這個問題。(2)確定性:算法描述的每一步都無二義性。(3)可行性:即算法所描述的每一步都是在現有基礎上能夠實現的。(4)輸入:一個算法有零個或多個輸入。(5)一個算法有一個或多個輸出

一個好的算法應該具備以下幾個特點:

正確性,可讀性,健壯性,效率與低存儲性。

算法與數據結構的關係:算法與數據結構不是單獨存在的而是相互依存的,它們具有雙向選擇性,數據結構組織數據是爲了使用算法來對數據結構中的數據元素進行操作,而算法的目的就是爲了對數據元素進行運算。算法的設計取決於數據(邏輯)結構,而算法的實現依賴於採用的存儲結構。數據的存儲結構實質上是它的邏輯結構在計算機存儲器中的實現,爲了全面的反映一個 數據的邏輯結構,它在存儲器中的映象包括兩方面內容,即數據元素之間的信息和數據元素之間的關係。不同數據結構有其相應的若干運算。數據的運算是在數據的 邏輯結構上定義的操作算法,如檢索、插入、刪除、更新和排序等。數據的運算是數據結構的一個重要方面,討論任一種數據結構時都離不開開對該結構上的數據運算及其實現算法的討論。有時我們是對一個數據結構要進行一個運算從而選擇一個算法,比如對於順序存儲的線性表的查找,我們可以採取順序查找我們也可以採取折半查找等。而另一種情況是基於算法選擇數據結構,我們知道在一類數據上我們已知需要進行某種操作,比如字典自然最多的是查找操作而不是插入更新等操作。這是我們是要針對某中查找算法而選擇一種數據結構如針對哈希查找的哈希表。

計算機解決一個具體問題時,大致需要經過下列幾個步驟:首先要從具體問題中抽象出一個適當的數學模型,然後設計一個解此數學模型的算法 (Algorithm),最後編出程序、進行測試、調整直至得到最終解答。尋求數學模型的實質是分析問題,從中提取操作的對象,並找出這些操作對象之間含 有的關係,然後用數學的語言加以描述。計算機算法與數據的結構密切相關,算法無不依附於具體的數據結構,數據結構直接關係到算法的選擇和效率。運算是由計算機來完成,這就要設計相應的插入、刪除和修改的算法 。也就是說,數據結構還需要給出每種結構類型所定義的各種運算的算法。

下面是一些常見的數據結構

線性結構:線性結構中的數據元素都是不可再分的原子類型,可以分爲以下集中類型

(1)線性表:線性表是數據元素同屬於同種數據並且有先後的順序關係,第一數據元素只有後繼沒有前驅,最後一個數據元素只有前驅而沒有後繼,其餘中間的每個數據元素都有一個唯一的前驅和一個唯一的後繼。線性表可以在任意位置進行讀取刪除等操作。線性表在計算機可由兩種方式來實現,一種是順序存儲,一種自然是鏈式存儲。一講到順序存儲大家可能會想到數組,的確在具體的程序設計語言中順序存儲都是通過一維數組來實現的(至少我還沒發現不是用數組實現的),但順序存儲決不等同於數組,數組本身也是種數據結構。

(2)棧(Stack):不多說大家都懂,就是後進先出。棧十個死衚衕只有一個口進出,所以是後進先出的。棧其實是受限的線性表。線性表可以在任意位置進行操作,而棧只能在一頭進行操作。同樣棧可以通過順序和鏈式兩種存儲方法來實現。

(3)隊列(Queue):也無須多說,大家應該都排過隊的,隊列是有兩頭口子的衚衕(不是死衚衕了)不過一頭只准進另一頭只准出,所以就是先進來的就可以先出去了。隊列也可以用兩種存儲方式實現,鏈式存儲方式和順序存儲方式,只不過順序存儲方式與一般不同的是把一連續的地址的存儲單元採用序號取模的方式循環使用,個這種順序方式實現的隊列又叫循環隊列。隊列裏面又可以分爲:優先隊列,雙端隊列,受限雙端隊列等顧名思義就不解釋了。

(4)串:即字符串。不知怎麼的把字符串也搞成了一個數據結構。串應該就是一種數據元素爲字符的線性表,可能是線性表中操作哦的多半是單個數據元素,而串中是把多個數據元素當成一個整體來操作。同樣也可以採取順序和鏈式兩種存儲方式。

(1)數組(Array):上述集中線性結構中的數 據元素都是不可再分的原子類型。數組看似和線性表很像但數組以及下面要講的廣義表的數據元素本身是一種數據結構如線性結果,棧等,數組可看成是拓展的線性結構,數組的每一個數據元素都是 一個等長的同一類型的線性表時就成了矩陣。數組自然是採用順序存儲方式,不知道有沒有采用鏈式的。

(2)廣義表:同樣廣義表可看成是拓展的線性結構。線性表被定義爲一個有限的序列 (a1,a2,a3,…,an)其中ai被限定爲是單個數據元素。廣義表是n個數據元素d1,d2,d3,…,dn的有限序列,但不同的是,廣義表中的 di 則既可以是單個元素,還可以是一個廣義表,通常記作:GL=(d1,d2,d3,…,dn)。GL是廣義表的名字,通常廣義表的名字用大寫字母表示。n是 廣義表的長度。若其中di是一個廣義表,則稱di是廣義表GL的子表。在廣義表GL中,d1是廣義表GL的表頭,而廣義表GL其餘部分組成的表 (d2,d3,…,dn)稱爲廣義表的表尾。由此可見廣義表的定義是遞歸定義的。因爲在定義廣義表時,又使用了廣義表的概念。廣義表通常採用鏈式存儲結 構。

非線性數據結構:


(3)樹(Tree):

樹(tree)是包含n(n>0)個結點的有窮集合K,且在K中定義了一個關係N,N滿足 以下條件:

(1)有且僅有一個結點 k0,他對於關係N來說沒有前驅,稱K0爲樹的根結點。簡稱爲根(root)。   

(2)除K0外,k中的每個結點,對於關係N來說有且僅有一個前驅。   

(3)K中各結點,對關係N來說可以有m個後繼(m>=0)。   

若n>1,除根結點之外的其餘數據元素被分爲m(m>0)個互不相交的結合T1,T2,……Tm,其中每一個集合Ti(1<=i<=m)本身也是一棵樹。

樹   T1,T2,……Tm稱作根結點的子樹(sub tree)。   

樹也就可以這樣定義:樹是有根結點和若干顆子樹構成的。------(上一段來自高林,《數據結構(C++)》,北京 清華大學出版社)   

樹是由一個集合以及在該集合上定義的一種關係構成的。集合中的元素稱爲樹的結點,所定義的關係稱爲父子關係。父子關係在樹的結點之間建立了一個層次結構。在這種層次結構中有一個結點具有特殊的地位,這個結點稱爲該樹的根結點,或簡稱爲樹根。我們可以形式地給出樹的遞歸定義如下:   

單個結點是一棵樹,樹根就是該結點本身。   

設T1,T2,..,Tk是樹,它們的根結點分別爲n1,n2,..,nk。用一個新結點n作 爲n1,n2,..,nk的父親,則得到一棵新樹,結點n就是新樹的根。我們稱n1,n2,..,nk爲一組兄弟結點,它們都是結點n的兒子結點。我們還 稱n1,n2,..,nk爲結點n的子樹。   

空集合也是樹,稱爲空樹。空樹中沒有結點。

樹是圖的一種特例,無向不循環圖即爲樹。

樹可細分很多種:有二叉樹,平衡二叉樹,紅黑樹,B樹等等

(4)堆 (Heap):

  在計算機科學中,堆是一種特殊的樹形數據結構,每個結點都有一個值。通常我們所說的堆的數據結構,是指二叉堆。堆的特點是根結點的值最小(或最大),且根結點的兩個子樹也是一個堆。

(5)圖(Graph):相比較起來圖是一種相當複雜的數據結構

圖的定義如下:

圖是由結點的有窮集合V和邊的集合E組成。其中,爲了與樹形結構加以區別,在圖結構中常常將結點稱爲頂點,邊是頂點的有序偶對,若兩個頂點之間存在一條邊,就表示這兩個頂點具有相鄰關係。   

在上面兩個圖結構中,一個是有向圖,即每條邊都有方向,另一個是無向圖,即每條邊都沒有方向。   

在有向圖中,通常將邊稱作弧,含箭頭的一端稱爲弧頭,另一端稱爲弧尾,記作<vi,vj>,它表示從頂點vi到頂點vj有一條邊。   

若有向圖中有n個頂點,則最多有n(n-1)條弧,我們又將具有n(n-1)條弧的有向圖稱作有向完全圖。以頂點v爲弧尾的弧的數目稱作頂點v的出度, 以頂點v爲弧頭的弧的數目稱作頂點v的入度。在無向圖中,邊記作(vi,vj),它蘊涵着存在< vi,vj>和<vj,vi>兩條弧。若無向圖中有n個頂點,則最多有n(n-1)/2條弧,我們又將具有n(n-1)/2條弧的無向 圖稱作無向完全圖。與頂點v相關的邊的條數稱作頂點v的度。   

路徑長度是指路徑上邊或弧的數目。   

若第一個頂點和最後一個頂點相同,則這條路徑是一條迴路。   

若路徑中頂點沒有重複出現,則稱這條路徑爲簡單路徑。   

在無向圖中,如果從頂點vi到頂點vj有路徑,則稱vi和vj連通。如果圖中任意兩個頂點之間都連通,則稱該圖爲連通圖,否則,將其中的極大連通子圖稱爲連通分量。   

在有向圖中,如果對於每一對頂點vi和vj,從vi到vj和從vj到vi都有路徑,則稱該圖爲強連通圖;否則,將其中的極大連通子圖稱爲強連通分量。

圖的基本操作

(1)創建一個圖結構 CreateGraph(G)   

(2)檢索給定頂點 LocateVex(G,elem)   

(3)獲取圖中某個頂點 GetVex(G,v)   

(4)爲圖中頂點賦值 PutVex(G,v,value)   

(5)返回第一個鄰接點 FirstAdjVex(G,v)   

(6)返回下一個鄰接點 NextAdjVex(G,v,w)   

(7)插入一個頂點 InsertVex(G,v)   

(8)刪除一個頂點 DeleteVex(G,v)   

(9)插入一條邊 InsertEdge(G,v,w)   

(10)刪除一條邊 DeleteEdge(G,v,w)   

(11)遍歷圖 Traverse(G,v)

圖的存儲結構:

1.數組(鄰接矩陣)存儲表示(有向或無向):用兩個數組分別存儲數據元素(定點)的信息和數據元素之間的關係(邊或弧)的信息

2.鄰接表:是圖的一種鏈式存儲結構。在圖的每個頂點建立一個單鏈表(n個頂點建立n個單鏈表),第i個單鏈表中的結點包含頂點Vi的所有鄰接頂點。又稱鏈接表。

補充: 1.在有向圖的鄰接表中不易找到指向該頂點的弧 2.在有向圖的鄰接表中,對每個頂點,鏈接的是指向該頂點的弧。

3.有向圖的十字鏈表:十字鏈表(Orthogonal List)是有向圖的另一種鏈式存儲結構。可以看成是將有向圖的鄰接表和逆鄰接表結合起來得到的一種鏈表。在十字鏈表中,對應於有向圖中每一條弧都有一個結點,對應於每個定頂點也有一個結點。十字鏈表之於有向圖,類似於鄰接表之於無向圖。用鏈表模擬矩陣的行(或者列,這可以根據個人喜好來定),然後,再構造代表列的鏈表,將每一行中的元素節點插入到對應的列中去。十字鏈表的邏輯結構就像是 一個圍棋盤(沒見過,你就想一下蒼蠅拍,這個總見過吧),而非零元就好像是在棋盤上放的棋子,總共佔的空間就是,確定那些線的表頭節點和那些棋子代表的非 零元節點。最後,我們用一個指針指向這個棋盤,這個指針就代表了這個稀疏矩陣。

4.無向圖的鄰接多重鏈表:鄰接多重表是無向圖的另一種鏈式存儲結構。

圖的遍歷:

1.圖的深度優先遍歷:深度優先搜索法是樹的先根遍歷的推廣,它的基本思想是:從圖G的某個頂點v0出發,訪問v0,然後選擇一個與v0相鄰且沒被訪問過的頂點vi訪問,再從 vi出發選擇一個與vi相鄰且未被訪問的頂點vj進行訪問,依次繼續。如果當前被訪問過的頂點的所有鄰接頂點都已被訪問,則退回到已被訪問的頂點序列中最 後一個擁有未被訪問的相鄰頂點的頂點w,從w出發按同樣的方法向前遍歷,直到圖中所有頂點都被訪問

2.圖的寬度優先遍歷:圖的廣度優先搜索是 樹的按層次遍歷的推廣,它的基本思想是:首先訪問初始點vi,並將其標記爲已訪問過,接着訪問vi的所有未被訪問過的鄰接點vi1,vi2, …, vi t,並均標記已訪問過,然後再按照vi1,vi2, …, vi t的次序,訪問每一個頂點的所有未被訪問過的鄰接點,並均標記爲已訪問過,依次類推,直到圖中所有和初始點vi有路徑相通的頂點都被訪問過爲止。

 (6)散列表 (Hash):

  若結構中存在關鍵字和K相等的記錄,則必定在f(K)的存儲位置上。由此,不需比較便可直接取得所查記錄。稱這個對應關係f爲散列函數(Hash function),按這個思想建立的表爲散列表。

常用的構造散列函數的方法

  散列函數能使對一個數據序列的訪問過程更加迅速有效,通過散列函數,數據元素將被更快地定位:   

1. 直接尋址法:取關鍵字或關鍵字的某個線性函數值爲散列地址。即H(key)=key或H(key) = a•key + b,其中a和b爲常數(這種散列函數叫做自身函數)   

2. 數字分析法   

3. 平方取中法   

4. 摺疊法   

5. 隨機數法   

6. 除留餘數法:取關鍵字被某個不大於散列表表長m的數p除後所得的餘數爲散列地址。即 H(key) = key MOD p, p<=m。不僅可以對關鍵字直接取模,也可在摺疊、平方取中等運算之後取模。對p的選擇很重要,一般取素數或m,若p選的不好,容易產生同義詞。

處理衝突的方法

  1. 開放尋址法:Hi=(H(key) + di) MOD m, i=1,2,…, k(k<=m-1),其中H(key)爲散列函數,m爲散列表長,di爲增量序列,可有下列三種取法:   

(1). di=1,2,3,…, m-1,稱線性探測再散列;   

(2). di=1^2, (-1)^2, 2^2,(-2)^2, (3)^2, …, ±(k)^2,(k<=m/2)稱二次探測再散列;   

(3). di=僞隨機數序列,稱僞隨機探測再散列。 ==   2. 再散列法:Hi=RHi(key), i=1,2,…,k RHi均是不同的散列函數,即在同義詞產生地址衝突時計算另一個散列函數地址,直到衝突不再發生,這種方法不易產生“聚集”,但增加了計算時間。   

3. 鏈地址法(拉鍊法)   

4. 建立一個公共溢出區

以上部分概念來自百度百科

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章