【数据结构】五种基本排序算法:冒泡排序、选择排序、直插排序、希尔排序、快速排序
五种排序算法
- 冒泡排序(Bubble Sort)
- 选择排序(Select Sort)
- 直接插入排序(insert Sort)
- 希尔排序(Shell Sort)
- 快速排序(Quick Sort)
冒泡排序(Bubble Sort)
原理:冒泡排序就是将相邻的两个元素进行比较,若要得到升序序列,则要满足前一个元素小于后一个元素,如果不满足则交换两个元素,一次冒泡过程至少要把一个元素放到正确的位置
下面为一次冒泡过程:
从图中可以看出一次冒泡过程后最大数飘到了最上面,经过重复的 N 次操作,所有元素都飘到自己应该在的位置,就好像是气泡从水中飘上来一样,所以叫作冒泡排序
下面是一个无序序列的完整冒泡排序过程:
经过 6 次冒泡排序后,原本的无序序列变为了有序序列,所有元素都在自己应该在的位置上
代码:
public class BubbleSort { public static int[] sort(int[] array) { //外循环表示需要冒泡的次数的次数 for (int i = 0; i < array.length; i++) { //内循环表示一次完美的冒泡排序 for (int j = 0; j < array.length - 1 - i; j++) { if (array[j] > array[j + 1]) { swap(array, j, j + 1);//调用swap方法交换两个元素位置 } } } return array; } public static void swap(int array[], int x, int y) { //swap方法 int temp = array[x]; array[x] = array[y]; array[y] = temp; } public static void main(String[] args) { int[] a = {5, 7, 4, 3, 2, 1}; System.out.println("原序列为:" + Arrays.toString(a)); System.out.println("冒泡排序后序列为:" + Arrays.toString(sort(a))); }}
选择排序(Select Sort)
原理:第一次先选择 arr[0] 到 arr[n - 1] 中的最小值,然后让其与 arr[0] 进行交换,第二次再 arr[1] 到 arr[n - 1] 中选择最小值,让其与 arr[1] 交换,第三次选择 arr[2] 到 arr[n - 1] 中的最小值,然后让其与 arr[2] 进行交换…第 i 次选择 arr[i - 1] 到 arr[n - 1] 中选择最小值,然后与 arr[i - 1] 进行交换,总共会交换 n - 1 次,最终会得到一个有序序列
下面为第一次排序的过程:
下面是排完一整个序列的过程:
代码:
public class SelectSort { public static int[] selectSort(int[] arr) { for (int i = 0; i < arr.length; i++) { int minIndex = i; for (int j = i; j < arr.length; j++) { if (arr[j] < arr[minIndex]) { minIndex = j; } } int temp = arr[minIndex]; arr[minIndex] = arr[i]; arr[i] = temp; } return arr; } public static void main(String[] args) { int[] a = {5, 7, 4, 3, 2, 6}; System.out.println("原序列为:" + Arrays.toString(a)); System.out.println("排序后序列为:" + Arrays.toString(selectSort(a))); }}
直接插入排序(insert Sort)
原理:直接插入排序就是先将一个序列的第一个元素假设为一个有序的序列,在他之后的所有元素看成一个无序序列,然后将无序序列中从前到后的每个元素与有序序列中从后往前的每个元素依次比较,如果待插入元素比有序序列中的元素大就放在他后面,否则一直往前知道到达合适位置
基本步骤如下所示:
完整的排序过程如下:
代码:
public class insertSort { public static int[] insertSort(int array[]){ for(int i = 1; i < array.length; i++){ //将无序序列的元素依次插入到有序序列 int temp = array[i]; //提前保存array[i],否则会覆盖array[i] int j; for(j = i - 1; j >= 0;j--){ //寻找插入的位置 if(array[j] > temp){ //满足条件贼进行下一步 array[j + 1] = array[j]; //将元素往后移 } if(array[j] < temp){ break; } } array[j + 1] = temp; //插入array[i] } return array; } public static void main(String[] args) { int[] a = {5, 7, 4, 3, 2, 6}; System.out.println("原序列为:" + Arrays.toString(a)); System.out.println("排序后序列为:" + Arrays.toString(insertSort(a))); }}
希尔排序(Shell Sort)
希尔排序就是直接插入排序的升级款,也叫缩小增量排序
原理:先将一个序列分为若干个子序列(序列中元素之间相隔某个“增量”),然后对这些子序列进行直接插入排序。然后缩小这个增量再次进行直接插入排序,知道增量足够小(增量为 1 时),对整个序列进行一次直接插入排序,此时这个序列处于基本有序状态,这时直接插入排序的效率最高
我们选择增量的时候首先选择序列长度的一半(length / 2),缩小增量时继续取前一个步长的一半(gap / 2),直到 gap = 1
这时增量为 4 ,将序列分为{5,8},{7,4},{6,3},{10,9},对每个序列进行直接插入排序使其基本有序,就会得到下面的序列
这时增量为 2 ,将序列分为{5,3,8,6},{4,9,7,10},对每个序列进行直接插入排序使其基本有序,得到序列{3,4,5,7,6,9,8,10}
此时的增量为 1 (足够小),那么现在就对整个序列进行一次直接插入排序就可以得到最终的有序序列
代码:
public class ShellSort { public static int[] shellSort(int[] arr) { int j, temp; for (int gap = arr.length / 2; gap > 0; gap /= 2) { //每一次的增量 for (int i = gap; i < arr.length; i++) { //从下标为增量的元素开始向后遍历 temp = arr[i]; //提前保存 arr[i],否则会将其覆盖 for (j = i - gap; j >= 0; j -= gap) { //寻找插入位置 if (temp < arr[j]) { //满足条件进行下一步 arr[j + gap] = arr[j]; //将元素后移 } else { break; } } arr[j + gap] = temp; //插入 arr[i] } } return arr; } public static void main(String[] args) { int[] a = {5, 7, 6, 10, 8, 4, 3, 9}; System.out.println("原序列为:" + Arrays.toString(a)); System.out.println("排序后序列为:" + Arrays.toString(insertSort(a))); }}
快速排序(Quick Sort)
听到快速排序这个名字我们第一下会想到这个排序可以很快速的将一个序列变为有序序列,那让我们看一下快速排序的原理吧!
原理:将一个序列中的第一个元素作为参照数,然后将序列中所有大于等于参照数的元素放在它后面,把所有小于参照数的元素放在它前面**
光看原理可能会有些不太理解,接下来用一个例子来解释一下它的排序过程:
我们首先给定一个无序序列{5, 7, 4, 3, 2, 6},我们需要两个指针 i 和 j ,分别在序列的头和尾两个位置,这里我们的参照数就是首元素 5 ,首先我们先动指针 j ,只要找到一个小于 5 的元素就停止,接下来动指针 i ,只要找到一个大于 5 的元素就停止,然后我们交换两个指针所对应的元素,得到{5,2,4,3,7,6},至此第一次交换完毕
第二次交换开始:指针 j 先动,找到了元素 3 ,接着指针 i 开始动,发现没有比 5 大的元素了,并且在指针 i 动的过程中,i 和 j 重合了,此时就结束循环了,我们就将参照数 5 和 3 进行交换,得到序列{3,2,4,5,7,6},第二次交换完毕
这时就将一个序列分成了一个全是小于 5 的序列{3,2,4}和一个全是大于 5 的序列{7,6},我们再对这两个序列继续重复上述的操作,就可以完成完美的快速排序
上图就是一个完整的快速排序过程
代码:
package kang.exercise;import java.util.Arrays;public class QuickSort { public static int[] quickSort(int[] arr, int low, int high) { if (low > high) { return null; } int i = low; int j = high; int temp = arr[low]; //temp就是参照数 while (i < j) { while (temp <= arr[j] && i < j) { //先走指针 j ,从后往前移动 j--; } while (temp >= arr[i] && i < j) { //再走指针 i ,从前往后移动 i++; } if (i < j) { //交换两个符合要求的元素 int t = arr[j]; arr[j] = arr[i]; arr[i] = t; } } //将指针重合位置的元素与参照数进行交换 arr[low] = arr[i]; arr[i] = temp; quickSort(arr, low, i - 1); //递归左边的序列 quickSort(arr, i + 1, high); //递归右边的序列 return arr; } public static void main(String[] args) { int[] a = {5, 7, 4, 3, 2, 6}; System.out.println("原序列为:" + Arrays.toString(a)); System.out.println("排序后序列为:" + Arrays.toString(quickSort(a, 0, a.length - 1))); }}