一、堆排序 : 原址排序 复杂度: nlg n
最大堆: A[parent(i)] > = A[i]
最小堆: A[parent(i)] < = A[i]
除了最底层外,其它层都是满状态。
判断节点是否为叶节点: [n/2]+1,.....n 均为叶节点
//Max-heapify(A,i) : A为一个 假定 left(i) right(i)的二叉树都是最大堆 。 但是A[i]可能小于孩子 。 时间复杂度为: o(h) //build_max_heap(A,len) : 将一个数组转换为 最大堆(从底向上的建堆) , 时间复杂度为: o(n) //heap_sort(A,len) : 将 A 进行排序 复杂度 为 nlg(n) void max_heapify(int *A , int i,int len) { int r = RIGHT(i); int l = LEFT(i); int large = i; if (i <= len&&*(A + i-1) < *(A+r-1)) large = r; if (i <= len && *(A+large-1)<*(A+l-1)) large = l; if (large == i) return; else swap(A, large-1, i-1,len); if (i <= len && 2 * i < len/2+1) // decide if the left son node is leaf node max_heapify(A, large, len); // not leaf node , carry on the recursion else return; // end the recursion } void build_max_heap(int *A, int len) { for (int i = len / 2; i>0; i--) max_heapify(A,i,len); } void heap_sort(int *A, int len) { build_max_heap(A,len); for (int i = len; i > 0; i--) { swap(A, i - 1, 0 ,len); max_heapify(A,1,i); } }
二、快速排序 原址
最坏时间复杂度: n^2 ,但是是实际应用中最好的排序算法,期望时间复杂度:nlgn,而且隐藏的因子特别小。
1 // partition(); 将数组A[p,……,r] 分成 A[p,….,q-1]<=A[q]<=A[q+1,r],返回q的数组下标 2 // quick_sort() : 递归调用,将分割好的数组继续分割 3 int PARTITION(int *A ,int p , int r ,int len) 4 { 5 if (p >= len || r >= len|| p<0||r<=0) 6 { 7 cout << "function PARTITION erro : the p or r is out range of the vector or array" << endl; 8 return 0; 9 } 10 int i = p - 1; 11 int x = 0; 12 for (int j = p; j < r; j++) 13 { 14 if (*(A+j)<*(A+r)) 15 { 16 i = i + 1; 17 EXCHANGE(A,i,j,len); 18 } 19 } 20 EXCHANGE(A,r,i+1,len); 21 return i + 1; 22 } 23 void QUICK_SORT(int *A,int p,int r,int len) 24 { 25 if (p >= r) 26 { 27 cout << "function QUICK_SORT error : r must larger than p" << endl; 28 return; 29 } 30 if (p >= len || r >= len||p<0||r<=0) 31 { 32 cout << "function QUICK_SORT error : the p or r is out range of the vector or array" << endl; 33 return; 34 } 35 if (p == r) 36 { 37 cout << "end of calling of QUICK_SORT" << endl; 38 return; 39 } 40 int mid=PARTITION(A,p,r,len); 41 cout << "mid is :" << mid << " p ="<<p<<" r="<<r<<" len="<<len<<endl; 42 QUICK_SORT(A,p,mid-1,len); 43 QUICK_SORT(A,mid+1,r,len); 44 output(A,len); 45 }
performance:
worst situation:
T(n) = T(n-1) + k; 它的复杂度为 n^2 ,当数组已经是排好序的,那么他需要进行 n^2 次运算
best situation:
T(n) = 2T(n/2)+k; 当两个子问题的规模都不大于n/2,这时候快速排序的性能最好 nlg n次运算
平衡的划分:
只要每次划分是一种常数比例的划分,都会产生深度为lgn的递归树
例如: T(n) = T(n/10)+T(9n/10) + k;
quicksort using random function
RANDOMIZED-PARTITION(A, p, r): i = RANDOM(p, r ) exchange A[r ] ↔ A[i ] return PARTITION(A, p, r )
三、线性时间排序
1、 决策树模型:
每次比较判断可以影响下一次的比较,
定理:对于一个比较排序算法在最坏情况下,都需要做Ω(nlgn)次比较。
参考: http://www.cnblogs.com/Anker/archive/2013/01/25/2876397.html
2、计数排序 : 时间复杂度为n ,其实是max-min+1,需要额外开辟内存空间
前提条件: 所有的元素都必须在一个范围内,如: min<a[i]<=max
int * count_sort(int *a ,int n){ //initialize int max=0xffffffff, min=0x7fffffff; for (int i = 0; i < n; i++){ if (*(a + i)>max) max = *(a+i); if (*(a + i) < min) min = *(a + i); } const int len = max - min+1; int *c = new int[len]; int *re = new int[n]; memset(c,0,len*4); //count the number of every element in a[] then store in c[] for (int i = 0; i < n; i++){ *(c + *(a+i) - min) += 1; } //sort based c[] for (int i = 0,j=0; i < len; i++){ int k = 0; while (k < *(c + i)){ *(re + j) = min + i; j++; k++; } } delete []c; return re; }
四:中位数和顺序统计量
1、期望为线性时间的选择算法: 最坏时间为n^2
RANDOMIZED_SELECT(A,p,r,i) if p==r then return A[p] //通过partition函数产生q值,与快速排序的partition原理相同 q = RANDOMIZED_PARTITION(A,p,r) k = q-p+1; if i==k then return A[q] else if i<k then return RANDOMIZED_SELECT(A,p,q-1,i) else return RANDOMIZED_SELECT(A,p,q-1,i-k)
c++代码:
#include <iostream> #include <ctime> #include <cstdlib> using namespace std; void swap(int* x, int* y) { int temp; temp = *x; *x = *y; *y = temp; } inline int random(int x, int y) { srand((unsigned)time(0)); int ran_num = rand() % (y - x) + x; return ran_num; } int partition(int* arr, int p, int r) { int x = arr[r]; int i = p - 1; for(int j = p; j < r; j++) { if (arr[j] <= x) { i++; swap(arr[i], arr[j]); } } swap(arr[i + 1], arr[r]); return ++i; } int randomizedpartition(int* arr, int p, int r) { int i = random(p, r); swap(arr[r], arr[i]); return partition(arr, p, r); } int randomizedSelect(int* arr, int p, int r, int i) { if(p == r) { return arr[p]; } int q = randomizedpartition(arr, p, r); int k = q - p + 1; if(i == k) { return arr[q]; } else if(i < k) { return randomizedSelect(arr, p, q - 1, i); } else return randomizedSelect(arr, q + 1, r, i - k); } int main() { int arr[] = {1, 3, 5, 23, 64, 7, 23, 6, 34, 98, 100, 9}; int i = randomizedSelect(arr, 0, 11, 4); cout << i << endl; return 0; }