这篇文章主要讨论常见的排序算法。
排序算法分为内部排序和外部排序两种,内部排序是指只利用内存来完成的排序,外部排序是指借助外部存储设备完成的排序。外部排序主要针对记录比较多、内存无法一次全部加载的情况。我们这里主要关注内部排序。
内部排序大致分为四类:1)插入排序;2)交换排序;3)选择排序;4)归并排序;5)基数排序。我们下面会分别进行描述。
首先,我们来确定排序的对象,这里我们假设排序的对象是随机生成的非重复整数数组,有下面的辅助方法:
1 public static int[] createArray(int count, int max)
2 {
3 if (count < 1) return null;
4 int[] arrResult = new int[count];
5 java.util.Random r = new java.util.Random();
6 for(int i = 0; i < arrResult.length; i++)
7 {
8 int temp = 0;
9 while(true)
10 {
11 temp = r.nextInt(max);
12 int j = 0;
13 for (j = 0; j < i; j++)
14 {
15 if (arrResult[j] == temp) break;
16 }
17 if (j == i) break;
18 }
19 arrResult[i] = temp;
20 }
21
22 return arrResult;
23 }
24
25 private static void printArray(int[] array)
26 {
27 if (array == null)
28 {
29 return;
30 }
31
32 StringBuffer sb = new StringBuffer();
33 for(int i = 0; i < array.length; i++)
34 {
35 sb.append(array[i]).append("->");
36 }
37 System.out.println(sb.substring(0, sb.length() - 2));
38 }
接下来,我们分别讨论上述几种排序算法。
1) 插入排序。它的基本思想是将一个元素插入到一个已排序的序列中,构成一个更大的序列。直接插入排序和希尔排序(shell)都属于插入排序。
1 public static void insertSort(int[] arrValue)
2 {
3 if (arrValue == null || arrValue.length < 2) return;
4 printArray(arrValue);
5 for (int i = 1; i < arrValue.length; i++)
6 {
7 int temp = arrValue[i];
8 int j = i;
9 for (j = i; j > 0; j--)
10 {
11 if (arrValue[j - 1] > temp)
12 {
13 arrValue[j] = arrValue[j - 1];
14 }
15 else
16 {
17 break;
18 }
19 }
20 arrValue[j] = temp;
21 printArray(arrValue);
22 }
23 }
运行结果
22->32->2->46->9->29->20->45->3->26 22->32->2->46->9->29->20->45->3->26 2->22->32->46->9->29->20->45->3->26 2->22->32->46->9->29->20->45->3->26 2->9->22->32->46->29->20->45->3->26 2->9->22->29->32->46->20->45->3->26 2->9->20->22->29->32->46->45->3->26 2->9->20->22->29->32->45->46->3->26 2->3->9->20->22->29->32->45->46->26 2->3->9->20->22->26->29->32->45->46
1 public static void shellSort(int[] arrValue)
2 {
3 if (arrValue == null || arrValue.length < 2) return;
4 int length = arrValue.length/2;
5 printArray(arrValue);
6 while(length >= 1)
7 {
8 shell(arrValue, length);
9 length = length/2;
10 }
11 }
12
13 private static void shell(int[] arrValue, int d)
14 {
15 for(int i = d; i < arrValue.length; i++)
16 {
17 if (arrValue[i] < arrValue[i -d])
18 {
19 int temp = arrValue[i];
20 int j = i;
21 while(j >= d)
22 {
23 if (arrValue[j-d] > temp)
24 {
25 arrValue[j] = arrValue[j - d];
26 j = j - d;
27 }
28 else
29 {
30 break;
31 }
32 }
33 arrValue[j] = temp;
34 }
35 printArray(arrValue);
36 }
37 }
运行结果
14->21->1->26->6->40->5->46->9->25 14->5->1->9->6->40->21->46->26->25 1->5->6->9->14->25->21->40->26->46 1->5->6->9->14->21->25->26->40->46
2) 交换排序。它的基本思想是遍历待排序序列,不停交换元素,最终得到一个排序的序列。冒泡排序和快速排序都属于交换排序。
1 public static void bubbleSort(int[] arrValue)
2 {
3 if (arrValue == null || arrValue.length < 2) return;
4 printArray(arrValue);
5 for(int i = 0; i < arrValue.length; i++)
6 {
7 for(int j = i+ 1; j < arrValue.length; j++)
8 {
9 if (arrValue[i] > arrValue[j])
10 {
11 int temp = arrValue[i];
12 arrValue[i] = arrValue[j];
13 arrValue[j] = temp;
14 }
15 }
16 printArray(arrValue);
17 }
18 }
运行结果
35->2->19->37->43->47->39->34->21->0 0->35->19->37->43->47->39->34->21->2 0->2->35->37->43->47->39->34->21->19 0->2->19->37->43->47->39->35->34->21 0->2->19->21->43->47->39->37->35->34 0->2->19->21->34->47->43->39->37->35 0->2->19->21->34->35->47->43->39->37 0->2->19->21->34->35->37->47->43->39 0->2->19->21->34->35->37->39->47->43 0->2->19->21->34->35->37->39->43->47 0->2->19->21->34->35->37->39->43->47
1 public static void quickSort(int[] arrValue, int left, int right)
2 {
3 if(left < right)
4 {
5 int i = division(arrValue, left, right);
6 quickSort(arrValue, left, i - 1);
7 quickSort(arrValue, i + 1, right);
8 }
9 }
10
11 private static int division(int[] arrValue, int left, int right)
12 {
13 int baseValue = arrValue[left];
14 int midPos = left;
15 printArray(arrValue);
16 for (int i = left + 1; i <= right; i++)
17 {
18 if(arrValue[i] < baseValue) midPos++;
19 }
20
21 if (midPos == left)
22 {
23 return midPos;
24 }
25
26 arrValue[left] = arrValue[midPos];
27 arrValue[midPos] = baseValue;
28
29 if (midPos == right)
30 {
31 return midPos;
32 }
33 for (int i = left; i < midPos; i++)
34 {
35 if (arrValue[i] > baseValue)
36 {
37 for (int j = right; j > midPos; j--)
38 {
39 if (arrValue[j] < baseValue)
40 {
41 int temp = arrValue[i];
42 arrValue[i] = arrValue[j];
43 arrValue[j] = temp;
44 right--;
45 break;
46 }
47 }
48 }
49 }
50
51 return midPos;
52 }
运行结果
14->5->36->17->34->2->47->7->22->42 7->5->2->14->34->36->47->17->22->42 2->5->7->14->34->36->47->17->22->42 2->5->7->14->34->36->47->17->22->42 2->5->7->14->22->17->34->36->47->42 2->5->7->14->17->22->34->36->47->42 2->5->7->14->17->22->34->36->47->42
3)选择排序。它的基本思想是每次都从子序列中取得最小或者最大的元素。简单选择排序和堆排序都属于选择排序。
1 public static void selectSort(int[] arrValue)
2 {
3 if (arrValue == null || arrValue.length < 2) return;
4 printArray(arrValue);
5 for (int i = 0; i < arrValue.length; i++)
6 {
7 int minValue = arrValue[i];
8 int minIndex = i;
9 for (int j = i; j < arrValue.length; j++)
10 {
11 if (arrValue[j] < minValue)
12 {
13 minIndex = j;
14 minValue = arrValue[j];
15 }
16 }
17 if (i != minIndex)
18 {
19 int temp = arrValue[i];
20 arrValue[i] = arrValue[minIndex];
21 arrValue[minIndex] = temp;
22 }
23 printArray(arrValue);
24 }
25 }
运行结果
43->28->29->31->37->32->27->36->12->3 3->28->29->31->37->32->27->36->12->43 3->12->29->31->37->32->27->36->28->43 3->12->27->31->37->32->29->36->28->43 3->12->27->28->37->32->29->36->31->43 3->12->27->28->29->32->37->36->31->43 3->12->27->28->29->31->37->36->32->43 3->12->27->28->29->31->32->36->37->43 3->12->27->28->29->31->32->36->37->43 3->12->27->28->29->31->32->36->37->43 3->12->27->28->29->31->32->36->37->43
1 public static void heapSort(int[] arrValue)
2 {
3 if (arrValue == null || arrValue.length < 2) return;
4 printArray(arrValue);
5 for (int i = arrValue.length/2 - 1; i>=0; i--)
6 {
7 heapAdjust(arrValue, i, arrValue.length);
8 }
9 printArray(arrValue);
10 for (int i = arrValue.length - 1; i > 0; i--)
11 {
12 int temp = arrValue[0];
13 arrValue[0] = arrValue[i];
14 arrValue[i] = temp;
15
16 heapAdjust(arrValue, 0, i);
17 printArray(arrValue);
18 }
19
20 }
21
22 private static void heapAdjust(int[] arrValue, int parent, int length)
23 {
24 int child = 2* parent + 1;
25 int temp = arrValue[parent];
26 while(child < length)
27 {
28 if (child + 1 < length && arrValue[child] < arrValue[child + 1])
29 {
30 child = child + 1;
31 }
32 if (temp > arrValue[child])
33 {
34 break;
35 }
36 arrValue[parent] = arrValue[child];
37
38 parent = child;
39 child = parent * 2 + 1;
40
41 }
42 arrValue[parent] = temp;
43 }
运行结果
4->26->29->7->30->2->19->42->13->46 46->42->29->13->30->2->19->7->4->26 42->30->29->13->26->2->19->7->4->46 30->26->29->13->4->2->19->7->42->46 29->26->19->13->4->2->7->30->42->46 26->13->19->7->4->2->29->30->42->46 19->13->2->7->4->26->29->30->42->46 13->7->2->4->19->26->29->30->42->46 7->4->2->13->19->26->29->30->42->46 4->2->7->13->19->26->29->30->42->46 2->4->7->13->19->26->29->30->42->46
4)归并排序。它的基本思想是递归和分治。
1 public static void mergeSort(int[] arrValue, int start, int end)
2 {
3 if (arrValue == null || arrValue.length < 2) return;
4 if (start + 1 < end)
5 {
6 int mid = (start + end)/2;
7 mergeSort(arrValue, start, mid);
8 mergeSort(arrValue, mid, end);
9 merge(arrValue, start, mid, end);
10 printArray(arrValue);
11 }
12
13 }
14
15 private static void merge(int[] arrValue, int start, int mid, int end)
16 {
17 int[] temp = new int[end - start];
18
19 int index1 = start;
20 int index2 = mid;
21 int index = 0;
22 while(index1 < mid && index2 < end)
23 {
24 if (arrValue[index1] < arrValue[index2])
25 {
26 temp[index] = arrValue[index1];
27 index1++;
28 }
29 else
30 {
31 temp[index] = arrValue[index2];
32 index2++;
33 }
34 index++;
35 }
36
37 if (index1 < mid)
38 {
39 while(index1 < mid)
40 {
41 temp[index] = arrValue[index1];
42 index1++;
43 index++;
44 }
45 }
46
47 if (index2 < end)
48 {
49 while(index2 < mid)
50 {
51 temp[index] = arrValue[index2];
52 index2++;
53 index++;
54 }
55 }
56
57 for (int i = 0; i < index; i++)
58 {
59 arrValue[start + i] = temp[i];
60 }
61 }
运行结果
41->49->9->31->23->0->25->2->6->7 41->49->9->23->31->0->25->2->6->7 41->49->9->23->31->0->25->2->6->7 9->23->31->41->49->0->25->2->6->7 9->23->31->41->49->0->25->2->6->7 9->23->31->41->49->0->25->2->6->7 9->23->31->41->49->0->25->2->6->7 9->23->31->41->49->0->2->6->7->25 0->2->6->7->9->23->25->31->41->49
5)基数排序。基数排序的思想和桶排序类似,它首先按照个位数值将序列放入到0-9共10个桶中,然后依次输出,接着,对新的序列按照十位数值再次放入桶中,然后再输出,以此类推,直到所有树的位数都遍历完毕,就可以得到排好序的序列。
1 public static void radixSort(int[] arrValue)
2 {
3 if (arrValue == null || arrValue.length < 2) return;
4
5 HashMap<Integer, List<Integer>> map = new HashMap<Integer, List<Integer>>();
6 int base = 10;
7 printArray(arrValue);
8 while(isNeedContinue(arrValue, base))
9 {
10 map.clear();
11 for (int i = 0; i < arrValue.length; i++)
12 {
13 int key = arrValue[i]%base/(base/10);
14 if (!map.containsKey(key))
15 {
16 map.put(key, new ArrayList<Integer>());
17 }
18 map.get(key).add(arrValue[i]);
19 }
20 for (int i = 0, j = 0; i < 10; i++)
21 {
22 if (map.containsKey(i))
23 {
24 for(Integer value : map.get(i))
25 {
26 arrValue[j] = value;
27 j++;
28 }
29 }
30 }
31 base = base*10;
32 printArray(arrValue);
33 }
34 }
35
36 private static boolean isNeedContinue(int[] arrValue, int base)
37 {
38 for(int i = 0; i < arrValue.length; i++)
39 {
40 if (base/10 <= arrValue[i]) return true;
41 }
42 return false;
43 }
运行结果
38->16->48->27->45->44->3->22->14->42 22->42->3->44->14->45->16->27->38->48 3->14->16->22->27->38->42->44->45->48
6)其他排序 也有一些其他排序算法比较巧妙,例如计数排序,它对于不重复序列排序来说,有时是一个很好的选择,它会首先计算序列的最小值和最大值,创建一个flag数组,数组长度为最大值和最小值之差,然后遍历序列,更新flag数组,最后遍历flag数组,输出排序结果。
1 public static void smartSort(int[] arrValue)
2 {
3 if (arrValue == null || arrValue.length < 2) return;
4 int min = arrValue[0];
5 int max = arrValue[0];
6 printArray(arrValue);
7 for (int i = 1; i < arrValue.length; i++)
8 {
9 if (arrValue[i] < min) min = arrValue[i];
10 if (arrValue[i] > max) max = arrValue[i];
11 }
12 int[] arrFlag = new int[max - min + 1];
13 for (int i = 0; i < arrFlag.length; i++) arrFlag[i] = 0;
14 printArray(arrFlag);
15 for (int i = 0; i < arrValue.length; i++)
16 {
17 arrFlag[arrValue[i] - min] = 1;
18 }
19 printArray(arrFlag);
20 for(int i = 0, j = 0; i < arrFlag.length; i++)
21 {
22 if (arrFlag[i] == 1)
23 {
24 arrValue[j] = i + min;
25 j++;
26 }
27 }
28 printArray(arrValue);
29 }
运行结果
2->32->35->0->38->26->21->10->22->5 0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0 1->0->1->0->0->1->0->0->0->0->1->0->0->0->0->0->0->0->0->0->0->1->1->0->0->0->1->0->0->0->0->0->1->0->0->1->0->0->1 0->2->5->10->21->22->26->32->35->38
下面我们来总结分析上述各排序算法
| 排序算法 | 平均时间复杂度 | 最优时间复杂度 | 最坏时间复杂度 | 空间复杂度 | 稳定性 |
| 直接插入排序 | O(n*n) | O(n) | O(n*n) | O(1) | 稳定 |
| 希尔(shell)排序 | O(1) | 不稳定 | |||
| 冒泡排序 | O(n*n) | O(n) | O(n*n) | O(1) | 稳定 |
| 快速排序 | O(n*logn) | O(n*logn) | O(n*logn) | O(n*logn) | 不稳定 |
| 简单选择排序 | O(n*n) | O(n) | O(n*n) | O(1) | 不稳定 |
| 堆排序 | O(n*logn) | O(n*logn) | O(n*logn) | O(1) | 不稳定 |
| 归并排序 | O(n*logn) | O(n*logn) | O(n*logn) | O(n) | 稳定 |
| 基数排序 | O(d(n+radix)) | O(d(n+radix)) | O(d(n+radix)) | O(radix) | 稳定 |
来源:https://www.cnblogs.com/Free-Thinker/p/3444602.html
