演算法分析基本概念
二分搜尋
Linearsearch
/*
* 輸入:n個元素的陣列A[1...n]、x
* 輸出:如果x=A[j]&&1<=j<=n,則輸出j,否則輸出0
*/
int Linearsearch(int *A,int x, int n){
int j=0;
while (j<n&&x!=A[j]){
j++;
}
if(x==A[j])return j;
return 0;
}
Binarysearch
/*
* 輸入:n個元素的升序陣列A[1...n]、x
* 輸出:如果x=A[j]&&1<=j<=n,則輸出j,否則輸出0
*/
int Binarysearch(int *A, int x, int n) {
int low = 1, high = n, j = 0;
while (low <= high && j == 0) {
int mid = (int) ((low + high) / 2);
if (x == A[mid])j = mid;
else if (x < A[mid])high = mid - 1;
else low = mid + 1;
}
return j;
}
要注意二分搜尋的輸入一定是一個升序的陣列,實質就是一個二叉搜尋樹(所以也把二分搜尋的執行描述為決策樹),對於一個大小為n的排序陣列,演算法Binarysearch執行比較的最大次數為int(logn)+1(如果輸入陣列不是遞增排好序的,則可在nlogn內對其進行排序後再進行二分搜尋)。
合併兩個已排序的表
/*
* 輸入:陣列A[1...m]和它的三個索引p,q,r,1<=p<=q<r<=m,p、q、r滿足A[p...q]、A[q+1...r]分別按照升序排列
* 輸出:合併兩個子陣列A[p...q]和A[q+1...r]的陣列A[p...r]
*/
void Merge(int *A, int p, int q, int r) {
int B[r + 1];//B[p...r]是輔助陣列
int s = p, t = q + 1, k = p;//s指向A[p...q]子陣列,t指向A[q+1...r]子陣列,k指向B陣列
while (s <= q && t <= r) {
if (A[s] <= A[t]) {
B[k] = A[s];
s++;
} else {
B[k] = A[t];
t++;
}
k++;
}
if (s = q + 1) {//說明s指向的陣列已經遍歷完了
for (int i = t; i <= r; ++i) {
B[k++] = A[i];
}
} else {
for (int i = s; i <= r; ++i) {
B[k++] = A[i];
}
}
for (int j = p; j <= r; ++j) {
A[j] = B[j];
}
}
設Merge演算法要合併兩個大小分別為n1和n2的陣列(n1
選擇排序
/*
* 輸入:n個元素的陣列A[1...n]
* 輸出:按非降序排列的陣列A[1...n]
*/
void SelectionSort(int *A, int n) {
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j <= n; ++j) {
if (A[i] > A[j]) {
int t = A[i];
A[i] = A[i];
A[i] = t;
}
}
}
}
演算法SelectionSort所需的元素比較次數為n(n-1)/2(n-1+n-2+n-3+…+2+1=n(n-1)/2),因為每次交換需要3次賦值,所以元素的賦值次數介於0到3(n-1)之間。
插入排序
思路
首先將第二個數與第一個數進行對比,如果第二個數比第一個數小,則將第二個數插入到第一個數之前,這樣保證前兩個數是有序的;
接下來將第三個數與前兩個數對比,比較的思路是先將第三個數存下來(記為x),然後將第三個數與第二個數比較,如果第二個數比第三個數大,則直接將第二個數向後移動一位,如果第二個數不比第三個數大,則說明此時前三個數都是有序的,因為之前前兩個數是有序的,比較到最後,將x放到第三個數比較的終止位置即可。以此類推,將後面的i個數分別其前面的i-1個數進行對比,並將其插入到第一個比其大的數前面,最後即可完成排序。
程式碼實現
/*
* 輸入:n個元素的陣列A[1...n]
* 輸出:按非降序排列的陣列A[1...n]
*/
void InsertionSort(int *A, int n) {
for (int i = 2; i <= n; ++i) {
int x = A[i];
int j = i - 1;
while (j > 0 && A[j] > x) {
A[j + 1] = A[j];
j--;
}
A[j + 1] = x;
}
}
執行演算法SelectionSort的元素比較次數在n-1到n(n-1)/2之間,元素賦值次數等於元素比較次數加上n-1.
自底向上合併排序
/*
* 輸入:n個元素的陣列A[1...n]
* 輸出:按非降序排列的陣列A[1...n]
*/
void Merge(int *A, int p, int q, int r);
void BottomUpSort(int *A, int n) {
int t = 1;
while (t < n) {
int s = t, t = 2 * s, i = 0;
while (i + t <= n) {
Merge(A, i + 1, i + s, i + t);
i = i + t;
}
if (i + s < n) {
Merge(A, i + 1, i + s, n);
}
}
}
用演算法BottomUpSort對n個元素的陣列進行排序,當n為2的冪時,元素比較次數在(nlogn)/2到nlogn-n+1之間。執行該演算法的元素賦值次數為2nlogn。
時間複雜性
O
前文提到演算法InsertionSort執行的運算次數至多為cn^2,其中c為某個適當選擇的正常數。這時我們說演算法InsertionSort的執行時間是O(n^2),說明當排序元素的個數等於或超過某個閾值n0時,對於某個常亮c,執行時間是cn^2,O符號描述的是一個上界但不一定是演算法的實際執行時間,比如當排序一個已經排序好的陣列時InsertionSort的執行時間就不是O(n^2)而是O(n)了。
Ω
相比於O,Ω描述的是演算法執行的下界,比如演算法InsertionSort的運算時間至少是cn,則稱演算法InsertionSort的執行時間是Ω(n),即無論何時,當被排序的元素個數等於或超過某一個閾值n0時,對於某個常數c,演算法的執行時間至少是cn。
Senta
Senta描述的是一個確切界限,如果對於任意大小等於或超過某一閾值n0的輸入,如果執行時間在c1g(n)和c2g(n)之間,則稱演算法的執行時間是Senta(g(n))。
複雜性類與 o 符號
o符號
O 符號給出的上界可以是“緊”的,也可以是非“緊”的。
2* n^ 2 =O ( n^ 2 ) 是漸近性緊邊界
2 *n = O ( n^ 2 ) 不是漸近性緊邊界
o 符號就用來表示不是漸近性緊邊界的上界
舉例: 2 n = o ( n ) , 2 ^n != o ( n )
直觀上來說,在小 o 符號中, f ( n ) =o ( g ( n )) ,當 n 趨向於無窮大時, f (n ) 函式相當於 g (n ) 就變得不再重要了
即lim->+oof(n)/g(n)=0
w符號
用類比法來講,小 w符號相對於大 Ω符號的關係正如 o 符號相對於 O 符號的關係。
我們用小 w 符號來表示一個漸近性非緊密的下界。
比如:
(n^2)/2=w(n )
(n^2)/2!=w(n^2)
lim->+oof(n)/g(n)=oo
空間複雜性
我們把演算法使用的空間 定義 、為:為了求解問題的例項而執行的計算步驟所需要的記憶體空間,它不包括分配用來儲存輸入的空間(為了區分那些在整個計算過程中佔用了少於輸入空間的演算法)。
演算法的空間複雜性不可能超過執行時間的複雜性,因為每寫入一個記憶體單元都至少需要一定的時間。所以,如果用 T (n ) 和 S (n ) 分別代表演算法的時間複雜性和空
間複雜性,有: S ( n ) = O ( T ( n )) 。
最優演算法
如果可以證明任何一個求解問題 T的演算法必定是Ω ( f ( n )) ,那麼我們把在 O ( f ( n )) 時間內求解問題T的任何演算法都稱為問題 T的最優演算法。
如何估計演算法的執行時間
- 計算迭代次數
- 計算基本運算的頻度
一般來說,在分析一個演算法執行時間時,可以找出這樣一個元運算,它的頻率至少和任何其他運算的頻度一樣大,稱這樣的運算為基本運算。我們還可以放寬這個定義,把那些頻度和執行時間成正比的運算包括進來。
- 使用遞推關係
如果一個演算法本身是遞迴演算法,那麼計算這個演算法執行時間的函式通常也是遞迴的,即是指,這個函式的定義中引用了函式自身。即便一個演算法本身是非遞迴的,我們有時也可以用遞迴式來計算它的執行時間。
lim->+oof(n)/g(n)!=oo f(n)=O(g(n))
lim->+oof(n)/g(n)!=0 f(n)=Ω(g(n))
lim->+oof(n)/g(n)==c f(n)=Senta(g(n))
相關文章
- 演算法基本概念演算法
- 演算法的基本概念演算法
- 資料分析基本概念
- Thrift原理分析(一)基本概念
- 統計公差分析--正態分佈基本概念
- Spring啟動過程原始碼分析基本概念Spring原始碼
- 演算法分析演算法
- 神經網路圖的簡介(基本概念,DeepWalk以及GraphSage演算法)神經網路演算法
- 資料探勘(1):關聯規則挖掘基本概念與Aprior演算法演算法
- RocketMQ基本概念MQ
- Mysql基本概念MySql
- Kafka基本概念Kafka
- mongodb 基本概念MongoDB
- javascript:基本概念JavaScript
- Kafka 基本概念Kafka
- MQ 基本概念MQ
- 機器學習基本概念機器學習
- babel基本概念Babel
- 加解密演算法分析解密演算法
- 如何分析排序演算法排序演算法
- CryptCD 3演算法分析演算法
- SFR演算法原理分析演算法
- LL(1)分析演算法演算法
- RabbitMQ(1)---基本概念MQ
- Spring 基本概念Spring
- GacUI基本概念(一)UI
- redux的基本概念Redux
- Docker的基本概念Docker
- 程式的基本概念
- 基本概念及操作
- MySQL基本概念【一】MySql
- Oracle RAC基本概念Oracle
- lipaper-基本概念
- 微服務基本概念微服務
- 樹的基本概念
- 演算法分析__級數求和演算法
- 演算法分析__時間估算演算法
- 演算法分析__遞推方程演算法