|
| 1 | +### 排序算法 |
| 2 | + |
| 3 | +| 算法 | 稳定 | 原地排序 | 时间复杂度 | 空间复杂度 | 备注 | |
| 4 | +| :--------------: | :--: | :------: | :--------------------------: | :--------: | :----------------------: | |
| 5 | +| 冒泡排序 | yes | yes | N^2^ | 1 | | |
| 6 | +| 选择排序 | no | yes | N<sup>2sup> | 1 | | |
| 7 | +| 插入排序 | yes | yes | N \~ N<sup>2sup> | 1 | 时间复杂度和初始顺序有关 | |
| 8 | +| 希尔排序 | no | yes | N 的若干倍乘于递增序列的长度 | 1 | | |
| 9 | +| 快速排序 | no | yes | NlogN | logN | | |
| 10 | +| 三向切分快速排序 | no | yes | N \~ NlogN | logN | 适用于有大量重复主键 | |
| 11 | +| 归并排序 | yes | no | NlogN | N | | |
| 12 | +| 堆排序 | no | yes | NlogN | 1 | | |
| 13 | + |
| 14 | +#### 选择排序 |
| 15 | + |
| 16 | +```java |
| 17 | +public void swap(int[] T,int i,int j){ |
| 18 | + int temp = T[i]; |
| 19 | + T[i] = T[j]; |
| 20 | + T[j] = temp; |
| 21 | + } |
| 22 | + |
| 23 | +public int[] selectSort(int[] nums){//选择排序 |
| 24 | + for (int i=0;i<nums.length-1;i++){ |
| 25 | + int min=i; |
| 26 | + for (int j=i+1;j<nums.length;j++){ |
| 27 | + if (nums[j]<nums[min]){ |
| 28 | + min=j; //选择最小的元素index |
| 29 | + } |
| 30 | + } |
| 31 | + swap(nums,i,min); //交换到最前面 |
| 32 | + } |
| 33 | + return nums; |
| 34 | + } |
| 35 | +``` |
| 36 | + |
| 37 | +#### 冒泡排序 |
| 38 | + |
| 39 | +```java |
| 40 | +public int[] bubbleSort(int[] nums){ |
| 41 | + boolean isSort = false; //如果数组已经排好序,就只需要遍历一遍 |
| 42 | + for (int i=nums.length-1;i>0&&!isSort;i--){ |
| 43 | + isSort=true; |
| 44 | + for (int j=0;j<i;j++){ |
| 45 | + if (nums[j]>nums[j+1]){//将大的元素向上冒泡 |
| 46 | + isSort=false; |
| 47 | + swap(nums,j,j+1); |
| 48 | + } |
| 49 | + } |
| 50 | + } |
| 51 | + return nums; |
| 52 | + } |
| 53 | +``` |
| 54 | + |
| 55 | +#### 插入排序 |
| 56 | + |
| 57 | +```java |
| 58 | +public int[] insertSort(int[] nums){ |
| 59 | + for (int i=0;i<nums.length-1;i++){ |
| 60 | + for (int j=i+1;j>0&&nums[j]<nums[j-1];j--){ //将小元素交换到之前已经排序的数组中去 |
| 61 | + swap(nums,j,j-1); |
| 62 | + } |
| 63 | + } |
| 64 | + return nums; |
| 65 | + } |
| 66 | +``` |
| 67 | + |
| 68 | +#### 希尔排序 |
| 69 | + |
| 70 | +```java |
| 71 | +public void shellSort(int[] nums){ |
| 72 | + int N=nums.length; |
| 73 | + int h=1; // h=N/2 就是以1,2,4的增量进行插入排序 |
| 74 | + while (h < N / 3) { |
| 75 | + h = 3 * h + 1; // 1, 4, 13, 40, ... |
| 76 | + } |
| 77 | + while (h >= 1) { |
| 78 | + for (int i = h; i < N; i++) { //循环内是插入排序 |
| 79 | + for (int j = i; j >= h && nums[j]<nums[j - h]; j -= h) { |
| 80 | + swap(nums, j, j - h); |
| 81 | + } |
| 82 | + } |
| 83 | + h = h / 3; |
| 84 | + } |
| 85 | + } |
| 86 | +``` |
| 87 | + |
| 88 | +#### 归并排序 |
| 89 | + |
| 90 | +```java |
| 91 | +public int[] mergeSort(int[] arr,int left,int right){ |
| 92 | + if (left==right) return new int[] {arr[left]}; |
| 93 | + int mid = left+(right-left)/2; |
| 94 | + int[] leftarr = mergeSort(arr,left,mid); //递归 |
| 95 | + int[] rightarr = mergeSort(arr,mid+1,right); |
| 96 | + int[] newarr = new int[leftarr.length+rightarr.length]; |
| 97 | + int i=0,j=0,k=0; |
| 98 | + while (i< leftarr.length && j< rightarr.length){ |
| 99 | + newarr[k++] = leftarr[i]<rightarr[j]? leftarr[i++]: rightarr[j++]; |
| 100 | + } |
| 101 | + while (i< leftarr.length){ |
| 102 | + newarr[k++] = leftarr[i++]; |
| 103 | + } |
| 104 | + while (j<rightarr.length){ |
| 105 | + newarr[k++] = rightarr[j++]; |
| 106 | + } |
| 107 | + return newarr; |
| 108 | + } |
| 109 | +``` |
| 110 | + |
| 111 | +#### 快速排序 |
| 112 | + |
| 113 | +```java |
| 114 | +public void quickSort(int[] arr,int start,int end){ |
| 115 | + int left=start,right=end; |
| 116 | + int pivot=arr[start]; |
| 117 | + while (left<right) { //两个指针 |
| 118 | + while (arr[right]>pivot && right>left){ //从右指向左,遇到比基准小的换到前面去 |
| 119 | + right--; |
| 120 | + } |
| 121 | + while (arr[left]<pivot && right>left){//从左指向右,遇到比基准大的换到后面去 |
| 122 | + left++; |
| 123 | + } |
| 124 | + if (arr[left]==arr[right] && left<right){ |
| 125 | + left++; |
| 126 | + }else swap(arr,left,right); |
| 127 | + } |
| 128 | + if (left-1>start) quickSort(arr,start,left-1); |
| 129 | + if (right+1<end) quickSort(arr,right+1,end); |
| 130 | + } |
| 131 | +``` |
| 132 | + |
| 133 | +#### 堆排序 |
| 134 | + |
| 135 | +```java |
| 136 | +public static int[] heapSort(int[] array) { |
| 137 | + //这里元素的索引是从0开始的,所以最后一个非叶子结点array.length/2 - 1 |
| 138 | + for (int i = array.length / 2 - 1; i >= 0; i--) { |
| 139 | + adjustHeap(array, i, array.length); //调整堆 |
| 140 | + } |
| 141 | + // 上述逻辑,建堆结束 |
| 142 | + // 下面,开始排序逻辑 |
| 143 | + for (int j = array.length - 1; j > 0; j--) { |
| 144 | + // 元素交换,作用是去掉大顶堆 |
| 145 | + // 把大顶堆的根元素,放到数组的最后;换句话说,就是每一次的堆调整之后,都会有一个元素到达自己的最终位置 |
| 146 | + swap(array, 0, j); |
| 147 | + // 元素交换之后,毫无疑问,最后一个元素无需再考虑排序问题了。 |
| 148 | + // 接下来我们需要排序的,就是已经去掉了部分元素的堆了,这也是为什么此方法放在循环里的原因 |
| 149 | + // 而这里,实质上是自上而下,自左向右进行调整的 |
| 150 | + adjustHeap(array, 0, j); |
| 151 | + } |
| 152 | + return array; |
| 153 | + } |
| 154 | + /** |
| 155 | + * 整个堆排序最关键的地方 |
| 156 | + * @param array 待组堆 |
| 157 | + * @param i 起始结点 |
| 158 | + * @param length 堆的长度 |
| 159 | + */ |
| 160 | + public static void adjustHeap(int[] array, int i, int length) { |
| 161 | + // 先把当前元素取出来,因为当前元素可能要一直移动 |
| 162 | + int temp = array[i]; |
| 163 | + for (int k = 2 * i + 1; k < length; k = 2 * k + 1) { //2*i+1为左子树i的左子树(因为i是从0开始的),2*k+1为k的左子树 |
| 164 | + // 让k先指向子节点中最大的节点 |
| 165 | + if (k + 1 < length && array[k] < array[k + 1]) { //如果有右子树,并且右子树大于左子树 |
| 166 | + k++; |
| 167 | + } |
| 168 | + //如果发现结点(左右子结点)大于根结点,则进行值的交换 |
| 169 | + if (array[k] > temp) { |
| 170 | + swap(array, i, k); |
| 171 | + // 如果子节点更换了,那么,以子节点为根的子树会受到影响,所以,循环对子节点所在的树继续进行判断 |
| 172 | + i = k; |
| 173 | + } else { //不用交换,直接终止循环 |
| 174 | + break; |
| 175 | + } |
| 176 | + } |
| 177 | + } |
| 178 | +``` |
| 179 | + |
0 commit comments