在这里整理一下目前一些常见的排序算法和一些个人理解,可能会存在一定的错误,后续发现后会立即更正。
所涉及到的算法包括:冒泡排序、选择排序、插入排序、希尔排序、快速排序(递归和非递归版本)、堆排序、归并排序、桶排序、基数排序、计数排序。
一些理解:
快速排序和归并排序都是基于分治的思想,区别在于快速排序是先整体再局部:先把数据整体划分成两部分,一部分大于某个值,另一部分小于某个值,然后再分别对两部分作递归处理,即先保证整体基本有序,再保证局部有序;而归并排序是先把数据划分成最小的排序单元,先局部有序,然后对排序单元进行合并,从而保证整体有序。
计数排序不适合大范围的数据排序的情况,因为会根据最大值来申请空间。
冒泡排序的改进:
①第一遍从前往后遍历,找到最大值,然后从后往前遍历,找到最小值,后面重复这两步操作,这种改进称为鸡尾酒排序。改进点在于增加了遍历的方向,在某些情况下有比冒泡更好的性能,但是两者在最差情况下的表现差不多。
1 package sortalg; 2 3 import java.util.ArrayList; 4 import java.util.Collections; 5 import java.util.List; 6 import java.util.Stack; 7 8 public class SortAlgorithms { 9 public static void main(String[] args){ 10 SortAlgorithms test = new SortAlgorithms(); 11 int[] arr = new int[]{1,3,4,2,5,4,7,9,21,10,11,8}; 12 test.radixsort(arr); 13 // test.mergesort(arr, 0, arr.length-1); 14 for(int i : arr){ 15 System.out.print(i + " "); 16 } 17 } 18 19 //冒泡排序 20 public void bubble(int[] nums){ 21 for(int i=0; i){ 22 for(int j=0; j ){ 23 if(nums[j] > nums[j+1]){ 24 nums[j] = nums[j] + nums[j+1]; 25 nums[j+1] = nums[j] - nums[j+1]; 26 nums[j] = nums[j] - nums[j+1]; 27 } 28 } 29 } 30 } 31 32 //选择排序 33 public void selectsort(int[] nums){ 34 for(int i=0; i ){ 35 int minIndex = i; 36 for(int j=i; j ){ 37 if(nums[j] < nums[minIndex]){ 38 minIndex = j; 39 } 40 } 41 swap(nums, i, minIndex); 42 } 43 } 44 45 //插入排序 46 public void insertsort(int[] nums){ 47 for(int i=1; i ){ 48 for(int j=i; j>0; j--){ 49 if(nums[j] ]){ 50 nums[j] = nums[j] + nums[j-1]; 51 nums[j-1] = nums[j] - nums[j-1]; 52 nums[j] = nums[j] - nums[j-1]; 53 } 54 } 55 } 56 } 57 58 //希尔排序--插入排序的改进版 59 public void shellsort(int[] nums){ 60 int step = 0; 61 while(step < nums.length) step = 3*step +1; 62 while(step >0){ 63 step /= 3; 64 for(int i=0; i ){ 65 for(int j=i+step; j step){ 66 int tmp = nums[j]; 67 int k = j-step; 68 while(k>=0 && nums[k] > nums[k+step]){ 69 nums[k+step] = nums[k]; 70 k = k-step; 71 } 72 nums[k+step] = tmp; 73 } 74 } 75 } 76 } 77 78 //堆排序:建堆,交换首尾元素,调整堆 79 public void heapsort(int[] nums){ 80 int len = nums.length; 81 while(len>1){ 82 for(int i = (len-2)/2; i>=0; i--){ 83 adjustheap(nums, i, len); 84 } 85 swap(nums, 0, len-1); 86 len--; 87 } 88 } 89 90 // 递归调整堆 91 public void adjustheap(int[] nums, int i, int len){ 92 int k = i; 93 int left = 2*i+1, right = 2*i+2; 94 if( left < len && nums[left] > nums[k]){ 95 k = left; 96 } 97 if(right < len && nums[right] > nums[k]){ 98 k = right; 99 } 100 if(k != i){ 101 swap(nums, i, k); 102 adjustheap(nums, k, len); 103 } 104 } 105 106 // =========================快速排序============================= 107 // 递归版本 108 public void quicksortRecursion(int[] nums, int low, int high){ 109 if(low >= high) return; 110 int left = low, right = high; 111 int tmp = nums[left]; 112 while(left < right){ 113 while(right > left && nums[right] >= tmp) right--; 114 nums[left] = nums[right]; 115 while(left < right && nums[left] <= tmp) left++; 116 nums[right] = nums[left]; 117 } 118 nums[left] = tmp; 119 quicksortRecursion(nums, low, left-1); 120 quicksortRecursion(nums, left+1, high); 121 } 122 123 // 快速排序-非递归版本 124 public void quicksortNonRecursion(int[] nums){ 125 Stack stack = new Stack<>(); 126 stack.push(0); 127 stack.push(nums.length-1); 128 while(!stack.empty()){ 129 int high = stack.pop(); 130 int low = stack.pop(); 131 132 int pivorite = partition(nums, low, high); 133 if(pivorite > low){ 134 stack.push(low); 135 stack.push(pivorite-1); 136 } 137 if(pivorite < high){ 138 stack.push(pivorite+1); 139 stack.push(high); 140 } 141 } 142 } 143 144 public int partition(int[] nums, int low, int high){ 145 if(low >= high) return low; 146 int left = low, right = high; 147 int tmp = nums[left]; 148 while(left < right){ 149 while(right > left && nums[right] >= tmp) right--; 150 nums[left] = nums[right]; 151 while(left < right && nums[left] <= tmp) left++; 152 nums[right] = nums[left]; 153 } 154 nums[left] = tmp; 155 return left; 156 } 157 // =========================快速排序 end============================= 158 159 // 归并排序 160 public void mergesort(int[] nums, int left, int right){ 161 int mid = left + (right-left)/2; 162 if(right > left){ 163 mergesort(nums, left, mid); 164 mergesort(nums, mid+1, right); 165 mergePartion(nums, left, mid, right); 166 } 167 } 168 169 // 合并每个partion 170 public void mergePartion(int[] nums, int left, int mid, int right){ 171 int[] tmp = new int[right-left +1]; 172 int low = left, high = mid+1; 173 int i=0; 174 while(low <= mid && high <= right){ 175 if(nums[low] <= nums[high]){ 176 tmp[i++] = nums[low++]; 177 }else{ 178 tmp[i++] = nums[high++]; 179 } 180 } 181 while(low<=mid) tmp[i++] = nums[low++]; 182 while(high<=right) tmp[i++] = nums[high++]; 183 for(i=left; i<=right; i++){ 184 nums[i] = tmp[i-left]; 185 } 186 } 187 188 // =========================桶排序 start============================= 189 // 先把元素放到桶里,再对每一个桶分别排序,最后汇总输出 190 public void bucketsort(int[] nums){ 191 int len = nums.length; 192 int max = Integer.MIN_VALUE, min = Integer.MAX_VALUE; 193 //找到最小值和最大值 194 for(int i=0; i ){ 195 if(nums[i] < min) min = nums[i]; 196 if(nums[i] > max) max = nums[i]; 197 } 198 int bucketnum = max/len - min/len + 1; 199 List list = new ArrayList >(); 200 for(int i=0; i ){ 201 list.add(new ArrayList<>()); 202 } 203 204 // 把数据放到不同的桶里 205 for(int i=0; i ){ 206 int index = (nums[i] - min)/len; 207 ((ArrayList )list.get(index)).add(nums[i]); 208 } 209 210 // 对每个桶分别排序 211 for(int i=0; i ){ 212 Collections.sort((ArrayList)list.get(i)); 213 } 214 215 // 汇总数据 216 int k=0; 217 for(int i=0; i ){ 218 List list1 = (ArrayList )list.get(i); 219 if(list1.size()>0){ 220 for(int j : list1){ 221 nums[k++] = j; 222 } 223 } 224 } 225 } 226 // =========================桶排序 end============================= 227 228 // =========================计数排序 start============================= 229 public void countsort(int[] nums){ 230 int max = Integer.MIN_VALUE; 231 for(int num : nums){ 232 if(num > max) max = num; 233 } 234 int busketnum = max + 1; 235 int[] arr = new int[busketnum]; 236 for(int num : nums){ 237 arr[num]++; 238 } 239 int index = 0; 240 for(int i=0; i< busketnum; i++){ 241 while(arr[i]>0){ 242 nums[index++] = i; 243 arr[i]--; 244 } 245 } 246 } 247 // =========================计数排序 end============================= 248 249 // =========================基数排序 end============================= 250 public void radixsort(int[] nums){ 251 //获取最大的数字 252 int max = Integer.MIN_VALUE; 253 for(int num : nums){ 254 if(num > max) max = num; 255 } 256 for(int exp = 1; max/exp > 0; exp*=10){ 257 radixsort(nums, exp); 258 } 259 } 260 261 public void radixsort(int[] nums, int exp){ 262 int[] busket = new int[10]; 263 int[] output = new int[nums.length]; 264 for(int i=0; i ){ 265 busket[(nums[i]/exp)%10]++; 266 } 267 268 // 修改后,每个数组元素就代表小于等于当前位的数字有多少 269 // 例如当前是个位排序,busket: 0 1 1 2 3 4 7 7 8 9的4表示个位小于等于5的数字有4个 270 for(int i=1; i ){ 271 busket[i] += busket[i-1]; 272 } 273 274 // 更改buckets[i]。目的是让更改后的buckets[i]的值,是该数据在output[]中的位置。 注意这里要从后向前遍历 275 for(int i=nums.length-1; i>=0; i--){ 276 int busketIndex = (nums[i]/exp)%10; 277 output[busket[busketIndex]-1] = nums[i]; 278 busket[busketIndex]--; 279 } 280 281 for(int i=0; i ){ 282 nums[i] = output[i]; 283 } 284 } 285 // =========================基数排序 end============================= 286 287 public void swap(int [] nums, int i, int j){ 288 int tmp = nums[i]; 289 nums[i] = nums[j]; 290 nums[j] = tmp; 291 } 292 }