经典常用算法/常用算法思维---附伪代码以及实现
本篇文章旨在分享一些常用算法的偽代碼以及部分算法的具體實現,后面也會更新我在刷算法題中學到的或者從別的地方看到的經典算法思維
本博客并不提供算法說明,算法證明,算法分析,算法測試等內容,只提供算法的偽代碼表示,在理解算法的前提下,很容易通過此文章了解并實現算法。
文章目錄
- 類別一:Sorting Algorithms(排序算法)
- Bucket Sort(桶排序)
- COUNTING_SORT(計數排序)
- RADIX_SORT(基數排序)
- INSERT_SORT(直接插入排序)
- MERGE_SORT(歸并排序)
- QUICK_SORT(快速排序)
- HEAP_SORT(堆排序)
- 類別二:BINARY TREE ALGORITHMS(二叉樹算法)
- TREE_SEARCH(二叉樹搜索)
- TREE_MINIMUM(查找BST最小值)
- TREE_MAXIMUM(查找BST最大值)
- TREE_INSERT(BST插入)
- TREE_DELETE(BST刪除)
- Minimum spanning tree(最小生成樹)
- MST_KRUSKAL(Kruskal生成樹算法)
- MST_PRIM(Prim生成樹算法)
- 類別三:Graph Algorithms(圖類算法)
- BFS(廣度優先搜索)
- DFS(深度優先搜索)
- DIJKSTRA(迪杰斯特拉算法)
- 類別四:模式匹配算法
- 樸素字符串匹配算法
- Rabin-Karp算法
- 基于有限狀態機的字符串匹配算法
- KMP 算法
- 類別五:常用算法思維
- 遞歸
- 分治算法
- 動態規劃
- 貪心算法
- 回溯算法
- 雙指針
- 滑動窗口
類別一:Sorting Algorithms(排序算法)
Bucket Sort(桶排序)
BUCKET_SORT(A) n = A.length let B[0...n-1] be a new array for i = 0 to n-1make B[i] an empty list for i = 1 to ninsert A[i] to B[A[i]] for i = 0 to nsort list B[i] with insertion sort concatenate the lists B[0]...B[n] together in orderCOUNTING_SORT(計數排序)
COUNTING_SORT(A,B,k) n = A.length let C[0...k] be a new array for i = 0 to kC[i] = 0 for i = 1 to nC[A[i]] = C[A[i]]+1 for i = 1 to kC[i] = C[i-1]+C[i] for i = n down to 1B[C[A[i]]] = A[i]C[A[i]] = C[A[i]]-1RADIX_SORT(基數排序)
RADIX_SORT(A,d) for i = 1 to buser a stable sort to sort array A on digit iexample use COUNTING_SORT:
COUNTING_SORT(A,exp) n = A.length let B[1...n] C[0...k] be new arrays for i = 0 to kC[i] = 0 for i = 1 to nC[(A[i]/exp)%10] = C[(A[i]/exp)%10] +1 for i = 1 to kC[i] = C[i-1] + C[i] for i = n down to 1B[C[(A[i])/exp]%10] = A[i]C[(A[i])/exp]%10] = C[(A[i])/exp]%10]-1 for i = n down to 1A[i] = B[i]RADIX_SORT(A,k) exp = 1 while (k/exp)%10!=0COUNTING_SORT(A,k)exp = exp*10INSERT_SORT(直接插入排序)
INSERT_SORT(A) for i = 2 to nkey = A[i]j = i-1while j > 0 and A[j]>keyA[j+1] = A[j]j = j -1A[j+1] = keyC語言實現
void insert_sort(int A[], int n) {int i = 0, j = 0;for (i = 1; i < n; i++){int key = A[i];for (j = i - 1; j >=0 && A[j] > key; j--){A[j + 1] = A[j];}A[j + 1] = key;} }MERGE_SORT(歸并排序)
MERGE_SORT(A,low,high) if low<highmid = (low+high)/2MERGE_SORT(A,low,mid-1)MERGE_SORT(A,mid,high)MERGE(A,low,high,mid)MERGE(A,low,high,mid) let LA[1..mid-low] RA[1...high-mid+1] be new arrays for i = 1 to mid-lowLA[i] = A[i+low] for j = 1 to high-mid+1RA[i] = A[i+mid-1] l = 1 r = 1 k = low while l<=i and r <= jif(LA[l]>RA[r])A[k++] = LA[l++]else A[k++] = RA[r++] while l<=iA[k++] = LA[l++] while r<=jA[k++] = RA[r++]C語言實現
void merge(int A[], int low, int mid, int high) {int i = 0, j = 0, k = 0;for (i = low; i <= high; i++){B[i] = A[i];}for (i = k = low, j = mid+1; i <= mid && j <= high; k++){if (B[i] < B[j]) A[k] = B[i++];else A[k] = B[j++];}while (j<=high){A[k++] = B[j++];}while (i <= mid){A[k++] = B[i++];} }void merge_sort(int A[], int low, int high) {if (low < high){int mid = (low + high) / 2;merge_sort(A, low, mid);merge_sort(A, mid + 1, high);merge(A, low, mid, high);} }QUICK_SORT(快速排序)
QUICK_SORT(A,p,r)if p<rq = PARTITION(A,p,r)QUICK_SORT(A,p,q-1)QUICK_SORT(A,q+1,r)PARTITION(A,p,r)i = p-1for j = p to r-1if A[j]<A[r]i = i+1exchange A[j] with A[i]exchange A[i+1] with A[r]return i+1C語言實現
int partition(int A[], int low, int high) {int pivot = A[low];while (low < high){while (low < high && A[high] > pivot) high--;A[low] = A[high];while (low < high && A[low] < pivot) low++;A[high] = A[low];}A[low] = pivot;return low; }void quick_sort(int A[], int low, int high) {if (low < high){int pivot = partition(A, low, high);quick_sort(A, low, pivot - 1);quick_sort(A, pivot + 1, high);} }HEAP_SORT(堆排序)
HEAP_SORT(A)BUILD_MAX_HEAP(A)for i = [A.length]/2 down to 1MAX_HEAPIFY(A,i)MAX_HEAPIFY(A,i) l = LEFT(i) r = RIGHT(i) if l <=A.heap-size and A[l]>A[i]largest = l else largest = i if r <= A.heap-size and A[r]> A[i]largest = r if largest != iexchange A[i] with A[largest]MAX_HEAPITY(A,largest)BUILD_MAX_HEAP(A) A.heap-size = A.length for i = A.heap-size/2 down to 1MAX_HEAPITY(A,i)C語言實現
void adjust_heap(int A[], int k, int len) {A[0] = A[k];for (int i = 2*k; i <= len; i *= 2){if (i < len && A[i] < A[i + 1]){i++;}if (A[0] >= A[i]){break;}else{A[k] = A[i];k = i;}}A[k] = A[0]; }void build_max_heap(int A[], int len) {for (int i = len / 2; i > 0; i--){adjust_heap(A, i, len);} }void heap_sort(int A[], int len) {build_max_heap(A, len);for (int i = len; i > 0; i--){swap(&A[1], &A[i]);adjust_heap(A, 1, i - 1);} }類別二:BINARY TREE ALGORITHMS(二叉樹算法)
TREE_SEARCH(二叉樹搜索)
TREE_SEARCH(x,k) while x!=NIL and k! = x.keyif k<x.keyx = x.leftelse x = x.right if x!=NILreturn xTREE_MINIMUM(查找BST最小值)
TREE_MINIMUM(x,k)whiel x!= NIL and k!=x.keyif k<x.keyx = x.leftelse x= x.right return xTREE_MAXIMUM(查找BST最大值)
TREE_MAXIMUM(x)while x.right != NILx = x.right return xTREE_INSERT(BST插入)
TREE_INSERT(T,z) y = NIL x = T.root while x!=NILy = xif z.key < x.keyx = x.leftelse x = x.right z.p = y if(y==NIL)T.root = z else if z.key > y.keyy.right = z else y.left = zTREE_DELETE(BST刪除)
TREE_DELETE(T,z) if z.left == NILTRANSPLANT(T,z,z.right) else if z.right == NILTRANSPLANT(T,z,z.left) else y = TREE_MINIMUM(z.right)if y.p!=zTRANSPLANT(T,y,y.right)y.right = z.righty.right.p = yTRANSPLANT(T,z,y)y.left = z.lefty.left.p = yTRANSPLANT(T,u,v) if u.p == NILT.root = v else if u == u.p.leftu.p.left = v else u.p.right = v if v!=NILv.p = u.pMinimum spanning tree(最小生成樹)
GENETRIC_MST(A,W) A = ? while A doesn't form a spanning treefind an edge(u,v) that is safe for AA = A∪(u,v) return AMST_KRUSKAL(Kruskal生成樹算法)
MST_KRUSKAL(G,w) A = ? for each vertex v ∈ G.VMAKE SET(v) sort the edges of G.E into nondecreasing order by weight w for each edge (u,v) ∈ G.V taken in nondecreasing order by weightif FIND-SET(u) != FIND-SET(v)A = A∪(u,v)UNION(u,v) return AMST_PRIM(Prim生成樹算法)
MST_PRIM(G,w,r) for each u ∈ G.Vu.key = ∞u.π = NIL r.key = 0 Q = G.V while Q != ?u = EXTRACT-MIN(Q)for each v∈G.Adj(u)if v∈Q and w(u,v)<v.keyv.π = uv.key = w(u,v)類別三:Graph Algorithms(圖類算法)
BFS(廣度優先搜索)
BFS(G,s) for each vertex u∈G.V-{s}u.color = WHITEu.d = ∞u.π = NIL s.color = GRAY s.d = 0 s.π = NIL Q= ? ENQUEUE(Q,s) while Q!=?u = DEQUEUE(Q)for each v ∈ G.Adj(u)v.color = GRAYv.d = u.d + 1v.π = uENQUEUE(Q,v)u.color = BLACKDFS(深度優先搜索)
DFS(G) for each vertex u ∈ G.Vu.color = WHITEu.π = NIL time = 0 for each vertex u ∈ G.Vif u.color = WHITEDFS-VISIT(G,u)DFS-VISIT(G,u) time = time +1 u.d = time u.color = GRAY for each v ∈ G.Adj(u)if v.color = WHITEDFS-VISIT(G, v) u.color = BLACK time = time +1 u.f = timeDIJKSTRA(迪杰斯特拉算法)
DIJKSTRA(G,w,s) S = ? Q = G.V while Q!= ?u = EXTRACT-MIN(Q)S = S ∪ {u};for each v ∈ Q.Adj(u)RELAX(u, v, w)RELAX(u,v,w) if v.d > u.d + w(u,v)v.d = u.d + w(u,v)v.π = u類別四:模式匹配算法
樸素字符串匹配算法
NAIVE-STRING-MATCHER(T, P)n = T.lengthm = P.lengthfor s = 0 to n-mif P[1...m] == T[s+1...s+m]print "Pattern occurs with shift"s預處理時間:0
時間復雜度:O((n-m+1)*m)
Rabin-Karp算法
RABIN-KARP-MATCHER(T, P)n = T.lengthm = p.lengthh = d^m-1 mod qp = 0t0 = 0//預處理for i = 1 to mp = (d*p + P[i]) mod qt_0 = (d*t_0 + T[i]) mod q//匹配for s = 0 to n-mif p == t_sif P[1..m] == T[s+1..s+m]print "Pattern occurs with shift"sif s < n-mt_(s+1) = (d*(t_s - T[s+1]*h) + T[s+m+1])mod q預處理時間O(m)
最壞時間復雜度O((n-m+1)*m)
一般時間復雜度O(n) + O(m(v + n/q))
基于有限狀態機的字符串匹配算法
FINITE-AUTOMATION-MATCHER(T, δ, m)//δ為狀態轉移函數n = T.lengthq = 0for i = 1 to nq = δ(q, T[i])if q == mprint "Pattern occurs with shift"s COMPUTE-TRANSITION-FUNCTION(P, ∑)//∑為字符串的字母表m = P.lengthfor q = 0 to mfor each character a ∈ ∑k = min(m+1, q+2)repeatk = k-1until P_k 是 P_qa的后綴δ(q,a) = kreturn δKMP 算法
KMP-MATCHER(T,P)n = T.lengthm = P.length//Π是后綴函數,Π(q) = max{k| k<q and P_k是P_q的后綴}Π = COMPUTE-PREFIX-FUNCTION(P)q = 0for i=1 to nwhile q > 0 and P[q+1]!=T[i]q = Π[q]if P[q+1] == T[i]q = q+1if q == mprint "Pattern occurs with shift"sq = Π[q] COMPUTE-PERFIX-FUNCTION(P)m = P.lengthlet Π[1..n] be a new arrayΠ[1] = 0k = 0for q = 2 to mwhile k > 0 and P[k+1] != P[q]k = Π[k]if P[k+1] == P[q]k = k+1Π[q] = kreturn Π類別五:常用算法思維
遞歸
void function(規模){if base_statereturn base_resultelse function(子規模) }分治算法
所謂分治算法就是將整個問題分解為子問題求解,再將子問題的解合并為原問題的解
不同于動態規劃算法和貪心算法,分支算法的子問題是不包含重疊子問題的,子問題的形式求解方法與原問題是一致的,只是規模不同
動態規劃
使用動態規劃之前,首先要確定問題是否具有最優子結構性質以及無后效應,總來的說就是是否符合最優性原則
最優子結構性質指的是整體問題的最優解包含其子問題的最優解
無后效應是指從現在所在的狀態往后所做的所有決策只于當前狀態有關,而與當前狀態之前的狀態或決策無關,并不關心當前狀態是怎么來的
最優性原則就是說無論初始狀態或者初始決策是什么,以后的決策一定相對于初始狀態構成一個最優決策序列
既然動態規劃解決問題,首先要根據問題畫出FSM(有限狀態機),搞清楚每個狀態的前一個狀態是什么,什么操作會導致什么狀態變化,然后根據FSM可以寫出狀態轉移方程,用代碼表示出狀態轉移方程即可。
dp[基本狀態] = 初始值 void dynamic_programming()for each 狀態∈狀態列表dp[狀態] = 擇優(前一個狀態做選擇1,前一個狀態做選擇2....)貪心算法
貪心算法和動態規劃算法有點像,首先都具有最優子結構性質,只不過貪心算法區別于動態規劃算法的一點就是貪心算法求解的問題需要具有貪心選擇性質
貪心選擇性質:整體的最優解可以通過一系列局部最優選擇,也就是貪心選擇來獲取
最優解 = 輸入序列[1…n]的一個子集
void recursive_greedy(問題,選擇列表, 解集)for each 選擇∈選擇列表if 選擇滿足局部最優解集 = 解集 ∪ 選擇recursive_greedy(子問題, 選擇列表, 解集)回溯算法
void backtrack(解集, 選擇序列, 選擇列表)if 滿足結束條件解集 = 解集 ∪ 選擇序列for each 選擇∈選擇列表//做選擇選擇序列 = 選擇序列 ∪ 選擇//下一步backtrack(解集, 選擇序列, 選擇列表)//撤銷選擇選擇序列 = 選擇序列 - 選擇雙指針
滑動窗口
總結
以上是生活随笔為你收集整理的经典常用算法/常用算法思维---附伪代码以及实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 你必须会的启发式搜索算法--A*算法
- 下一篇: JVM自动化的内存分配与内存回收