算法的概念和性質略過算法
算法的複雜度數組
例子 | 時間複雜度 | 術語 |
---|---|---|
5201314 | O(1) | 常數階 |
3n+4 | O(n) | 線性階 |
3n²+4n+5 | O(n²) | 平方階 |
3log2n+4 | O(logn) | 對數階 |
2n+3nlog2n+14 | O(nlogn) | nlogn階 |
n3+2n2+4n+6 | O(n3) | 立方階 |
2n | O(2n) | 指數階 |
O(1) < O(logn) < O(n) < O(nlogn) < O(n2) < O(n3) < O(2n) < O(n!) < (nn)數據結構
複雜度分析法則學習
1)單段代碼看高頻:好比循環。
2)多段代碼取最大:好比一段代碼中有單循環和多重循環,那麼取多重循環的複雜度。
3)嵌套代碼求乘積:好比遞歸、多重循環等
4)多個規模求加法:好比方法有兩個參數控制兩個循環的次數,那麼這時就取兩者複雜度相加。code
時間複雜度分析對象
只關注循環執行次數最多的一段代碼
加法法則:總複雜度等於量級最大的那段代碼的複雜度
乘法法則:嵌套代碼的複雜度等於嵌套內外代碼複雜度的乘積blog
幾個常見例子遞歸
線性階it
int i, n = 100, sum = 0; for(i = 0; i<n; i++) { sum = sum + i; }
上面這段代碼的循環複雜度爲O(n),由於循環體中的代碼須要執行n次io
平方階
int i,j,n = 100; for(i = 0; i < n; i++) { for(j = 0; j < n; j++) { printf("aaaaaaaaaaaa\n"); } }
上面這段代碼的時間複雜度爲O(n²)
int i,j,n = 100; for(i = 0; i < n; i++) { for(j = i; j < n; j++) { pringtf("aaaaaaaaaaaaaa\n"); } }
分析,因爲當i=0時,內循環執行了n次,當i=1時,內循環則執行n-1次。。。。。。當i=n-1時,內循環執行1次,因此總的執行次數應該是n+(n-1)+(n-2)+...+1=n(n+1)/2用上面的簡化方法來簡化½n²+½n,這個式子中沒有常數項不用考慮第一條,根據第二條只保留最高項,去掉½n這一項,根據第三條去掉與最高項相乘的常數½,最終獲得O(n²)
對數階
int i = 1, n = 100; while(i < n) { i = i*2; }
因爲每次i2以後就距離n更近一步,假設有x個2相乘後大於或等於n,則會退出循環。因而由2^x=n
獲得x=log2n,因此這個循環的時間複雜度爲O(logn)。
抽象數據類型的定義格式以下:
ADT抽象數據類型名{ 數據對象:(數據對象的定義〉 數據關係:(數據關係的定義〉 基本操做:(基本操做的定義〉 }ADT抽象數據類型名
基本操做的定義格式爲:
基本操做名(參數表)
初始條件:(初始條件描述〉
操做結果:(操做結果描述〉
基本操做有兩種參數: 賦值參數只爲操做提供輸入值;引用參數以"&"打頭,除可提供輸
入值外,還將返回操做結果。
對非空的線性表或線性結構, 其特色是:
ADT List{ 數據對象: D={ai|ai E ElemSet, i=l, 2, …n, n>=0} 數據關係: R=(<ai-1,ai> ai-1,aiE D, i=2, …, n} 基本操做: InitList (&L) 操做結果:構造一個空的線性表L。 DestroyList(&L) 初始條件:線性表L已存在。 操做結果:銷燬線性表L。 ClearList (&L) 初始條件:線性表L已存在。 操做結果:將L重置爲空表。 ListEmpty(L) 初始條件:線性表L已存在。 操做結果:若L爲空表, 則返回true, 不然返回false。 ListLength(L) 初始條件:線性表L已存在。 操做結果:返回L中數據元素個數。 GetElem(L,i,&e) 初始條件:線性表L巳存在 操做結果:用e返回L中第i個數據元素的值。 LocateElem(L,e) 初始條件:線性表L已存在。 操做結果:返回L中第1個 值與e相同的元素在 L中的位置 。若這樣的數據元素不存在 , 則返回值爲0。 PriorElem(r,,cur_e,&pre_e) 初始條件:線性表L已存在。 操做結果:若cur_e是L的數據元素,且不是第一個,則用pre_e返回其前驅,不然操做失敗,pre_e無定義。 NextElem(L,cur_e,&next_e) 初始條件:線性表L已存在。 操做結果:若cur_e是L的數據元素,且不是最後一個,則用next_e返回其後繼,不然操做失敗,next_e無定義。 Listinsert(&L,i,e) 初始條件:線性表L已存在,且1:,s;i:os;ListLength (L) +l。 操做結果:在 L中第1個位置以前插入新的數據元素 e, L的長度加1。 ListDelete(&L,i) 初始條件:線性表L已存在且非空 ,且l:os;i:os;ListLength(L)。 操做結果:刪除L的第1個數據元素,L的長度減1。 TraverseList(L) 初始條件:線性表L已存在。 操做結果:對線性表L進行遍歷,在遍歷過程當中對 L的每一個結點訪問一次。 ) ADT List
//----- 順序表的存儲結構----- //
#define MAXSIZE 100 //順序表可能達到的最大長度 typedef struct { ElemType *elem //聲明瞭一個名爲elem的長度不肯定的數組,也叫「動態數組」,也能夠聲明爲 //data[MAXSIZE]; int Length; //當前長度 }SqList; //順序表的結構類型爲SqList
算法步驟::
算法描述:
Status InitList(SqList &L){ //構造一個空的順序表 L.elem=(ElemType *)malloc(MAXSIZE*sizeof(ElemType)); //爲順序表分配空間,也能夠用new if (!L.elem) exit(OVERFLOW); //分配空間失敗,退出 L.Length=0; //初始化長度爲0 return OK; }
算法步驟 :
算法描述:
Status GetElem(SqList L,int i,ElemType &e){ if (i<1||i>L.Length) return ERROR; //判斷數據不合理 e=L.elem[i-1]; return OK; }
算法步驟 :
從第一個元素起,依次和 e相比較,若找到與 e相等的元素 L.elem[i], 則查找成功,返回該元素的位置 i+l。
若查遍整個順序表都沒有找到,則查找失敗, 返回0。
算法描述:
int LocateELem(SqList L,ElemType e){ //在順序表1中查找值爲e的數據元素, 返回其序號 for (i=0;i<L.Length;i++){ if (L.elem[i]==e) return i+1; //查找成功 } return 0; //查找失敗 }
算法步驟 :
算法描述:
Status ListInit(SqList &L,int i,ElemType e){ if (i<1||i>L.Length+1) return ERROR; //插入位置不合理 if (L.Length==MaixSize) return ERROR; //順序表已滿 for (j=L.Length-1;j>=i-1;j--){ L.elem[j+1]= L.elem[j]; //從後向前依次後移 } L.elem[i-1]=e //插入新元素 L.Length++; //長度加1 return OK; }
算法步驟 :
算法描述:
Status ListDelete(SqList &L,int i){ if (i<1||i>L.Length) return ERROR; //插入位置不合理 for (j=i;j<=L.Length-1;j++){ L.elem[j-1]=L.elme[j]; } --L.Length; return OK; }
#include <stdio.h> #include <stdlib.h> #define Size 5 typedef struct Table{ int * head; int length; int size; }table; //初始化順序表 table initTable(){ table t; t.head=(int*)malloc(Size*sizeof(int)); if (!t.head) { printf("初始化失敗"); exit(0); } t.length=0; t.size=Size; return t; } //添加元素 table addTable(table t,int elem,int add) { if (add>t.length+1||add<1) { printf("插入位置有問題"); return t; } if (t.length>=t.size) { t.head=(int *)realloc(t.head, (t.size+1)*sizeof(int)); if (!t.head) { printf("存儲分配失敗"); } t.size+=1; } for (int i=t.length-1; i>=add-1; i--) { t.head[i+1]=t.head[i]; } t.head[add-1]=elem; t.length++; return t; } //刪除元素 table delTable(table t,int add){ if (add>t.length || add<1) { printf("被刪除元素的位置有誤"); exit(0); } for (int i=add; i<t.length; i++) { t.head[i-1]=t.head[i]; } t.length--; return t; } //查找元素 int selectTable(table t,int elem){ for (int i=0; i<t.length; i++) { if (t.head[i]==elem) { return i+1; } } return -1; } //修改元素 table amendTable(table t,int elem,int newElem){ int add=selectTable(t, elem); t.head[add-1]=newElem; return t; } //遍歷輸出 void displayTable(table t){ for (int i=0;i<t.length;i++) { printf("%d ",t.head[i]); } printf("\n"); } int main(){ table t1=initTable(); for (int i=1; i<=Size; i++) { t1.head[i-1]=i; t1.length++; } printf("原順序表:\n"); displayTable(t1); printf("刪除元素1:\n"); t1=delTable(t1, 1); displayTable(t1); printf("在第2的位置插入元素5:\n"); t1=addTable(t1, 5, 2); displayTable(t1); printf("查找元素3的位置:\n"); int add=selectTable(t1, 3); printf("%d\n",add); printf("將元素3改成6:\n"); t1=amendTable(t1, 3, 6); displayTable(t1); return 0; }
輸出:
原順序表: 1 2 3 4 5 刪除元素1: 2 3 4 5 在第2的位置插入元素5: 2 5 3 4 5 查找元素3的位置: 3 將元素3改成6: 2 5 6 4 5