第一章 緒論
數據:所有能輸入到計算機中並被計算機程序處理的符號的總稱。
數據結構:數據間的相互關系,即數據的組織形式。包括三個方面:數據的邏輯結構,數據的存儲結構,數據的運算(對數據的操作)。
邏輯結構:線性結構(2 線性表;3 棧和隊列;4 數組和廣義表;5 串)和非線性(6 樹;7 圖)
8 查找 ;9 排序
存儲結構(數據的物理結構):順序存儲、鏈式存儲、索引存儲、散列存儲
順序存儲和鏈式存儲的優缺點:
順序存儲優點:存取方式是隨機的,讀取數據比較方便,缺點:插入和刪除操作需要移動大量的數據
鏈式存儲方式的優缺點與順序相反。
判斷算法好壞的標准:時間復雜度和空間復雜度(耗費的存儲空間),合稱算法復雜度。
時間復雜度:漸進時間復雜度T(n)
第二章 線性表
線性表:由n(n>=0)個相同數據類型的元素組成的有限序列。
邏輯特征:(1:1)
l 第一個結點是開始結點,無前驅有唯一的后繼
l 最后一個結點是終端節點,無后繼有唯一的前驅
l 中間結點,有唯一前驅和唯一的后繼
邏輯結構的定義方式:(元素1,元素2,。。。)
存儲結構:(物理結構)
l 順序存儲(用數組體現):預先分配一段連續的區域,靜態分配 int a[10]; a表示a[0]的地址,大小是事先知道的,注意溢出問題。
順序表:兩層含義:邏輯結構上線性結構
物理上順序存儲
l 鏈式存儲(用指針):占用的區域不一定連續,動態分配;malloc free
鏈表:兩層含義:邏輯結構上線性結構
物理上鏈式存儲
順序表的插入:maxsize表示最多存放的元素的個數,size表示有效元素的個數
1、 判斷滿不滿:滿的條件:size= =maxsize
2、 插入的位置是不是合法(i>=1&&i<=size+1)
3、 后移(先移動后面的)
4、 插入 size++;
順序表的刪除:
1、 判斷空間是否是空 (size= =0)
2、 判斷位置是不是合法 (1<=i<=size)
3、 前移(先移動前面的)
4、 Size- -
移動次數:n/2插入,(n-1)/2刪除
鏈表:
結點:date+next
分類:單鏈表、循環鏈表、雙鏈表
三個術語:頭結點、頭指針、開始結點
插入操作:p結點的后面
1、 生成空間:s=(S *)malloc(sizeof(S));
2、 賦值:s->data=X;
3、 s->next=p->next;(修改新結點的指針)
4、 P->next=s;
鏈表的刪除:p結點的后面的結點
1、 q=p->next;
2、 p->next=q->next; //p->next=p->next->next;
3、 free(q);
刪除p結點本身:
A、 尋找p結點的前驅結點,轉化為刪除p結點的前驅結點的后繼
q=head;
while(q->next!=p)
q=q->next;
q->next=p->next;
free(p);
B、 刪除p的后繼(p結點不是終端結點,p一定要有后繼)
q=p->next;
p->data=q->data;
p->next=q->next;
free(q);
多項式表達式:結構體一個系數,一個指數
第三章 棧和隊列
棧和隊列是特殊的線性表。特殊在插入和刪除操作都是在表的端點處進行。
棧Stack:操作受限(插入和刪除)的線性表。
在線性表的末尾做插入和刪除,叫做棧頂top 線性表的開始部分叫做棧底 bottom
特點:FILO
典型應用:函數的調用,數制轉換(求余過程中,需逆序輸出),括弧匹配檢驗,迷宮問題(方向設置為8個方向,走過標記),表達式求解問題(中綴表達式,后綴表達式),遞歸。
后綴表達式:加上所有能加的括號;用離右括號左邊最近的運算符來替代所有的右括號;去掉所有的左括號。后綴表達式中沒有括號,運算符優先級也蘊含在表達式中,可直接利用棧來求解。運算數是個位的數。中間不能出現空格。
存儲方式:
l 順序存儲(用數組體現,靜態分配存儲空間)
l 鏈式存儲(涉及到指針,動態分配和釋放存儲空間)
順序棧的插入:top表示棧頂元素的下標,定義是int類型的,格式是int top;maxsize表示空間的大小,最多存放多少個元素。
(在順序表的基礎上修改的,紅顏色粗體部分去掉)
1、 判斷滿不滿:滿的條件是top= = maxsize-1
2、 插入的位置是不是合法(i>=1&&i<=size+1):去掉原因是位置固定 size+1
3、 后移(先移動后面的):去掉
4、 top++;插入(data[top]=X)
順序棧的刪除:(在順序表的基礎上修改的,紅顏色粗體部分去掉)
1、 判斷空間是否是空 (top= =-1 top<0)
2、 判斷位置是不是合法(1<=i<=size)
3、 前移(先移動前面的)
4、 top - -
鏈棧的插入操作:top表示棧頂的指針,類似於head,top是指針變量 格式:數據類型 *top;
1、 生成空間:s=malloc(。。。。);
2、 賦值:s->data=X;
3、 修改指針:s->next=top;(先修改的是新結點的指針)
4、 修改top指針:top=s;
鏈棧的刪除:
1、 p=top;
2、 top=top->next;
3、 free(p);
進棧的順序是123,則可能的出棧的順序是123、132、213、231、312、321
隊列:
1、 定義:操作受限的線性表(在表的一端進行插入、在另一端進行刪除)
2、 在線性表的末尾進行插入操作,叫做隊尾 rear,指向隊尾元素的下一個位置
在線性表的開始做刪除操作,叫做隊頭 front
3、 特點:FIFO
4、 存儲結構:
l 順序存儲(用數組體現,靜態分配存儲空間)
l 鏈式存儲(用指針體現,動態分配和釋放存儲空間)
入隊列的順序是1234,則出隊的順序是1234。
避免順序隊列的假溢出現象(存儲空間未滿,rear到達終點),引入循環隊列。
循環隊列:隊列的順序存儲結構
隊列空時和隊列滿時判斷條件都相同,就少用一個元素空間,約定以“隊列頭指針front在隊尾指針reat的下一個位置上”為隊列滿的標志。rear指向的是隊列中空的位置。
循環隊列長度是maxsize,則最多存放maxsize-1個元素。
l Front表示:隊頭元素的前一個位置
l Rear:隊尾元素的下標
循環隊列空的條件是:front= = rear
循環隊列滿的條件是:front==(rear+1)%maxsize
循環隊列的元素的個數是:(rear-front+maxsize)%maxsize
循環隊列的隊頭元素的下標:(front+1)%maxsize
備注:凡涉及到+1,都要%maxsize
順序隊列的插入:(在順序表的基礎上修改的,紅顏色粗體部分去掉)
1、 判斷滿不滿:滿的條件:front= =(rear+1)%maxsize
2、 插入:rear=(rear+1)%maxsize
data[rear]=X;
順序隊列的刪除:(在順序表的基礎上修改的,紅顏色粗體部分去掉)
1、 判斷空間是否是空:空的條件是front= =rear
2、 刪除:front=(front+1)%maxsize
鏈隊列:隊列的鏈式存儲結構
Front表示的隊頭元素的指針
Rear表示隊尾的指針
鏈隊列的插入操作:
1、 p=malloc(…);
2、 p->data=X;
3、 p->next=NULL;(先修改新產生結點的指針)
4、 rear->next=p;
5、 rear=p;
鏈隊列的刪除:(帶頭結點的隊列)
一、 刪除真正的隊頭元素
1、 判斷隊列是否為空:空的條件是front= = rear
2、 s=front->next;
3、 front->next=s->next;
4、 free(s);
二、 通過刪除頭結點轉化為刪除隊頭元素
1、 判斷隊列是否為空:空的條件是front= = rear
2、 s=front;
3、 front=front->next;
4、 free(s);
練習:
(10,20,30)
1、 線性表,畫出帶頭結點的單鏈表
2、 棧,分別畫出順序存儲結構 鏈式存儲結構
3、 隊列,分別畫出順序存儲結構 鏈式存儲結構
第四章 數組和廣義表
數組:兩種操作(查找和修改)
兩種存儲結構:按行優先、按列優先
因為數組沒有插入和刪除,所以順序存儲結構更適宜。
運算:計算地址、計算按行優先時的地址按列優先時是哪個元素
廣義表:(不考)元素具有其自身結構。是遞歸定義的線性結構。
l 表頭一定是原子。 (×)
l 表頭一定是廣義表。 (×)
l 表尾一定是原子。(×)
l 表尾一定是廣義表。(√)
元素ai可以是原子項,可以是廣義表。圓括號將廣義表括起來,逗號分隔元素。
廣義表的數據元素有相對次序;長度定義為最外層包含的元素個數;深度定義為所含括弧的重數,原子項深度為0,空表深度為1.;廣義表可以共享;可以是一個遞歸的表,遞歸表的深度是無窮值,長度時有限值;任何一個非空廣義表可分解為表頭和表尾。
第五章 串
兩個串相等的充要條件是:串長相等並且對應位置上的字符要相同。
空串和空白串區別:n為0,空白串是指內容是空格。串的結束標志:“”和字符數組。
串的運算:串的鏈接、求子串、求子串在主串中的位置(模式匹配)、串的比較、串的復制、串的替換 等等。
Int a[]=”123”; (√)
Int a[10]; a=”123”; (×)
Char name[10]=”gmm”;
For(i=0;i<size;i++)
If(strcmp(name,stu[i].name)= =0)
練習:
輸出所有的“水仙花數”。所謂“水仙花數”是指一個3位數,其各位數字立方和等於該數本身。例如:153是一個水仙花數,應為153=13+53+33。
第六章 樹
樹:非線性結構
1、定義:有n(n>=0)個結點組成的有限集合。對於非空樹來說:有且僅有一個根結點;子樹由t1,t2.。。互斥的集合。
2、術語:結點的度、樹的度、樹的高度、路徑、路徑的長度、樹的路徑長度、樹的帶權路徑長度
結點的度:結點擁有的子樹的個數,最大的結點的度稱為樹的度。
結點的層次:根節點層次為1。
樹的高度或深度:樹中結點的最大層數。
路徑長度:路徑所經過的邊的數目。
森林:m(m>=0)棵互不相交的樹所構成的集合。
3、樹的存儲:雙親表示法、孩子表示法、雙親孩子表示法、孩子兄弟表示法(順序,鏈式,數組鏈式)
二叉樹:
判斷:二叉樹是樹;是度為2的樹;是特殊的樹;是度為2 的有序樹。(×)二叉樹不一定是有序的。
5個性質:
性質1:二叉樹第i層上最多2i-1(數學歸納法)
性質2:深度為k的二叉樹上最多2k-1(等比數列),滿二叉樹的結點數量為2k-1。
性質3:二叉樹上度為0的節點有n0個,度為2的節點有n2個,則n0=n2+1 (N=n0+n1+n2=0*n0+1*n1+2*n2+1)
滿二叉樹完全二叉樹
l 滿二叉樹一定是完全二叉樹。(√)
l 完全二叉樹一定是滿二叉樹。(×)
l 完全二叉樹的結點如果有左孩子,則它一定有右孩子。(×)
l 完全二叉樹的結點如果有右孩子,則它一定有左孩子。(√)
l 完全二叉樹的結點如果沒有左孩子,則它一定沒有右孩子,該結點一定是葉結點。(√)
完全二叉樹的定義:一棵具有n個結點的二叉樹,它的結構與一棵滿二叉樹的前n個結點的結構相同。滿二叉樹:所有葉子結點都在統一層上,所有的非葉子結點的度都為2.
性質4:有n個節點的完全二叉樹的深度為(設深度k,2k-1-1+1≤n≤2k-1)[log2(n+1)]+1
[]表示取整。
性質5:把完全二叉樹編碼,從上到下,同一層上從左向右,
l I=1:是根結點,沒有雙親;i>1:有雙親,雙親編碼是i/2;
l I:2i是左孩子,如果存在右孩子,則右孩子的編碼是2i+1;
l I:2i+1是它的右孩子,左孩子的編碼是2i。
練習:
1、有1001個結點的完全二叉樹,樹的高度為(),其中葉子結點的個數為(),度為1的結點的個數為(),度為2的結點的個數為()。
2、已知二叉樹有52個葉子結點,度為1的結點個數為30則總結點個數為()。
二叉樹的存儲:
l 順序存儲---à完全二叉樹的存儲(下表為0的空間沒用 性質5來判斷雙親和孩子的關系)
l 鏈式存儲(二叉鏈表、帶雙親的二叉鏈表(三叉鏈表))-à一般二叉樹
二叉樹的遍歷:先序遍歷(第一個節點是根結點)、中序遍歷(來判斷左右子樹的結點)、后序遍歷(最后一個節點是根結點)
根據先序和中序、中序和后序得到二叉樹。
層次遍歷:從二叉樹的第一層開始,上到下,左到右的遍歷。
練習:
1、已知二叉樹的中序遍歷序列是ACBDGHFE,后序遍歷序列是ABDCFHEG,請構造一棵二叉樹。
2、已知二叉樹的層次遍歷序列為ABCDEFGHIJK,中序序列為DBGEHJACIKF,請構造一棵二叉樹。
3、已知二叉樹的前序、中序和后序遍歷序列如下,其中有一些看不清的字母用*表示,請先填寫*處的字母,再構造一棵符合條件的二叉樹。
(1)前序遍歷序列是:*BC***G*
(2)中序遍歷序列是:CB*EAGH*
(3)后序遍歷序列是:*EDB**FA
線索二叉樹:將二叉樹的結點的空閑指針指向該結點在某種遍歷次序下的前驅結點或后繼結點所形成的樹的結構。分為前序線索二叉樹,中序。。,后續。。。
樹、森林和二叉樹之間的轉換:
l 樹----à二叉樹:加線(相鄰兄弟加虛)、抹線(刪除雙親與非第一個孩子連線,即刪除同層中相連的結點靠右結點與上一層結點的連線)、調整(結論:轉換后的二叉樹沒有右子樹)
l 二叉樹-----à樹:加線(相鄰兄弟加虛)、抹線(刪除雙親與非第一個孩子連線,即刪除同層次中結點相連的線)、調整(剩余線中有虛線的變實線,調整角度)
l 森林-----à二叉樹:
l 二叉樹-----à森林:串接,按先后順序,依次將后邊的二叉樹作為前邊二叉樹的根節點的右子樹。
樹、森林和二叉樹的遍歷
1、樹的先跟遍歷次序與它所對應的二叉樹的先序遍歷次序相同;
2、樹的后跟遍歷次序與它所對應的二叉樹的中序遍歷次序相同;
3、森林的先序遍歷次序與它所對應的二叉樹的先序遍歷次序相同;
4、森林的中序遍歷次序與它所對應的二叉樹的中序遍歷次序相同;
哈弗曼樹及其編碼:
帶權二叉樹,權值為w。
l 術語:路徑、路徑的長度、樹的路徑長度(從根結點到每一個葉子結點的路徑長度之和)、帶權路徑長度(根結點到葉子結點的路徑長度*權值乘積之和)
l 構造:每次找兩個權值最小的結點進行合並,得到的新節點的權值放到最后,循環合並,直到只剩下一個結點的時候結束過程,這時候的二叉樹就是所求的最優二叉樹(哈夫曼樹)。
l 哈弗曼編碼:左分支為0,右分支為1,從根結點到葉子結點所經過的邊的編碼就是它所對應的哈弗曼編碼。
第七章 圖
1、定義:
l 圖:Graph 兩個集合V(vertex) E
l 有向圖:V E <V,W > 邊又稱為弧,<vi,vj>,弧尾(vi不帶箭頭的一端),弧頭(帶箭頭的一端)
l 無向圖: (V,W)= =(W,V)邊(vi,vj)
2、術語:
l 完全圖(任意兩個定點之間都有邊 無向圖 n*(n-1)/2 有向圖 n*(n-1))
l 結點的度:與這個頂點相關聯的邊的條數TD
l 入度:針對的有向圖 以這個頂點為弧頭 ID
l 出度:針對有向圖 以這個頂點為弧尾OD, TD=ID+OD
l 邊的個數:所有頂點的度的總和/2
l 連通圖:
如果兩個頂點之間有路徑(頂點序列),那么這兩個頂點就是連通的
連通圖:無向圖 任意兩個頂點之間都有路徑
判斷: 完全圖一定是連通圖(√)
連通圖一定是完全圖(×)
l 連通分量:非連通圖的極大連通子圖
l 強連通圖:有向圖中兩個頂點間相互存在路徑的圖
強連通分量:有向圖的極大強連通子圖
l 生成樹:連通圖的生成樹是連通圖,有n個頂點,(至少需要n-1邊使得它連通,)包含且僅包含n-1條邊,一個連通圖的極小連通子圖
3、 圖的存儲:
(1)鄰接矩陣:
如果有n個頂點的無向圖,存儲空間壓縮 n*(n+1)/2
如果有n個頂點的有向圖,存儲空間不能壓縮 n*n
有向圖的連接矩陣 第i行非零元素的個數------à出度
第i列非零元素的個數------à入度
無向圖的連接矩陣:第i行(或者列)非零元素的個數------à度
(2)鄰接表:
無向圖中頂點Vi的度是鄰接表中結點的個數;
有向圖中,頂點Vi的出度是鄰接表中結點的個數;
頂點Vi的入度是逆鄰接表中結點的個數。
圖的遍歷:深度遍歷廣度遍歷
深度遍歷:v出發,訪問鄰接點進行深度優先遍歷,直到所有和v有路徑相通的點被訪問,再另選未被遍歷的點,進行深度優先遍歷。類似先根遍歷。0-1-3-7-4-5-2-6
廣度遍歷:訪問v的未曾訪問過的鄰接點,再以鄰接點為出發點訪問其鄰接點,使“先被訪問的頂點的鄰接點”先於“后被訪問的頂點的鄰接點”。類似層次遍歷。0-1-2-3-4-5-6-7
生成樹:深度遍歷的生成樹 廣度遍歷生成樹
最小生成樹:
l Prim:把頂點分為兩個集合,分別從這兩個集合中各找出一個頂點,使得這兩個頂點之間的邊的權值是最小的,把綠顏色頂點合並到黃顏色中,繼續。。。,直到所有頂點都合並到黃顏色中為止。
l Kruscal:把頂點分別作為集合,每次從邊的集合中查找權值最小的兩個頂點:如果這兩個頂點分屬於不同集合,合並;如果這兩個頂點分屬於同一集合,繼續查找下一條權值較小的邊。
最短路徑:迪傑斯特拉算法
l 第一條最短路徑:在所有的直達路徑中,找出最短的一條路徑
l 在后面的最短路徑:要么直達;要么經過已經求出的最短路徑的頂點。
拓撲結構:主要用於查看工序之間的前驅后繼的關系。AOV網
第八章 查找
1、線性表的查找(靜態查找)
l 順序查找:順序表 鏈表 n
l 折半查找(二分查找):有序的順序表(中間元素作為比較對象):遞歸和非遞歸
l 索引順序表查找(分塊查找):結合了順序查找和折半查找,將查找表分成若干分塊,建立相應的索引,索引表是按序的。子表中的數據均小於關鍵字的值。
2、樹表的查找(動態查找):二叉排序樹(二叉查找樹)
(1)定義:可以是空樹,如果非空,滿足3個條件(左不為空,左上的所有點均小於根,右不為空,均大於根;左右子樹也都是二叉查找樹)
(2)查找
(3)插入(作為葉子結點插入)
(4)刪除(3種情況):
l 刪除葉子結點:直接刪除,修改其雙親的左指針或者右指針為NULL
l 刪除只有左子樹或者只有右子樹:修改其雙親直接指向其左孩子或者右孩子
l 刪除既有左子樹又有右子樹:用中序遍歷的前驅結點代替刪除結點,然后刪除前驅結點。
平衡二叉樹:AVL空二叉樹或是具有下列性質:左子樹和右子樹都是平衡二叉樹,且左和右子樹高度差得絕對值不超過1.
哈希表:選取某個函數,根據寒素按關鍵字計算數據的存儲位置,按次位置存放數據(哈希造表);查找時,同一個函數對給定值x計算地址,再將x與地址中的關鍵字比較,哈希方法,散列法。