《大话数据结构》一些基础知识
第一章 數(shù)據(jù)結(jié)構(gòu)緒論
?
1.4 基本概念和術(shù)語(yǔ)
1.4.1 數(shù)據(jù)
數(shù)據(jù):描述客觀事物的符號(hào),是計(jì)算機(jī)中可以操作的對(duì)象,是能被極端及識(shí)別,并輸入給計(jì)算機(jī)處理的符號(hào)集合。
1.4.2 數(shù)據(jù)元素
數(shù)據(jù)元素:是組成數(shù)據(jù)的、有一定意義的基本單位,在計(jì)算機(jī)中通常作為整體處理(也叫記錄)
1.4.3 數(shù)據(jù)項(xiàng)
數(shù)據(jù)項(xiàng):一個(gè)數(shù)據(jù)元素可以由若干個(gè)數(shù)據(jù)項(xiàng)組成
數(shù)據(jù)項(xiàng)是數(shù)據(jù)不可分割的最小單位
1.4.4 數(shù)據(jù)對(duì)象
數(shù)據(jù)對(duì)象:是性質(zhì)相同的數(shù)據(jù)元素的集合,是數(shù)據(jù)的子集。
1.4.5 數(shù)據(jù)結(jié)構(gòu)
1)不同元素之間不是獨(dú)立的,而是存在特定的關(guān)系,我將這些關(guān)系稱為結(jié)構(gòu)
2)數(shù)據(jù)結(jié)構(gòu):是相互之間存在一種或多種特定關(guān)系的數(shù)據(jù)元素的集合
?
1.5 邏輯結(jié)構(gòu)和物理結(jié)構(gòu)
1.5.1 邏輯結(jié)構(gòu)
邏輯結(jié)構(gòu):指數(shù)據(jù)對(duì)象中數(shù)據(jù)元素之間的相互關(guān)系。分4種:
1)集合結(jié)構(gòu):同屬于一個(gè)集合,沒有其他的關(guān)系
2)線性結(jié)構(gòu):線性結(jié)構(gòu)中的數(shù)據(jù)元素的一對(duì)一的關(guān)系
3)樹形結(jié)構(gòu):數(shù)據(jù)元素存在一對(duì)多的層次關(guān)系
2)圖形結(jié)構(gòu):數(shù)據(jù)元素的多對(duì)多的關(guān)系
1.5.2 物理結(jié)構(gòu)
物理結(jié)構(gòu):值數(shù)據(jù)的邏輯結(jié)構(gòu)在計(jì)算機(jī)中的存儲(chǔ)形式。分2種:
1)順序存儲(chǔ)結(jié)構(gòu):把數(shù)據(jù)元素存放在連續(xù)的存儲(chǔ)單元里,其數(shù)據(jù)間的邏輯關(guān)系和物理關(guān)系的一致的。
2)鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu):把數(shù)據(jù)存放在任意的存儲(chǔ)單元里,這組存儲(chǔ)單元可以是連續(xù)的,也可以是不連續(xù)的
?
1.6 抽象數(shù)據(jù)類型
1.6.1 數(shù)據(jù)類型
數(shù)據(jù)類型:指一組性質(zhì)相同的值的集合及定義在此集合上的一些操作的總稱
C語(yǔ)言中,數(shù)據(jù)類型分兩類:
1)原子類型:不可以再分割的,包括整型,實(shí)型,字符型
2)結(jié)構(gòu)類型:由若干個(gè)類型組合而成,可以再分解。
抽象是指抽取出事物具有的普遍性的本質(zhì)
1.6.2 抽象數(shù)據(jù)類型
抽象數(shù)據(jù)類型:指一個(gè)數(shù)學(xué)模型及定義在該模型上的一組操作
“抽象”的意義在于數(shù)據(jù)類型的數(shù)學(xué)抽象特性
抽象數(shù)據(jù)類型體現(xiàn)了程序設(shè)計(jì)中問題分解、抽象和信息隱藏的特性。
?
?
第二章 算法
定義:算法是解決特定問題求解步驟的描述,在計(jì)算機(jī)中表現(xiàn)為指令的有限序列,并且每條指令表示一個(gè)或多個(gè)操作
?
2.5 算法的特性
五個(gè)基本特性:輸入、輸出、有窮性,確定性、可行性
2.5.1 輸入輸出
算法具有零個(gè)或多個(gè)輸入
算法具有一個(gè)或多個(gè)輸出
2.5.2 有窮性
指算法在執(zhí)行有限的步驟之后,自動(dòng)結(jié)束而不會(huì)出現(xiàn)無限循環(huán),并且每個(gè)步驟可在可接受的時(shí)間內(nèi)完成
2.5.3 確定性
算法的每一步驟都具有確定的含義,不會(huì)出現(xiàn)二義性。
2.5.4 可行性
算法的每一步都必須是可行的,每一步都能通過執(zhí)行有限次數(shù)完成。
?
2.6 算法設(shè)計(jì)的要求
2.6.1 正確性
指算法至少應(yīng)該具有輸入、輸出和加工的無歧義性,能正確反映問題的需求,能夠得到問題的正確答案。
沒有語(yǔ)法錯(cuò)誤,對(duì)于合法輸入能滿足要求,對(duì)于非法輸入和對(duì)于精心選擇的刁難的測(cè)試數(shù)據(jù)都能滿足要求。
2.6.2 可讀性
算法設(shè)計(jì)的另一目的就是便于閱讀、理解和交流
2.6.3 健壯性
當(dāng)輸入不合法時(shí),算法也能做相應(yīng)的處理,而不是產(chǎn)生莫名其妙的結(jié)果。
2.6.4 時(shí)間效率高 存儲(chǔ)量低
盡量滿足時(shí)間效率高和存儲(chǔ)量低的要求
?
2.7 算法效率的度量方法
2.7.1 事后統(tǒng)計(jì)方法
通過設(shè)計(jì)好的測(cè)試程序和數(shù)據(jù),利用計(jì)算機(jī)計(jì)時(shí)器對(duì)不同算法編制的程序的運(yùn)行時(shí)間進(jìn)行比較,從而確定算法效率的高低。
有很大缺陷:費(fèi)時(shí)費(fèi)力,依賴軟硬件、測(cè)試程序設(shè)計(jì)困難,一版不采納
2.7.2 事先分析估算方法
指在計(jì)算機(jī)程序編制前,依照統(tǒng)計(jì)方法對(duì)算法進(jìn)行估算。
一個(gè)程序的運(yùn)行時(shí)間,依賴于算法的好壞和問題的輸入規(guī)模(輸入量的多少)
?
2.8 函數(shù)的漸進(jìn)增長(zhǎng)
判斷一個(gè)算法的效率時(shí),函數(shù)中的常數(shù)和其他次要項(xiàng)常常可以忽略,而應(yīng)該關(guān)注主項(xiàng)的階數(shù)(最高階項(xiàng))
?
2.9 算法時(shí)間復(fù)雜度
2.9.1 定義
語(yǔ)句執(zhí)行總數(shù)T(n)是關(guān)于問題規(guī)模n的函數(shù)。進(jìn)而分析T(n)隨n的變化情況并確定T(n)的數(shù)量級(jí)。
也就是算法的時(shí)間量度,記作:T(n) = O(f(n));它表示隨問題規(guī)模n的增大,算法執(zhí)行時(shí)間的增長(zhǎng)率和f(n)的增長(zhǎng)率相同。稱作算法的漸進(jìn)時(shí)間復(fù)雜度,簡(jiǎn)稱時(shí)間復(fù)雜度。
其中f(n)是問題規(guī)模n的某個(gè)函數(shù)。
?
這樣用大寫O()來體現(xiàn)算法時(shí)間復(fù)雜度的記法,稱為大O記法。
一般隨著n的增大,T(n)增長(zhǎng)最慢的算法稱為最優(yōu)算法
?
比如
O(n),線性階
O(1),常數(shù)階
O(n2),平方階
?
2.9.2 推導(dǎo)大O階方法
如下:
1)用常數(shù)1取代運(yùn)行時(shí)間中所有加法常數(shù)
2)在修改后的運(yùn)行次數(shù)函數(shù)中,只保留最高階項(xiàng)
3)若最高階項(xiàng)存在且不是1,則去除這個(gè)像相乘的常數(shù)
?
2.9.3 常數(shù)階
與n的大小無關(guān),執(zhí)行時(shí)間恒定的算法,我們稱之為具有O(1)的時(shí)間復(fù)雜度。也叫常數(shù)階
?
2.9.4 線性階
隨著n增大,執(zhí)行次數(shù)線性增大。比如一個(gè)for循環(huán)。
要分析算法的復(fù)雜度,關(guān)鍵是要分析循環(huán)結(jié)構(gòu)的運(yùn)行情況
for(i = 0; i<n; i++ ){……}
?
2.9.5 對(duì)數(shù)階
比如:
int count = 1;
while(count < n)
{
???????? count = count * 2;
}
?
每次乘以2之后,就巨鹿n更近了一分。
也就是說有多少個(gè)2相乘大于n就會(huì)退出循環(huán)。2x=n,x=log2n;
所以這個(gè)循環(huán)的時(shí)間復(fù)雜度為O(logn)
2.9.6 平方階
注意只需要計(jì)算最高階就好了,兩個(gè)for循環(huán)嵌套就是O(n2)。
如果兩個(gè)for循環(huán)嵌套再加上一個(gè)嵌套的for循環(huán),時(shí)間復(fù)雜度依然是 O(n2)。
?
2.10 常見的時(shí)間復(fù)雜度
?
?
O(n3) O(2n) O(n!) 過大的n會(huì)使得結(jié)果變得非常大。這樣是不現(xiàn)實(shí)的,一般不去討論它。
?
2.11 最壞情況與平均情況
最壞情況運(yùn)行時(shí)間是一種保證,那就是運(yùn)行時(shí)間將不會(huì)再壞了。在應(yīng)用中,這是一種最重要的需求,通常,除非特別指定,我們提到的運(yùn)行時(shí)間都是最壞情況的運(yùn)行時(shí)間
?
平均運(yùn)行時(shí)間是所有情況中最有意義的,因?yàn)樗瞧谕倪\(yùn)行時(shí)間。
?
對(duì)時(shí)間復(fù)雜度的分析主要有上面兩種,一般在沒有特殊說明的情況下都是指最壞時(shí)間復(fù)雜度。
?
2.12 算法空間復(fù)雜度
算法的空間復(fù)雜度通過計(jì)算算法所需的存儲(chǔ)空間實(shí)現(xiàn),算法空間復(fù)雜度的計(jì)算公式記作:S(n)=O(f(n))。n為問題的規(guī)模,f(n)為語(yǔ)句關(guān)于n所占存儲(chǔ)空間的函數(shù)。
?
?
第三章 線性表
?
3.2 線性表的定義
線性表:零個(gè)或多個(gè)數(shù)據(jù)元素的有限序列
?
首先,是一個(gè)序列(元素之間是有順序的),而且是有限的。
比如:a1,a2,a3……an-1,an。
ai-1是ai的直接前驅(qū)元素,ai+1是ai的直接后繼元素
n定義為線性表的長(zhǎng)度,當(dāng)n為0 的時(shí)候,稱為空表
?
3.3 線性表的抽象數(shù)據(jù)類型
?
?
上面這些是最基本的一些操作,實(shí)際情況會(huì)復(fù)雜一點(diǎn)。
?
3.4 線性表的順序存儲(chǔ)結(jié)構(gòu)
定義:指用一段地址連續(xù)的存儲(chǔ)單元依次存儲(chǔ)線性表的數(shù)據(jù)元素
3.4.2 順序存儲(chǔ)方式
可以用C語(yǔ)言的一維數(shù)組來實(shí)現(xiàn)順序存儲(chǔ)結(jié)構(gòu)
順序存儲(chǔ)結(jié)構(gòu)需要三個(gè)屬性:
1)存儲(chǔ)空間的起始位置:數(shù)組data,它的位置就是存儲(chǔ)空間的存儲(chǔ)位置
2)線性表的最大存儲(chǔ)容量:數(shù)組長(zhǎng)度
3)線性表的當(dāng)前長(zhǎng)度:
?
3.4.3 數(shù)據(jù)長(zhǎng)度和線性表長(zhǎng)度的區(qū)別
數(shù)組的長(zhǎng)度是存放線性表的存儲(chǔ)空間的長(zhǎng)度,存儲(chǔ)分配后一般就不變了。
線性表的長(zhǎng)度是線性表中數(shù)據(jù)元素的個(gè)數(shù),插入刪除會(huì)影響這個(gè)值。
?
3.4.4 地址計(jì)算方法
存儲(chǔ)器中每個(gè)存儲(chǔ)單元都有自己的編號(hào),這個(gè)編號(hào)稱為地址。
?
3.5 順序存儲(chǔ)結(jié)構(gòu)的插入與刪除
3.5.1 獲得元素操作
就是將線性表中的第i個(gè)位置元素值返回
3.5.2 插入操作
基本思路:
1)插入位置不合理,拋出異常
2)線性表長(zhǎng)度大于等于數(shù)組長(zhǎng)度,拋異常或者動(dòng)態(tài)增加容量
3)從最后一個(gè)開始往前遍歷,分別將它們向后挪一位。arr[i+1] = a[i];
4)將要插入元素填入位置i處
5)表長(zhǎng)加1
?
3.5.3 刪除操作
基本思路:
1)若位置不合理,拋異常
2)取出刪除元素
3)從刪除元素的位置到末尾,全部往前移動(dòng)一個(gè)位置
4)表長(zhǎng)減1
3.5.4 線性表順序存儲(chǔ)的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):速度快 無需為表示表中元素之間的邏輯關(guān)系增加額外的存儲(chǔ)空間(鏈表需要next)
缺點(diǎn):插入刪除都需要移動(dòng)大量元素 長(zhǎng)度變化大時(shí)難以缺點(diǎn)存儲(chǔ)空間 造成存儲(chǔ)空間的碎片
?
3.6 線性表的鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)
3.6.1 順序存儲(chǔ)結(jié)構(gòu)不足的解決方法
讓每個(gè)元素知道它下一個(gè)元素的位置
3.6.2 線性表鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)定義
順序結(jié)構(gòu)中每個(gè)數(shù)據(jù)元素只要存數(shù)據(jù)元素信息就可以了。
鏈?zhǔn)浇Y(jié)構(gòu)還需要存儲(chǔ)它的后繼元素的地址。
存儲(chǔ)數(shù)據(jù)元素信息的域稱為數(shù)據(jù)域,存儲(chǔ)后繼位置的域稱為指針域
鏈表中第一個(gè)節(jié)點(diǎn)的存儲(chǔ)位置叫做頭指針。
有時(shí)會(huì)在單鏈表的第一個(gè)節(jié)點(diǎn)前附設(shè)一個(gè)節(jié)點(diǎn),稱為頭結(jié)點(diǎn)。頭結(jié)點(diǎn)的數(shù)據(jù)域可以不存儲(chǔ)任何信息。
3.6.3 頭指針與頭結(jié)點(diǎn)的異同
頭指針:
1)頭指針是鏈表指向第一個(gè)節(jié)點(diǎn)的指針。(若鏈表有頭結(jié)點(diǎn),則是指向頭結(jié)點(diǎn)的指針)
2)頭指針具有標(biāo)識(shí)作用,座椅常用頭指針冠以鏈表的名字
3)無論鏈表是否為空,頭指針均不為空。頭指針是鏈表的必要元素
頭結(jié)點(diǎn):
1)為了操作的同一個(gè)方便而設(shè)立的,放在第一元素的節(jié)點(diǎn)之前,其數(shù)據(jù)域一般無意義
2)有了頭結(jié)點(diǎn),對(duì)在第一元素節(jié)點(diǎn)前插入節(jié)點(diǎn)和刪除第一節(jié)點(diǎn),就跟對(duì)其他結(jié)點(diǎn)一樣了
3)頭結(jié)點(diǎn)不一定是鏈表必須要素。
?
頭結(jié)點(diǎn)的指針域存儲(chǔ)執(zhí)行第一個(gè)節(jié)點(diǎn)的指針。我覺得這個(gè)指針就是頭指針。
?
?
3.7 單鏈表的讀取
獲得鏈表第i個(gè)數(shù)據(jù)的算法思路:
1)聲明一個(gè)節(jié)點(diǎn)p指向鏈表的第一個(gè)節(jié)點(diǎn),初始化j從1 開始
2)j<i時(shí)就遍歷鏈表,p向后移動(dòng),不斷指向下一結(jié)點(diǎn)。j++
3)若到鏈表末尾p為空,則第i個(gè)元素不存在。
4)否則查找成功
?
3.8 單鏈表的插入與刪除
注意插入和刪除都需要找到對(duì)應(yīng)位置的那個(gè)結(jié)點(diǎn),這個(gè)很重要
3.8.1 單鏈表的插入
大概是這樣子:
?
?
先將p的后繼結(jié)點(diǎn)改成s的后繼結(jié)點(diǎn)。再把s變成p的后繼結(jié)點(diǎn)
s->next = p->next;
p->next = s;
3.8.2 單鏈表的刪除
大概是這樣子,假設(shè)需要?jiǎng)h除q:
?
?
將p的后繼結(jié)點(diǎn)指向q的后繼結(jié)點(diǎn),再把q的資源回收了。
p->next=q->next;
free(q);
?
對(duì)于插入或刪除數(shù)據(jù)越頻繁的操作,單鏈表的效率優(yōu)勢(shì)就越明顯。
時(shí)間復(fù)雜度是O(1)。
順序存儲(chǔ)的則是O(n)
?
3.9 單鏈表的整表創(chuàng)建
基本思路:
1)聲明一結(jié)點(diǎn)p和計(jì)數(shù)器變量i
2)初始化空鏈表L
3)L 的頭結(jié)點(diǎn)的指針指向NULL(建立帶頭結(jié)點(diǎn)的單鏈表)
4)循環(huán),就可以插入數(shù)據(jù)了
?
3.10 單鏈表的整體刪除
思路:
1)聲明結(jié)點(diǎn)p和q
2)將第一個(gè)節(jié)點(diǎn)賦給p
3)循環(huán):將下一結(jié)點(diǎn)賦給q,釋放q,將q賦給p。
?
Node *p = L->head;
Node *temp;
while(p)
{
? q = p->next;
free(p);
p=q;
}
free(head);
?
3.11 單鏈表結(jié)構(gòu)順序存儲(chǔ)和鏈?zhǔn)酱鎯?chǔ)的優(yōu)缺點(diǎn)
?
?
經(jīng)驗(yàn)性結(jié)論:
1)需要頻繁查找,很少插入刪除。可以用順序存儲(chǔ)。
需要頻繁插入刪除,則用鏈?zhǔn)酱鎯?chǔ)
2)對(duì)于未知元素個(gè)數(shù),最好用單鏈表
?
3.12 靜態(tài)鏈表
用數(shù)組描述的鏈表叫做靜態(tài)鏈表。這種描述方法還被叫做游標(biāo)實(shí)現(xiàn)法。
數(shù)組里的元素由兩個(gè)數(shù)據(jù)域組成,data和next。也就是說數(shù)組的每個(gè)下標(biāo)都對(duì)應(yīng)一個(gè)data和一個(gè)next。
數(shù)據(jù)域data用來存放數(shù)據(jù)元素。
而游標(biāo)next相當(dāng)于單鏈表中的next指針。
?
以int為例:
結(jié)點(diǎn)是
struct Node
{
???????? int data; // 數(shù)據(jù)域
???????? int next; // 游標(biāo)next,相當(dāng)于next指針,指向下一個(gè)結(jié)點(diǎn)再數(shù)組的下標(biāo)。
};
?
一個(gè)靜態(tài)鏈表就是相當(dāng)于一個(gè)結(jié)構(gòu)體數(shù)組。
Node slink[1000];?
這樣對(duì)鏈表的操作就變成了移動(dòng)游標(biāo)了。
插入數(shù)據(jù)還是放在末尾,但是插入位置的那個(gè)結(jié)點(diǎn)的游標(biāo)就要指向最后,要插入的結(jié)點(diǎn)的游標(biāo)指向之前插入位置的那個(gè)結(jié)點(diǎn)指向的下一個(gè)。
?
注意:這個(gè)鏈表的通過游標(biāo)排序的。
第一個(gè)結(jié)點(diǎn)的游標(biāo)在數(shù)組的最后一個(gè)位置的next。
鏈表的最后一個(gè)節(jié)點(diǎn)的next為0;
數(shù)組的第一個(gè)存儲(chǔ)空間存的是(當(dāng)前數(shù)據(jù)個(gè)數(shù)+1):若有1個(gè)數(shù)據(jù),這里的next為2.
2個(gè)數(shù)據(jù),則為3.? 3個(gè)數(shù)據(jù)則為4。用來插入數(shù)據(jù)時(shí)找空間存放。
?
遍歷是這樣遍歷的:
int count = 0;
int first = arr[MAXSIZE - 1];
while(first)
{
???????? // printf arr[first].data;
???????? first = arr[first].next; // 這里相當(dāng)于往下移動(dòng)
???????? cout++; // 統(tǒng)計(jì)個(gè)數(shù)
}
?
插入操作:
假設(shè)在需要在鏈表的第i個(gè)位置插入(注意這里是鏈表的位置,而不是數(shù)組的下標(biāo)):
需要找到它前一個(gè)結(jié)點(diǎn)的next。
int k = MAXSIXE – 1; //這里是起點(diǎn)
for(int I = 1; I < index; I++)
{
???????? k = arr[k].next;
}
找到了之后找位置存放新的結(jié)點(diǎn),就是
j = arr[0].next;
更新
if(arr[0].next)
{
arr[0].next = arr[j].next;
}
這里插入數(shù)據(jù)
arr[j].data = inputdata;
arr[j].next = arr[k].next;
arr[k].next = j;
?
優(yōu)點(diǎn):插入刪除時(shí)只需要修改游標(biāo),不需要移動(dòng)元素。改進(jìn)了順序結(jié)構(gòu)中插入刪除需要大量移動(dòng)元素的缺點(diǎn)
缺點(diǎn):還是難以確定長(zhǎng)度,失去了順序存儲(chǔ)結(jié)構(gòu)隨機(jī)存取的特性。
?
下面是一個(gè)雙鏈表的例子:
http://www.cnblogs.com/xcywt/p/8039607.html
轉(zhuǎn)載于:https://www.cnblogs.com/xcywt/p/8423936.html
總結(jié)
以上是生活随笔為你收集整理的《大话数据结构》一些基础知识的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring Data JPA中文文档[
- 下一篇: 静态代理和JDK动态代理