1 package sort; 2 /** 3 * 插入排序 4 * 1)直接插入排序 5 * 2)折半插入排序 6 * 3)希尔排序 7 * 8 * 选择排序 9 * 1)简单选择排序 10 * 2)堆排序 11 * 12 * 交换排序 13 * 1)起泡排序 14 * 2)快速排序 15 * 16 * 归并排序 17 */ 18 public class sorts { 19 /** 20 * 直接插入排序 稳定排序 21 * 空间复杂度:o(1) 22 * 时间复杂度: 23 * 最坏情况: o(n^2) 24 * 最好情况: o(n) 25 * 平均情况: o(n^2) 26 * @param data 待排数据数组 27 */ 28 public static void InsertSort(int[] data){ 29 30 for(int i = 1; i < data.length; i++){//数组下标从0开始,第一个元素有序,所以从第二个开始处理 31 int tmp = data[i];//用来临时存放待排元素 32 int j = i - 1;//标记开始比较的位置 33 //完成了从待排元素之前的元素开始扫描,如果大于待排元素,则后移一位 34 while(j >= 0 && tmp < data[j]){ 35 data[j+1] = data[j]; 36 --j; 37 } 38 data[j+1] = tmp;//找到插入位置,将tmp中暂存的待排元素插入 39 } 40 } 41 42 43 44 /** 45 * 折半插入排序 稳定排序 折半查找法的基本要求是序列已经基本有序 46 * 空间复杂度:o(1) 47 * 时间复杂度: 48 * 最坏情况: o(n^2) 49 * 最好情况: o(n) 50 * 平均情况: o(n^2) 51 * @param data 待排数据数组 52 */ 53 public static void binaryInsertSort(int[] data){ 54 55 for(int i = 1; i < data.length; i++){//数组下标从0开始,第一个元素有序,所以从第二个开始处理 56 int tmp = data[i]; 57 int low = 0; 58 int high = i - 1; 59 while(low <= high){//当low > high 折半查找结束 60 int mid = (low + high) / 2; 61 if(tmp < data[mid]){ 62 high = mid - 1; // 插入点在低半区 63 }else{ //关键字相同时,使low = mid + 1,到高半区,保证稳定性 64 low = mid + 1;// 插入点在高半区 65 } 66 } 67 //依次向后移动记录 68 for(int t = i-1; t > high; t--){// 记录后移 69 data[t+1] = data[t]; 70 } 71 data[high+1] = tmp; // 插入 72 } 73 } 74 75 /** 76 * 冒泡(起泡)排序 稳定排序 77 * 空间复杂度:o(1) tmp 78 * 时间复杂度: 79 * 最坏情况: o(n^2) 80 * 最好情况: o(n) 81 * 平均情况: o(n^2) 82 * @param data 待排数据数组 83 */ 84 public static void BubbleSort(int[] data){ 85 int n = data.length; 86 for(int k = 0; k < n-1; k++){//进行(n-1)趟冒泡 87 boolean flag = false;//变量flag用来标记本趟排序是否发生交换 88 for(int i = 1; i < n-k; i++){ 89 if(data[i-1] > data[i]){ 90 int tmp = data[i]; 91 data[i] = data[i-1]; 92 data[i-1] = tmp; 93 flag = true;//如果没发生交换,则flag为false,否则为true 94 } 95 } 96 if(!flag){ 97 return; 98 } 99 } 100 } 101 102 /** 103 * 快速排序 对从data[l]到data[r]的元素进行排序 通常都选取第一个元素作为枢纽 104 * 空间复杂度:o(logn) 快速排序是递归进行的, 递归需要栈的辅助 105 * 时间复杂度: 106 * 最坏情况: o(n^2) 107 * 最好情况: o(nlogn) 108 * 平均情况: o(nlogn) 就平均时间而言,快速排序是所有排序算法中最好的 快速排序的排序趟数和初始序列有关 109 * @param data 待排数据数组 110 * @param l 待排数据数组起始位置 111 * @param r 待排数据数组终止位置 112 */ 113 public static void QuickSort(int[] data, int l, int r){ 114 115 int i = l; 116 int j = r; 117 if(l < r){//l >= r 相当于递归终止条件 118 int tmp = data[l]; 119 //下面这个循环完成了一趟排序,即将数组中小于等于tmp的元素放在左边,大于等于tmp的元素放在右边 120 while(i != j){ 121 while(j>i&&data[j]>=tmp) --j;//从右到左扫描找到一个小于tmp的元素 122 if(i<j){ 123 data[i] = data[j]; 124 i++; 125 } 126 while(j>i&&data[i]<=tmp) i++; 127 if(i<j){ 128 data[j] = data[i]; 129 j--; 130 } 131 } 132 data[i] = tmp; 133 QuickSort(data, l, i-1);//递归地对tmp左边元素进行排序 134 QuickSort(data, i+1, r);//递归地对tmp右边元素进行排序 135 } 136 } 137 138 /** 139 * 简单选择排序 从头到尾顺序扫描序列,找出最小的一个记录,和第一个记录交换,接着从剩下的记录中继续这种选择和交换,最终使序列有序 140 * 空间复杂度:o(1) tmp 141 * 时间复杂度:o(n^2) 142 * @param data 待排数据数组 143 */ 144 public static void SelectSort(int[] data, int n){ 145 for(int i = 0; i < (n-1); i++){ 146 int k = i;//k用来记录最小值的位置 147 for(int j = i + 1; j < n; j++){ 148 if(data[j] < data[k]){ 149 k = j; 150 } 151 } 152 if(k != i){ 153 int tmp = data[k]; 154 data[k] = data[i]; 155 data[i] = tmp; 156 } 157 158 } 159 } 160 }
折半插入排序:
与直接插入排序相比,折半插入排序寻找插入位置上面所花的时间大大减少。折半插入排序在记录移动次数方面和直接插入排序是一样的,所以时间复杂度和直接插入排序还是一样的。
希尔排序:
又叫做缩小增量排序,其本质是插入排序,只不过是将待排序的序列按某种规则分成几个子序列,分别对这几个子序列进行直接插入排序。
希尔排序是不稳定的排序
空间复杂度:o(1)
平均情况下时间复杂度: o(nlogn)
注意:希尔排序的增量取法要注意,首先增量序列的最后一个值一定是1; 其次增量序列中的值没有除1之外的公因子,如8、4、2、1这样的序列就不要取(8、4、2有公共因子2)
堆排序:
堆排序是不稳定的。可以把堆看成一棵完全二叉树,这棵完全二叉树满足:任何一个非叶子结点的值都不大于(或不小于)其左右孩子结点的值。若父亲大孩子节点,则这样的堆叫做大顶堆,反之叫小顶堆。
对结点调整方法:
1) 将当前结点(假设为a)的值与其孩子结点进行比较,如果存在大于a值的孩子结点,则从中选出最大的一个与a交换。当a来到下一层的时候重复以上过程,直到a的孩子结点值都小于a的值为止。
2) 将当前无序序列中第一个元素,反映在树中是根结点(假设为a)与无序序列中最后一个元素交换(假设为b)。a进入有序序列,到达最终位置,无序序列中的元素减少1个,有序序列中元素增加1个。此时只有结点b可能不满足堆的定义,对其调整
3) 重复2)过程,直到无序序列中的元素剩下1个时排序结束。
适用范围:
记录数很多的情况,典型的例子是从10000个记录中选出前10个最小的。
|
时间复杂度 |
空间复杂度 |
稳定性 |
||
最坏情况 |
最好情况 |
平均情况 |
|||
直接插入排序 |
o(n2) |
o(n) |
o(n2) |
o(1) |
稳定 |
折半插入排序 |
o(n2) |
o(n) |
o(n2) |
o(1) |
稳定 |
希尔排序 |
|
|
O(nlog2n) |
o(1) |
不稳定 |
冒泡排序 |
o(n2) |
o(n) |
o(n2) |
o(1) |
稳定 |
快速排序 |
o(n2) |
o(nlog2n) |
o(nlog2n) |
o(log2n) |
不稳定 |
简单选择排序 |
o(n2) |
o(n2) |
o(n2) |
o(1) |
不稳定 |
堆排序 |
|
|
O(nlog2n) |
o(1) |
不稳定 |
归并排序 |
O(nlog2n) |
O(nlog2n) |
O(nlog2n) |
o(n) |
|