各种排序算法
public class BubbleSort implements SortUtil.Sort{ public void sort(int[] data){ for (int i = 0; i < data.length; i++ ){//遍历待排序的位 for (int j = data.length-1; j>i ; j--){ //交换到最后,第一位必定是最小的 if (data[j] < data[j-1]) SortUtil.swap(data, j, j-1); } } } }
public class SelectSort implements SortUtil.Sort{ public void sort(int[] data){ int temp; for (int i = 0; i < data.length; i++ ){ temp = i; for (int j = data.length-1; j>i ; j--){ if (data[j] < data[temp]) temp = j; } SortUtil.swap(data, i, temp); } } }
public class InsertSort implements SortUtil.Sort{ public void sort(int[] data){ for (int i = 1; i < data.length; i++ ) { //遍历待排序的位 for (int j = i ; j>0 && data[j-1]> data[j]; j--){ //从后往前(数组,从最后一位开始移位操作) SortUtil.swap(data, j, j-1); } } } }
void insertSort(int* int_array,int start, const int len, int inc){ //对步长为inc的子序列进行排序 int temp; for(int i = start; i < len; i+=inc){ //for循环的增量为inc for(int j = i; j>0; j-= inc){ if(int_array[j] < int_array[j-inc]){ temp = int_array[j]; int_array[j] = int_array[j-inc]; int_array[j-inc] = temp; } } } } void shellSort(int* int_array, const int len){ for(int inc = len/2; inc >0; inc/=2) {//先对inc由大到小遍历 for(int i = 0; i < inc; i++) {//遍历组 insertSort(int_array, i, len, inc);//在每组内进行插入排序 } } }
快速排序
思路:选取一个中间值,大于他的放在他的右边,小于他的则放在左边,然后对左边序列及右边序列分别再进行递归。
时间复杂度分析:希尔排序,快速排序,堆排序都是采用了分治法,最外层循环至少进行logn次。每次循环要进行n/(2^i)次比较和3次移动,时间复杂度在平均情况和最好情况下是O(nlogn),在最坏情况下是O(n2)。
不稳定排序。
void sort(int* int_array, int start, int end) { if(start == end ) return; int p1=start+1; int p2 = end; int tmp; //range the array into two part according to the sentinel value while(1){ while(int_array[p1] <= int_array[start]) p1++; while(int_array[p2] > int_array[start]) p2--; if(p1>=p2) break; tmp = int_array[p1]; int_array[p1] = int_array[p2]; int_array[p2] = tmp; } //put the sentinel into the middle of the array tmp = int_array[start]; int_array[start] = int_array[p2]; int_array[p2]=tmp; //recursion sort(int_array,start,p2); sort(int_array,p1,end); } void quickSort(int* int_array, int len) { sort(int_array,0,len-1); }
思路:把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列两两合并为整体有序序列。
不同于快速排序(先排序再二分),归并排序是先二分,再将二分法的结果进行排序
稳定排序,因为并没有涉及到两个元素的交换。
void sort(int* int_array, int* result_array, int start, int end) { if(start==end) return; int mid = (start + end)/2; sort(int_array,result_array,start,mid); sort(int_array,result_array,mid+1,end); //现在两个子序列是有序的,开始合并这两个子序列 int p1 = start; int p2 = mid+1; int rp = start; while(p1 <= mid && p2 <=end){ //要额外申请一个空间result_array保存数组。 if(int_array[p1] <= int_array[p2]) result_array[rp++] = int_array[p1++]; else result_array[rp++] = int_array[p2++]; } while(p1<=mid) result_array[rp++] = int_array[p1++]; while(p2<=end) result_array[rp++] = int_array[p2++]; for(int i = start; i<=end; i++) int_array[i] =result_array[i]; } void mergeSort(int* int_array, const int len) { int* result_array = new int[len]; sort(int_array,result_array,0,len-1); }
改进:递归以及并行操作的优化都是,设置一个阈值,比如7,对于<7的子序列,不再递归,而是采用直接插入排序。
递归问题时间复杂度的计算方法:
法I:看成一颗二叉树,有lgN+1层,每层有N个节点。所以时间复杂度O(n)=(lgN+1)N=NlgN+N=NlgN
法II:递归表达式求解的一种常用方法是数学归纳法。
首先猜测O(N)=NlgN
当N=1时,O(1)=0,满足初始条件。
假设O(2k)=2klg2k=k*2k
那么O(2k+1)=(2k+1)(lg2k+1)=2klg2k+lg2k+2k+1=k*2k+k+2k+1=2k(k+1)+(k+1)=(k+1)*(2k+1)
所以假设成立,O(N)=NlgN
堆排序
思路:最大堆是最大的一个数在堆顶,父节点总比子节点大(新添节点放在叶子节点,自下而上调整)。然后我们将堆顶放到序列的尾部,选一个叶子节点放到堆顶,利用循环自上而下调整最大堆。
class MaxHeap { //建堆 public: int * queue; MaxHeap::MaxHeap(int* data, const int len) { queue = new int (len+1);//queue[0]空着,以便实现子是父的两倍关系 for(int i = 1; i <= len; i++) { queue[i] = data[i-1]; fixUp(i); } } void fixUp(int k){ //k是队列下标 int j = k >> 1; //右移一位,相当于除以2,即找到父节点 int temp; while(j>0){ if(queue[j]>queue[k]) break; temp = queue[j]; queue[j] = queue[k]; queue[k] = temp; k = j; //向上移一层 j = k>>1; } } }; void fixDown(int* queue, const int queue_size, int k){ //排序 int j = k << 1; //找左儿子 int temp; while(j<=queue_size){ if (j!=queue_size && queue[j] < queue[j+1]) j++;//取左右儿子中大的那个 if(queue[j] > queue[k]){ temp = queue[j]; queue[j] = queue[k]; queue[k] = temp; k = j; j = k << 1; } } } void heapSort(int* int_array, const int len) { MaxHeap maxHeap(int_array, len); int queue_size = len; for(int i = len-1; i >= 0; i--) { int_array[i] = maxHeap.queue[1]; maxHeap.queue[1] = maxHeap.queue[queue_size--]; fixDown(maxHeap.queue,queue_size, 1); } }
排序算法 |
最好时间 |
平均时间 |
最差时间 |
稳定否 |
空间复杂度 |
冒泡 |
O(n) |
O(n2) |
O(n2) |
稳定 |
O(1) |
选择 |
O(n2) |
O(n2) |
O(n2) |
不稳定 |
O(1) |
插入 |
O(n) |
O(n2) |
O(n2) |
稳定 |
O(1) |
Shell |
O(nlogn) |
O(nlogn) |
O(n^s) 1 |
不稳定 |
O(1) |
快速 |
O(nlogn) |
O(nlogn) |
O(n2) |
不稳定 |
O(logn) (递归栈上需要花费最少logn 最多n的空间) |
归并 |
O(nlogn) |
O(nlogn) |
O(nlogn) |
稳定 |
O(n) |
堆 |
O(nlogn) |
O(nlogn) |
O(nlogn) |
不稳定 |
O(1) |