基本算法——排序算法

来源:互联网 发布:网络集线器怎么用 编辑:程序博客网 时间:2024/06/06 00:20

一、 插入排序

InsertSort(A, p, q)1 for i <- p+1 to q2 do x <- A[i]3 for j <- i-1 to p4 do if A[j] > x5  then A[j+1] <- A[j]6 A[j+1] <- x

算法复杂度:O(n^2)


折半插入排序:总得算法复杂度没变,但是查找插入位置(比较)的时间减少了。算法复杂度:O(n^2)。

BInsertSort(SqList *L){for(int i = 1; i < L.length(); ++i){int low = 0, high = i-1;int x = L[i];while(low <= high){int m = (low + high)/2;if(x < L[m]) high = m-1;else low = m+1;}for(int j = i-1; j >= high + 1; j--)L[j+1] = L[j]L[high+1] = x;}}


二、 希尔排序

ShellInsert(SqList &L, int dk){for(int i = dk+1; i <= L.length(); ++i){int x = L[i];int j = i-dk;while(j > 0 && L[j] > x) L[j+dk] = L[j];L[j+dk] = x;}}ShellSort(SqList &L, int delt[]){for(int i = 1; i < delt[0]; ++i)ShellInsert(L, delt[i]);}

希尔排序的复杂度难以分析。


三、 快速排序

int Partition1(A, p, r){int x = A[r];int i = p-1;for(int j = p; j < r; ++j)if(A[j] < x){int tmp = A[++i];A[i] = A[j];A[j] = tmp;}A[r] = A[++i];A[i] = x;return i;}int Partition2(A, low, high){int x = A[low];while(low < high){while(low < high && A[high] >= x)--high;A[low] = A[high];while(low < high && A[low] <= x) ++low;A[high] = A[low];}A[low] = x;return low;}int QuickSort(A, low, high){if(low < high){int m = Partition(A, low, high);QuickSrot(A, low, m-1);QuickSort(A, m+1, high);}}

快速排序的平均时间复杂度为O(nlongn),最坏情况下复杂度为O(n^2)


四、选择排序和堆排序

1. 简单选择排序

void SelectSort(A){for(int i = 0; i < A.length(); ++i){int j = SelectMin(A, i);if(j != i){int tmp = A[i];A[i] = A[j];A[j] = tmp;}}}
简单选择排序的时间复杂度为O(n^2)

2. 树形选择排序:

需要较多的额外空间,与最大值进行比较等多余的计算。


3. 堆排序

//已知H[s..m]除H[s]外,都满足(大顶)堆的定义,将H[s...m]调整,使之满足堆的定义HeapAdjust(H, s, m){int key = H[s];int i = s;for(int j = s*2; j <= m; j *= 2){if(j < m && H[j] < H[j+1])++jif(key >= H[j])break;H[i] = H[j];i = j;}H[i] = key;}HeapSort(H){for(int i = H.length/2; i > 0; --i)HeapAdjust(H, i, H.length);for(int i = H.length; i > 0; --i){int tmp = H[i];H[i] = H[1];H[1] = tmp;HeapAdjust(H, 1, i-1);}}
算法的时间复杂度为:O(nlogn),即使在最坏情况下堆排序的时间复杂度也为O(nlogn),仅需要一个辅助空间。

五、 归并排序

void Merge(int A[], int B[], int &C[]){for(int k = 0, i = 0, j = 0; i < A.length && j < B.length; ++k){if(A[i] <= B[j]) C[k] = A[i++];else C[k] = B[j++];}while(i < A.length)C[k++] = A[i++];while(j < B.length)C[k++] = A[j++];}void MergeSort(int A[], int &C[], int m, int n){if(m == n) C[m] = A[m];else{int mid = (m+n)/2;MSort(A, C1, m, mid);MSort(A, C2, mid+1, n);Merge(C1,C2, C);}}

归并排序时间复杂度为O(nlogn),空间复杂度为O(n).



六、 基数排序
基数排序不需要关键字的比较。

1. 计数排序

  1. Count-Sort(A, B, k)  
  2. for i <-- 0 to k  
  3. 2   do C[i] <-- 0  
  4. for i <-- 1 to length[A]  
  5. 4   do C[A[i]] <-- C[A[i]] + 1  
  6. for i <-- 1 to k  
  7. 6   do C[i] <-- C[i-1] + C[i]  
  8. for j <-- length[A] downto 1  
  9. 8   do B[C[A[j]]] <-- A[j]  
  10. 9       C[A[j]] <-- C[A[j]] - 1  

 计数排序时间代价:Θ(k+n), 实践中当k=O(n)时,运行时间为O(n)。

2. 基数排序

  1. Radix-Sort(A, d)  
  2. for i <-- 1 to d  
  3. 2   do use a stable sort to sort array A on digit i 

七、 内部排序算法比较

下面是一个总的表格,大致总结了我们常见的所有的排序算法的特点。

排序法平均时间最差情形稳定度额外空间备注冒泡O(n2)    O(n2)稳定O(1)n小时较好交换    O(n2)    O(n2)不稳定O(1)n小时较好选择O(n2)O(n2)不稳定O(1)n小时较好插入O(n2)O(n2)稳定O(1)大部分已排序时较好基数O(logRB)O(logRB)稳定O(n)

B是真数(0-9),

R是基数(个十百)

ShellO(nlogn)O(ns) 1<s<2不稳定O(1)s是所选分组快速O(nlogn)O(n2)不稳定O(nlogn)n大时较好归并O(nlogn)O(nlogn)稳定O(1)n大时较好O(nlogn)O(nlogn)不稳定O(1)n大时较好




0 0
原创粉丝点击