1、排序算法
1.1、冒泡排序
1.冒泡排序详细过程
假设原始数组顺序:10, 4, 20, 25, 3
- 第1轮后的顺序(确定了最大的一个数):4, 10, 20, 3, (25)
- 第2轮后的数组(确定了最大的俩个数):4, 10, 3, (20, 25)
- 第3轮后的数组(确定了最大的三个数):4, 3, (10, 20, 25)
- 第4轮后的数组(确定了最大的四个数):3, (4, 10, 20, 25)
2.Java代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
public static void bubbleSort(int[] array) { int temp = 0; for (int i = 0; i < array.length - 1; i++) { for (int j = 0; j < array.length - 1 - i; j++) { if (array[j] > array[j + 1]) { temp = array[j]; array[j] = array[j + 1]; array[j + 1] = temp; } } System.out.println("冒泡排序第" + (i + 1) + "趟后的数组:" + Arrays.toString(array)); } }
|
2.1 冒泡排序优化
- 当数组原来就有序,或者排序到一半就已经有序,冒泡排序仍会浪费时间继续两两进行比较,因此,需要定义一个标识,来判断数组是否已经有序,有序的话程序直接结束。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
public static void betterBubbleSort(int[] array) { int temp = 0; boolean flag = false; for (int i = 0; i < array.length - 1; i++) { for (int j = 0; j < array.length - 1 - i; j++) { if (array[j] > array[j + 1]) { flag = true; temp = array[j]; array[j] = array[j + 1]; array[j + 1] = temp; } } System.out.println("冒泡排序第" + (i + 1) + "趟后的数组:" + Arrays.toString(array)); if (!flag) { break; } else { flag = false; } } }
|
3.时间复杂度感受
排序十万个随机数所花费时间:15424毫秒,大概15秒
1 2 3 4 5 6 7 8 9 10
| public static void main(String[] args) { int[] a = new int[100000]; for (int i = 0; i < 100000; i++) { a[i] = (int) (Math.random() * 100000); } long start = System.currentTimeMillis(); BubbleSort.bubbleSort(a); long end = System.currentTimeMillis(); System.out.println(end - start); }
|
1.2、选择排序
1.选择排序详细过程
假设原始数组顺序:10, 4, 20, 25, 3
- 第1轮(看全部的数字,将最小的和”第一位”交换顺序):[10, 4, 20, 25, 3] –> [3, 4, 20, 25, 10]
- 第2轮(只看后面四个,将最小的和”第一位”交换顺序):3, [4, 20, 25, 10] –> 3, [4, 20, 25, 10]
- 第3轮(只看后面三个,将最小的和”第一位”交换顺序):3, 4, [20, 25, 10] –> 3, 4, [10, 25, 20]
- 第4轮(只看后面两个,将最小的和”第一位”交换顺序):3, 4, 10, [25, 20] –> 3, 4, 10, [20, 25]
2.Java代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
public static void selectSort(int[] array) { int temp = 0; int minIndex; for (int i = 0; i < array.length - 1; i++) { minIndex = i; for (int j = i + 1; j < array.length; j++) { if (array[j] < array[minIndex]) { minIndex = j; } } if (minIndex != i) { temp = array[i]; array[i] = array[minIndex]; array[minIndex] = temp; } System.out.println("第" + (i + 1) + "轮排序后的数组:" + Arrays.toString(array)); } }
|
3.时间复杂度感受
排序十万个随机数所花费时间:5256毫秒,大概5秒
1 2 3 4 5 6 7 8 9 10
| public static void main(String[] args) { int[] a = new int[100000]; for (int i = 0; i < 100000; i++) { a[i] = (int) (Math.random() * 100000); } long start = System.currentTimeMillis(); SelectSort.selectSort(a); long end = System.currentTimeMillis(); System.out.println(end - start); }
|
1.3、插入排序
1.插入排序详细过程
假设原始数组顺序:10, 4, 20, 25, 3
思路:将数组分为 有序表 和 无序表 两部分。之后将无序表的数据取出来插入到有序表的适当位置
- 有序——————————无序
- 排序前:(10)——————[4, 20, 25, 3]
- 第一轮:(4, 10)—————[20, 25, 3]
- 第二轮:(4, 10, 20)——— [25, 3]
- 第三轮:(4, 10, 20, 25)——[3]
- 第四轮:(3, 4, 10, 20, 25)—[]
2.Java代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
public static void insertSort(int[] array) { int insertVal; int temp; for (int i = 1; i < array.length; i++) { insertVal = array[i]; temp = i - 1; while (temp >= 0 && insertVal < array[temp]) { array[temp + 1] = array[temp]; temp--; } array[temp + 1] = insertVal;
System.out.println("插入排序第" + i + "趟后的数组:" + Arrays.toString(array)); } }
|
3.时间复杂度感受
排序十万个随机数所花费时间:828毫秒,大概0.8秒
1 2 3 4 5 6 7 8 9 10
| public static void main(String[] args) { int[] a = new int[100000]; for (int i = 0; i < 100000; i++) { a[i] = (int) (Math.random() * 100000); } long start = System.currentTimeMillis(); InsertSort.insertSort(a); long end = System.currentTimeMillis(); System.out.println(end - start); }
|
1.4、希尔排序
1.希尔排序详细过程
希尔排序VS插入排序
- 希尔排序其实质是一种特殊的插入排序,插入排序将一个数字插入到有序表里面时,需要将插入的位置之后的数字全部向后移动,这种频繁赋值需要耗费大量时间。
- 假设一个长度为十万的数组,最小的值恰好在最后一个,那么最后一次插入,前面的九万九个数字全部需要向后移动,每次移动都需要赋值一次,时间太长。
- 因此,希尔排序为了解决上述问题,其采了分组插入排序的方式(如上图),当排到最后一次时,数组总体已经趋向由小到大排列,不存在最后一个数还在最后一个的情况,最后一轮也只需要移动几次便可以结束排序,大大提高了排序效率。
2.Java代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
public static void shellSort2(int[] array) { for (int step = array.length / 2; step > 0; step /= 2) { for (int i = step; i < array.length; i++) { int j = i; int temp = array[j]; while (j - step >= 0 && temp < array[j - step]) { array[j] = array[j - step]; j -= step; } array[j] = temp; } System.out.println(Arrays.toString(array)); } }
|
3.时间复杂度感受
排序十万个随机数所花费时间:19毫秒,大概0.02秒
排序一百万个随机数所花费时间:182毫秒,大概0.18秒
排序一千万个随机数所花费时间:2517毫秒,大概2.5秒
1 2 3 4 5 6 7 8 9 10
| public static void main(String[] args) { int[] a = new int[100000]; for (int i = 0; i < 100000; i++) { a[i] = (int) (Math.random() * 100000); } long start = System.currentTimeMillis(); ShellSort.shellSort2(a); long end = System.currentTimeMillis(); System.out.println(end - start); }
|
1.5、快速排序
1.快速排序详细过程
基本思想:随便找一个数(一般是第一个)作为基准,定义一个左索引,一个右索引;左索引不断向右移,直到找到一个比基准大的数停下,右索引不断向左移,直到找到比索引小的数停下,左右索引所在的两个数交换位置,交换完成,两索引继续按照上面的规则移动,直到左右索引相遇,然后基准数和索引相遇时所在位置的数交换位置,这样一来,基准左边的数都比它小,右边的数都比它大。随后进行左递归、右递归。递归完成,排序完成。
2.Java代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
|
public static void quickSort(int[] array, int start, int end) { if (start >= end) { return; } int left = start; int right = end; int key = array[left]; int temp; while (left < right) { while (left < right && array[right] >= key) { right--; } while (left < right && array[left] <= key) { left++; } if (left<right){ temp = array[left]; array[left] = array[right]; array[right] = temp; } } temp = array[left]; array[left] = array[start]; array[start] = temp; quickSort(array, start, left - 1); quickSort(array, right + 1, end); }
|
3.时间复杂度感受
排序十万个随机数所花费时间:26毫秒,大概0.03秒
排序一百万个随机数所花费时间:122毫秒,大概0.12秒
排序一千万个随机数所花费时间:1216毫秒,大概1.2秒
1 2 3 4 5 6 7 8 9 10
| public static void main(String[] args) { int[] a = new int[100000]; for (int i = 0; i < 100000; i++) { a[i] = (int) (Math.random() * 100000); } long start = System.currentTimeMillis(); QuickSort.quickSort(a, 0, a.length - 1); long end = System.currentTimeMillis(); System.out.println(end - start); }
|
1.6、归并排序
1.归并排序详细过程
基本思想:采用分治思想。
- 以中间的数为基准,进行左右递归拆分,最后会拆到单个数,下面弹栈时两个组的数字进行组合的同时进行排序。
- 定义左右索引,且开辟一个临时数组,长度和原数组相同。左索引指向左数组的开头,右索引指向右数组的开头。
- 然后比较两索引所在位置哪个数更小,
若左索引的那个数更小,则拿出放入临时数组,且左索引向右移动一位,右索引不变,继续比较两数大小;
若右索引的那个更小,则拿出放到临时数组,且右索引向右移动一位,左索引不变,继续比较两数大小。
- 若干次后,有一方会先到数组的尾部,那么两边比较结束,另一方直接将剩下的数按序全部放入临时数组即可。
- 最后将临时数组的数据再复制给原数组。
直到弹栈结束,则排序结束。
2.Java代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
|
public static void mergeSort(int[] array, int start, int end, int[] temp) { if (start < end) { int mid = (start + end) / 2; mergeSort(array, start, mid, temp); mergeSort(array, mid + 1, end, temp); merge(array, start, mid, end, temp); } }
public static void merge(int[] array, int start, int mid, int end, int[] temp) { int left = start; int right = mid + 1; int t = 0; while (left <= mid && right <= end) { if (array[left] <= array[right]) { temp[t] = array[left]; left++; } else { temp[t] = array[right]; right++; } t++; } while (left <= mid) { temp[t] = array[left]; left++; t++; } while (right <= end) { temp[t] = array[right]; right++; t++; } t = 0; while (start <= end) { array[start] = temp[t]; t++; start++; } }
|
3.时间复杂度感受
排序十万个随机数所花费时间:16毫秒,大概0.02秒
排序一百万个随机数所花费时间:135毫秒,大概0.13秒
排序一千万个随机数所花费时间:1406毫秒,大概1.4秒
1 2 3 4 5 6 7 8 9 10
| public static void main(String[] args) { int[] a = new int[100000]; for (int i = 0; i < 100000; i++) { a[i] = (int) (Math.random() * 100000); } long start = System.currentTimeMillis(); MergeSort.mergeSort(a, 0, a.length - 1, temp); long end = System.currentTimeMillis(); System.out.println(end - start); }
|