一、數據
數據(Data)是信息的載體,它能夠被計算機識別、存儲和加工處理。它是計算機程序加工的原料,應用程序處理各種各樣的數據。
計算機科學中,所謂數據就是計算機加工處理的對象,它可以是數值數據,也可以是非數值數據。數值數據是一些整數、實數或復數,主要用於工程計算、科學計算和商務處理等;
非數值數據包括字符、文字、圖形、圖像、語音等。
二、數據元素
數據元素(Data Element)是數據的基本單位。在不同的條件下,數據元素又可稱為元素、結點、頂點、記錄等。
例如,學生信息檢索系統中學生信息表中的一個記錄、八皇后問題中狀態樹的一個狀態、教學計划編排問題中的一個頂點等,都被稱為一個數據元素。
有時,一個數據元素可由若干個數據項(Data Item)組成,例如,學籍管理系統中學生信息表的每一個數據元素就是一個學生記錄。它包括學生的學號、姓名、性別、籍貫、出生年月、成績等數據項。
這些數據項可以分為兩種:
一種叫做初等項,如學生的性別、籍貫等,這些數據項是在數據處理時不能再分割的最小單位;
另一種叫做組合項,如學生的成績,它可以再划分為數學、物理、化學等更小的項。通常,在解決實際應用問題時是把每個學生記錄當作一個基本單位進行訪問和處理的。
三、數據對象
數據對象(Data Object)或數據元素類(Data Element Class)是具有相同性質的數據元素的集合。
在某個具體問題中,數據元素都具有相同的性質(元素值不一定相等),屬於同一數據對象(數據元素類),數據元素是數據元素類的一個實例。例如,在交通咨詢系統的交通網中,所有的頂點是一個數據元素類,頂點A 和頂點B 各自代表一個城市,是該數據元素類中的兩個實例,其數據元素的值分別為A 和B。
四、數據結構
數據結構研究的三個方面:
(1)數據集合中各數據元素之間所固有的邏輯關系,即數據的邏輯結構;
(2)在對數據進行處理時,各數據元素在計算機中的存儲關系,即數據的存儲結構;
(3)對各種數據結構進行的運算。
數據結構是指相互有關聯的數據元素的集合。
數據的邏輯結構包含:
(1)表示數據元素的信息;
(2)表示各數據元素之間的前后件關系。
數據的存儲結構有順序、鏈接、索引等。
線性結構條件:
(1)有且只有一個根結點;
(2)每一個結點最多有一個前件,也最多有一個后件。
非線性結構:不滿足線性結構條件的數據結構。
五、數據的邏輯結構
數據的邏輯結構有以下兩大類:
線性結構:有且僅有一個開始結點和一個終端結點,且所有結點都最多只有一個直接前驅和一個直接后繼。
線性表是一個典型的線性結構。棧、隊列、串、數組等都是線性結構。
非線性結構:在該類結構中至少存在一個數據元素,它具有兩個或者兩個以上的前驅或后繼。
如樹和二叉樹集合結構和多維數組、廣義表、圖、堆等數據結構都是非線性結構。
六、基本的數據結構
集合結構:數據元素的有限集合。數據元素之間除了“屬於同一個集合”的關系之外沒有其他關系。
線性結構:數據元素的有序集合。數據元素之間形成一對一的關系。
樹型結構:樹是層次數據結構,樹中數據元素之間存在一對多的關系。
圖狀結構:圖中數據元素之間的關系是多對多的。
七、數據的存儲結構
數據的存儲結構可采用順序存儲或鏈式存儲的方法。
順序存儲方法是把邏輯上相鄰的元素存儲在物理位置相鄰的存儲單元中,由此得到的存儲表示稱為順序存儲結構。順序存儲結構是一種最基本的存儲表示方法,通常借助於程序設計語言中的數組來實現。
鏈式存儲方法對邏輯上相鄰的元素不要求其物理位置相鄰,元素間的邏輯關系通過附設的指針字段來表示,由此得到的存儲表示稱為鏈式存儲結構,鏈式存儲結構通常借助於程序設計語言中的指針類型來實現。
除了通常采用的順序存儲方法和鏈式存儲方法外,有時為了查找的方便還采用索引存儲方法和散列存儲方法。
八、算法
算法:是指解題方案的准確而完整的描述。
算法不等於程序,也不等計算機方法,程序的編制不可能優於算法的設計。
算法的基本特征:是一組嚴謹地定義運算順序的規則,每一個規則都是有效的,是明確的,此順序將在有限的次數下終止。特征包括:
(1)可行性;
(2)確定性,算法中每一步驟都必須有明確定義,不充許有模棱兩可的解釋,不允許有多義性;
(3)有窮性,算法必須能在有限的時間內做完,即能在執行有限個步驟后終止,包括合理的執行時間的含義;
(4)擁有足夠的情報。
算法的基本要素:一是對數據對象的運算和操作;二是算法的控制結構。
指令系統:一個計算機系統能執行的所有指令的集合。
基本運算和操作包括:算術運算、邏輯運算、關系運算、數據傳輸。
算法的控制結構:順序結構、選擇結構、循環結構。
算法基本設計方法:列舉法、歸納法、遞推、遞歸、減斗遞推技術、回溯法。
算法復雜度:算法時間復雜度和算法空間復雜度。
算法時間復雜度是指執行算法所需要的計算工作量。
算法空間復雜度是指執行這個算法所需要的內存空間。
時間復雜度
定義:設問題的規模為n,把一個算法的時間耗費T(n)稱為該算法的時間復雜度,它是問題規模為n的函數。
常用的算法的時間復雜度的順序:(比較時只看最高次冪)
for ( i = 1 , i < = 10 , i++ ) x=x+c; =>O(1)
for ( i = 1 , i < = n , i++ ) x=x+n; =>O(n)
多嵌套一個for,則為 =>O(n^2) 以此類推
真題難點:i = 1,while(i < = n)
i = i * 3;=>O(log3^n)
i = i * 2;=>O(log2^n) 以此類推
九、線性表
線性表由一組數據元素構成,數據元素的位置只取決於自己的序號,元素之間的相對位置是線性的。
在復雜線性表中,由若干項數據元素組成的數據元素稱為記錄,而由多個記錄構成的線性表又稱為文件。
非空線性表的結構特征:
(1)且只有一個根結點a1,它無前件;
(2)有且只有一個終端結點an,它無后件;
(3)除根結點與終端結點外,其他所有結點有且只有一個前件,也有且只有一個后件。結點個數n稱為線性表的長度,當n=0時,稱為空表。
線性表的順序存儲結構具有以下兩個基本特點:
(1)線性表中所有元素的所占的存儲空間是連續的;
(2)線性表中各數據元素在存儲空間中是按邏輯順序依次存放的。
ai的存儲地址為:adr(ai)=adr(a1)+(i-1)k,,adr(a1)為第一個元素的地址,k代表每個元素占的字節數。
順序表的運算:插入、刪除。
十、線性鏈表
數據結構中的每一個結點對應於一個存儲單元,這種存儲單元稱為存儲結點,簡稱結點。
結點由兩部分組成:(1)用於存儲數據元素值,稱為數據域;(2)用於存放指針,稱為指針域,用於指向前一個或后一個結點。
在鏈式存儲結構中,存儲數據結構的存儲空間可以不連續,各數據結點的存儲順序與數據元素之間的邏輯關系可以不一致,而數據元素之間的邏輯關系是由指針域來確定的。
鏈式存儲方式即可用於表示線性結構,也可用於表示非線性結構。
線性鏈表,head稱為頭指針,head=null(或0)稱為空表,如果是兩指針:左指針(llink)指向前件結點,右指針(rlink)指向后件結點。
線性鏈表的基本運算:查找、插入、刪除。
單鏈表
指針域中存儲的信息稱做指針或鏈。N個結點鏈結成一個鏈表,由於此鏈表的每一個結點中包含一個指針域,故又稱線性鏈表或單鏈表。
循環鏈表
循環鏈表是單鏈表的變形
循環鏈表最后一個結點的next指針不為空,而是指向了表的前端。為簡化操作,在循環鏈表中往往加入表頭結點。
循環鏈表的特點是:只要知道表中某一結點的地址,就可搜尋到所有其他結點的地址。
雙向鏈表
雙向鏈表是指在前驅和后繼方向都能游歷(遍歷)的線性鏈表。
在雙向鏈表結構中,每一個結點除了數據域外,還包括兩個指針域,一個指針指向該結點的后繼結點,另一個指針指向它的前趨結點。通常采用帶表頭結點的循環鏈表形式。
用指針實現表
用數組實現表時,利用了數組單元在物理位置上的鄰接關系表示表元素之間的邏輯關系。
優點是:
無須為表示表元素之間的邏輯關系增加額外的存儲空間。
可以方便地隨機存取表中任一位置的元素。
缺點是:
插入和刪除運算不方便,除表尾位置外,在表的其他位置上進行插入或刪除操作都須移動大量元素,效率較低。
由於數組要求占用連續的存儲空間,因此在分配數組空間時,只能預先估計表的大小再進行存儲分配。當表長變化較大時,難以確定數組的合適的大小
順序表與鏈表的比較
順序表的存儲空間可以是靜態分配的,也可以是動態分配的。鏈表的存儲空間是動態分配的。順序表可以隨機或順序存取。
鏈表只能順序存取。順序表進行插入/刪除操作平均需要移動近一半元素。鏈表則修改指針不需要移動元素。
若插入/刪除僅發生在表的兩端,宜采用帶尾指針的循環鏈表。存儲密度=結點數據本身所占的存儲量/結點結構所占的存儲總量。順序表的存儲密度= 1,鏈表的存儲密度< 1。
總結:順序表是用數組實現的,鏈表是用指針實現的。用指針來實現的鏈表,結點空間是動態分配的,鏈表又按鏈接形式的不同,區分為單鏈表、雙鏈表和循環鏈表。
十一、棧和隊列
棧是限定在一端進行插入與刪除的線性表,允許插入與刪除的一端稱為棧頂,不允許插入與刪除的另一端稱為棧底。
棧按照“先進后出”(filo)或“后進先出”(lifo)組織數據,棧具有記憶作用。用top表示棧頂位置,用bottom表示棧底。
棧的基本運算:(1)插入元素稱為入棧運算;(2)刪除元素稱為退棧運算;(3)讀棧頂元素是將棧頂元素賦給一個指定的變量,此時指針無變化。
隊列是指允許在一端(隊尾)進入插入,而在另一端(隊頭)進行刪除的線性表。rear指針指向隊尾,front指針指向隊頭。
隊列是“先進行出”(fifo)或“后進后出”(lilo)的線性表。
隊列運算包括(1)入隊運算:從隊尾插入一個元素;(2)退隊運算:從隊頭刪除一個元素。
循環隊列:s=0表示隊列空,s=1且front=rear表示隊列滿
十二、棧
是限定僅在表尾進行插入或刪除操作的線性表。棧是一種后進先出(Last In First Out)/先進后出的線性表,簡稱為LIFO
用指針實現棧—鏈(式)棧鏈式棧
無棧滿問題,空間可擴充
插入與刪除僅在棧頂處執行
鏈式棧的棧頂在鏈頭
適合於多棧操作
鏈棧的基本操作
1)進棧運算
進棧算法思想:
1)為待進棧元素x申請一個新結點,並把x賦給 該結點的值域。
2)將x結點的指針域指向棧頂結點。
3)棧頂指針指向x結點,即使x結點成為新的棧頂結點。
具體算法如下:
SNode *Push_L(SNode * top,ElemType x)
{
SNode *p;
p=(SNode*)malloc(sizeof(SNode));
p->data=x;
p->next=top;
top=p;
return top;
}
2)出棧運算
出棧算法思想如下:
1)檢查棧是否為空,若為空,進行錯誤處理。
2)取棧頂指針的值,並將棧頂指針暫存。
3)刪除棧頂結點。
SNode *POP_L(SNode * top,ElemType *y)
{SNode *p;
if(top==NULL) return 0;/*鏈棧已空*/
else{
p=top;
*y=p->data;
top=p->next; free(p);
return top;
}
3)取棧頂元素
具體算法如下:
void gettop(SNode *top)
{
if(top!=NULL)
return(top->data); /*若棧非空,則返回棧頂元素*/
else
return(NULL); /*否則,則返回NULL*/
}
十三、隊列(Queue)
是只允許在表的一端進行插入,而在另一端進行刪除的運算受限的線性表。其所有的插入均限定在表的一端進行,該端稱為隊尾(Rear);所有的刪除則限定在表的另一端進行,該端則稱為隊頭(Front)。
如果元素按照a1,a2,a3....an的順序進入隊列,則出隊列的順序不變,也是a1,a2,a3....an。所以隊列具有先進先出(First In First Out,簡稱FIFO)/后進后出特性。
如車站排隊買票,排在隊頭的處理完走掉,后來的則必須排在隊尾等待。
在程序設計中,比較典型的例子就是操作系統的作業排隊。隊列的順序存儲結構稱為順序隊列,順序隊列實際上是運算受限的順序表,和順序表一樣,順序隊列也是必須用一個數組來存放當前隊列中的元素。
由於隊列的隊頭和隊尾的位置是變化的,因而要設兩個指針分別指示隊頭和隊尾元素在隊列中的位置。
循環隊列是為了克服順序隊列中“假溢出”,通常將一維數組Sq.elem[0]到Sq.elem.[MaxSize-1]看成是一個首尾相接的圓環,即Sq.elem[0]與Sq.elem .[maxsize-1]相接在一起。這種形式的順序隊列稱為循環隊列。
用線性鏈表表示的隊列稱為鏈隊列。鏈表的第一個節點存放隊列的隊首結點,鏈表的最后一個節點存放隊列的隊尾首結點,隊尾結點的鏈接指針為空。另外還需要兩個指針(頭指針和尾指針)才能唯一確定,頭指針指向隊首結點,尾指針指向隊尾結點
十四、 樹與二叉樹
樹是一種簡單的非線性結構,所有元素之間具有明顯的層次特性。
在樹結構中,每一個結點只有一個前件,稱為父結點,沒有前件的結點只有一個,稱為樹的根結點,簡稱樹的根。每一個結點可以有多個后件,稱為該結點的子結點。沒有后件的結點稱為葉子結點。
在樹結構中,一個結點所擁有的后件的個數稱為該結點的度,所有結點中最大的度稱為樹的度。樹的最大層次稱為樹的深度。
二叉樹的特點:(1)非空二叉樹只有一個根結點;(2)每一個結點最多有兩棵子樹,且分別稱為該結點的左子樹與右子樹。
二叉樹的基本性質:
(1)在二叉樹的第k層上,最多有2k-1(k≥1)個結點;
(2)深度為m的二叉樹最多有2m-1個結點;
(3)度為0的結點(即葉子結點)總是比度為2的結點多一個;
(4)具有n個結點的二叉樹,其深度至少為[log2n]+1,其中[log2n]表示取log2n的整數部分;
(5)具有n個結點的完全二叉樹的深度為[log2n]+1;
(6)設完全二叉樹共有n個結點。如果從根結點開始,按層序(每一層從左到右)用自然數1,2,….n給結點進行編號(k=1,2….n),有以下結論:
①若k=1,則該結點為根結點,它沒有父結點;若k>1,則該結點的父結點編號為int(k/2);
②若2k≤n,則編號為k的結點的左子結點編號為2k;否則該結點無左子結點(也無右子結點);
③若2k+1≤n,則編號為k的結點的右子結點編號為2k+1;否則該結點無右子結點。
滿二叉樹是指除最后一層外,每一層上的所有結點有兩個子結點,則k層上有2k-1個結點深度為m的滿二叉樹有2m-1個結點。
完全二叉樹是指除最后一層外,每一層上的結點數均達到最大值,在最后一層上只缺少右邊的若干結點。
二叉樹存儲結構采用鏈式存儲結構,對於滿二叉樹與完全二叉樹可以按層序進行順序存儲。
二叉樹的遍歷:
(1)前序遍歷(dlr),首先訪問根結點,然后遍歷左子樹,最后遍歷右子樹;
(2)中序遍歷(ldr),首先遍歷左子樹,然后訪問根結點,最后遍歷右子樹;
(3)后序遍歷(lrd)首先遍歷左子樹,然后訪問遍歷右子樹,最后訪問根結點。
十五、樹
①結點的度:結點擁有子節點的個數
②樹的度:該樹中最大的度數
③葉子結點:度為零的結點
④分支結點:度不為零的結點
⑤內部結點:除根結點之外的分支結點
⑥開始結點:根結點又稱為開始結點
結點的高度:該結點到各結點的最長路徑的長度
森林:m(m≥0)棵互不相交的樹的集合。將一棵非空樹的根結點刪去,樹就變成一個森林;
反之,給m棵獨立的樹增加一個根結點,並把這m棵樹作為該結點的子樹,森林就變成一棵樹。
2.結點的層數和樹的深度
①結點的層數:根結點的層數為1,其余結點的層數等於其雙親結點的層數加1。
②堂兄弟:雙親在同一層的結點互為堂兄弟。
③樹的深度:樹中結點的最大層數稱為樹的深度。
注意:要弄清結點的度、樹的度和樹的深度的區別。
樹中結點之間的邏輯關系是“一對多”的關系,樹是一種非線性的結構
樹的遍歷
先序遍歷:訪問根結點——先序遍歷根的左子樹——先序遍歷根的右子數
中序遍歷:中序遍歷左子樹——訪問根結點——中序遍歷右子樹
后序遍歷:后序遍歷左子樹——后序遍歷右子樹——訪問根結點
最優二叉樹(哈夫曼樹):最小兩結點數相加的值再與次小結點數合並。
已知一棵二叉樹的前根序序列和中根序序列,構造該二叉樹的過程如下:
1. 根據前根序序列的第一個元素建立根結點;
2. 在中根序序列中找到該元素,確定根結點的左右子樹的中根序序列;
3. 在前根序序列中確定左右子樹的前根序序列;
4. 由左子樹的前根序序列和中根序序列建立左子樹;
5. 由右子樹的前根序序列和中根序序列建立右子樹。
-已知一棵二叉樹的后根序序列和中根序序列,構造該二叉樹的過程如下:
1. 根據后根序序列的最后一個元素建立根結點;
2. 在中根序序列中找到該元素,確定根結點的左右子樹的中根序序列;
3. 在后根序序列中確定左右子樹的后根序序列;
4. 由左子樹的后根序序列和中根序序列建立左子樹;
5. 由右子樹的后根序序列和中根序序列建立右子樹。
十六、圖
G= ( V , E ) = ( 頂點,邊)
無向完全圖有n(n - 1)/ 2 個邊 ,有向完全圖有n(n - 1)個邊 。n表結點。
邊無向(),弧有向<>
迪傑斯特拉(Dijkstra)算法
是典型的單源最短路徑算法,用於計算一個節點到其他所有節點的最短路徑。主要特點是以起始點為中心向外層層擴展,直到擴展到終點為止。Dijkstra算法是很有代表性的最短路徑算法,在很多專業課程中都作為基本內容有詳細的介紹,如數據結構,圖論,運籌學等等。注意該算法要求圖中不存在負權邊。
弗洛伊德(Floyd)算法<鄰接矩陣求>
是解決任意兩點間的最短路徑的一種算法,可以正確處理有向圖或負權的最短路徑問題,同時也被用於計算有向圖的傳遞閉包。Floyd-Warshall算法的時間復雜度為O(N3),空間復雜度為O(N2)。
普里姆(Prim)算法
普里姆算法的基本思想:
從連通網絡N= {V,E}中的某一頂點u0出發,選擇與它關聯的具有最小權值的邊(u0,v),將其頂點加入到生成樹頂點集合S中。以后每一步從一個頂點在S中而另一個頂點不在S中的各條邊中選擇權值最小的邊(u,v),把它的頂點加入到集合S中。如此繼續下去,直到網絡中的所有頂點都加入到生成樹頂點集合S中為止。
克魯斯卡爾(Kruskal)算法
克魯斯卡爾算法的基本思想:
設有一個有n個頂點的連通網絡N= {V,E},最初先構造一個只有n個頂點,沒有邊的非連通圖T= {V,∅},圖中每個頂點自成一個連通分支。當在E中選到一條具有最小權值的邊時,若該邊的兩個頂點落在不同的連通分支上,則將此邊加入到T中;否則將此邊舍去,重新選擇一條權值最小的邊。如此重復下去,直到所有頂點在同一個連通分支上為止。
十七、查找計數
順序查找的使用情況:
(1)線性表為無序表;
(2)表采用鏈式存儲結構。
二分法查找只適用於順序存儲的有序表,對於長度為n的有序線性表,最壞情況只需比較log2n次。
十八、排序計數
排序是指將一個無序序列整理成按值非遞減順序排列的有序序列。
交換類排序法:(1)冒泡排序法,需要比較的次數為n(n-1)/2; (2)快速排序法。
插入類排序法:(1)簡單插入排序法,最壞情況需要n(n-1)/2次比較;(2)希爾排序法,最壞情況需要o(n1.5)次比較。
選擇類排序法:(1)簡單選擇排序法,
最壞情況需要n(n-1)/2次比較;(2)堆排序法,最壞情況需要o(nlog2n)次比較。
排序小結
1、就平均時間性能而言,快速排序最佳。但在最壞情況下不如堆排序和歸並排序。(歸並排序對n較大時適用)
2、當序列中的記錄“基本有序”或n值較小時,直接插入排序是最佳的方法,因此常將它與其他排序方法結合使用,如快速排序、歸並排序等。
3、基數排序的時間復雜度也可寫成O(d*n),因此它最適用於n值很大而關鍵字較小的序列。
4、穩定的排序方法:簡單排序。不穩定的排序方法:快速排序、堆排序。
一般來說,排序過程中的“比較”是在相鄰的兩個記錄的關鍵字之間進行的排序方法是穩定的。
參考:
http://c.biancheng.net/cpp/u/shuju/
http://www.cnhonkerarmy.com/thread-94743-1-7.html
https://www.jianshu.com/p/730be599b6b7