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