常见的排序算法整理

在这里整理一下目前一些常见的排序算法和一些个人理解,可能会存在一定的错误,后续发现后会立即更正。

所涉及到的算法包括:冒泡排序、选择排序、插入排序、希尔排序、快速排序(递归和非递归版本)、堆排序、归并排序、桶排序、基数排序、计数排序。

一些理解:

快速排序和归并排序都是基于分治的思想,区别在于快速排序是先整体再局部:先把数据整体划分成两部分,一部分大于某个值,另一部分小于某个值,然后再分别对两部分作递归处理,即先保证整体基本有序,再保证局部有序;而归并排序是先把数据划分成最小的排序单元,先局部有序,然后对排序单元进行合并,从而保证整体有序。

计数排序不适合大范围的数据排序的情况,因为会根据最大值来申请空间。

冒泡排序的改进:

①第一遍从前往后遍历,找到最大值,然后从后往前遍历,找到最小值,后面重复这两步操作,这种改进称为鸡尾酒排序。改进点在于增加了遍历的方向,在某些情况下有比冒泡更好的性能,但是两者在最差情况下的表现差不多。

  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<nums.length-1; i++){
 22       for(int j=0; j<nums.length-1-i; 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<nums.length-1; i++){
 35       int minIndex = i;
 36       for(int j=i; j<nums.length; 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<nums.length; i++){
 48       for(int j=i; j>0; j--){
 49         if(nums[j]<nums[j-1]){
 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<step; i++){
 65         for(int j=i+step; j<nums.length; j += step){
 66           int tmp = nums[j];
 68           while(j>=step && nums[j-step] > tmp){
 69             nums[j] = nums[j-step]; 70             j -= step 71           }
 72           nums[j] = 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<Integer> 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<len; 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<ArrayList<Integer>>();
200     for(int i=0; i<bucketnum; i++){
201       list.add(new ArrayList<>());
202     }
203 
204     // 把数据放到不同的桶里
205     for(int i=0; i<len; i++){
206       int index = (nums[i] - min)/len;
207       ((ArrayList<Integer>)list.get(index)).add(nums[i]);
208     }
209 
210     // 对每个桶分别排序
211     for(int i=0; i<bucketnum; i++){
212       Collections.sort((ArrayList)list.get(i));
213     }
214 
215     // 汇总数据
216     int k=0;
217     for(int i=0; i<bucketnum; i++){
218       List<Integer> list1 = (ArrayList<Integer>)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<nums.length; 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<busket.length; 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];279     }
280 
281     for(int i=0; i<nums.length; 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 }

 补充鸡尾酒排序:

 1     //鸡尾酒排序:冒泡排序的改进,稳定
 2     //先从低到高,再从高到低
 3     public void cocktail(int[] arr){
 4         if(arr==null||arr.length==0) return;
 5         for(int left=0,right=arr.length-1;left<right;){
 6             //从低到高,将较大元素后移
 7             for(int i=left;i<right;i++){
 8                 if(arr[i]>arr[i+1]){
 9                     exchange(arr,i,i+1);
10                 }                
11             }
12             right--;
13             //从高到低,将较小元素前移
14             for(int j=right;j>0;j--){
15                 if(arr[j]<arr[j-1]){
16                     exchange(arr,j,j-1);
17                 }
18             }
19             left++;
20         }
21     }
原文地址:https://www.cnblogs.com/NaLanZiYi-LinEr/p/10803909.html