一、八种排序算法

直接插入排序、希尔排序、简单选择排序、堆排序、冒泡排序、快速排序、归并排序和基数排序。

二、算法使用

1 直接插入排序

使用场景:

如把新的数据插入到已排好的数据列中。

实现思想:

a、将第一个数和第二个数排序,然后构成一个有序序列;

b、将第三个数插入进去,构成一个新的有序序列;

c、对第四个数、第五个数……直到最后一个数,重复第二步。

 代码实现:

 1 /**
 2  * @author tjt
 3  * @time 2020-09-02
 4  * Java 排序算法
 5  */
 6 public class JavaSortAlgorithm {
 7 
 8 
 9     /**
10      * 直接插入排序:
11      * 首先,设定插入次数,即循环次数,for(int i=1;i<length;i++),第1个数的那次不用插入,会有元素间的比较排序
12      * 然后,设定插入数和得到已经排好序列的最后一个数的位数:insertNum和j=i-1
13      * 从最后一个数开始向前循环,如果插入数小于当前数,就将当前数向后移动一位
14      * 将当前数放置到空着的位置,即j+1。
15      *
16      * @param array
17      */
18     private static void justInsertSort(int[] array) {
19         System.out.println("***********直接插入排序*************");
20         int length = array.length;
21         // insertNum 为要插入的数
22         int insertNum;
23         for (int i = 1; i < length; i++) {
24             insertNum = array[i];
25             System.out.println("insertNum: " + insertNum);
26             // 已经排序好的序列元素个数
27             int j = i - 1;
28             System.out.println(Arrays.toString(array));
29             // 序列从后到前循环,将大于insertNum 的数向后移动一格
30             while (j >= 0 && array[j] > insertNum) {
31                 // 元素移动一格
32                 array[j + 1] = array[j];
33                 // j-- 之后继续于之前的比较,从后往前
34                 j--;
35             }
36             // 将需要插入的数放在要插入的位置。
37             array[j + 1] = insertNum;
38         }
39     }
40 
41 }
 

 

2 希尔排序

使用场景:

对于直接插入排序问题,数据量巨大时,可以考虑使用希尔排序。

实现思想:

a、将数的个数设为n,取奇数k=n/2,将下标差值为k 的树分为一组,构成有序序列;

b、再取k=k/2 ,将下标差值为k 的数分为一组,构成有序序列;

c、重复第二步,直到k=1 执行简单插入排序。

 代码实现:

 1     /**
 2      * 希尔排序:
 3      * 首先,确定分的组数,然后对组中元素进行插入排序
 4      * 接下来,将length/2,重复1,2步,直到length=0 为止。
 5      *
 6      * @param array
 7      */
 8     private static void xiErSort(int[] array) {
 9         System.out.println("***********希尔排序*************");
10         int length = array.length;
11         while (length != 0) {
12             length = length / 2;
13             // 分的数组
14             for (int x = 0; x < length; x++) {
15                 // 组中的元素,从第二个数开始
16                 for (int i = x + length; i < array.length; i += length) {
17                     // j为有序序列最后一位的位数
18                     int j = i - length;
19                     // temp 为要插入的元素
20                     int temp = array[i];
21                     // 从后往前遍历
22                     for (; j >= 0 && temp < array[j]; j -= length) {
23                         // 向后移动length 位
24                         array[j + length] = array[j];
25                     }
26                     array[j + length] = temp;
27                 }
28             }
29         }
30     }
 

 

3 简单选择排序

使用场景:

常用于取序列中最大最小的几个数。(如果每次比较都交换,那么就是交换排序;如果每次比较完一个循环再交换,就是简单选择排序。)

实现思想:

a、遍历整个序列,将最小的数放在最前面;

b、遍历剩下的序列,将最小的数放在最前面;

c、重复第二步,直到只剩下一个数。

1   /**
 2      * 简单选择排序:
 3      * 首先确定循环次数,并且记住当前数字和当前位置。
 4      * 将当前位置后面所有的数与当前数字进行对比,小数赋值给key,并记住小数的位置。
 5      * 比对完成后,将最小的值与第一个数的值交换。
 6      * 重复2、3步。
 7      *
 8      * @param array
 9      */
10     private static void simpleSelectSort(int[] array) {
11         System.out.println("***********简单选择排序*************");
12         int length = array.length;
13         // 循环次数
14         for (int i = 0; i < length; i++) {
15             int key = array[i];
16             int position = i;
17             // 选出最小的值和位置
18             for (int j = i + 1; j < length; j++) {
19                 if (array[j] < key) {
20                     key = array[j];
21                     position = j;
22                 }
23             }
24             // 交换位置
25             array[position] = array[i];
26             array[i] = key;
27         }
28     }
 

 

4 堆排序

使用场景:

堆排序使用场景与简单排序相似,其是简单排序的优化。

实现思想:

a、将序列构建成大顶堆;

b、将根节点与最后一个节点交换,然后断开最后一个节点;

c、重复第一、二步,直到所有节点断开。

  

1  /**
 2      * 堆排序:
 3      * 将序列构建成大顶堆;
 4      * 将根节点与最后一个节点交换,然后断开最后一个节点;
 5      * 重复第一、二步,直到所有节点断开。
 6      *
 7      * @param array
 8      */
 9     public static void heapSort(int[] array) {
10         System.out.println("***********堆排序*************");
11         System.out.println("开始排序:");
12         int arrayLength = array.length;
13         // 循环建堆
14         for (int i = 0; i < arrayLength - 1; i++) {
15             // 建堆
16             buildMaxHeap(array, arrayLength - 1 - i);
17             // 交换堆顶和最后一个元素
18             swap(array, 0, arrayLength - 1 - i);
19             System.out.println(Arrays.toString(array));
20         }
21     }
 

5 冒泡排序

使用场景:

一般比较少使用冒泡排序,徐工说会哥冒泡排序出去面试就有15K。

实现思想:

a、将序列中所有元素两两比较,将最大的放在最后面。

b、将剩余序列中所有元素两两比较,将最大的放在最后面。

c、重复第二步,直到只剩下一个数

 代码实现:

 1     /**
 2      * 冒泡排序:
 3      * 设置循环次数。
 4      * 设置开始比较的位数,和结束的位数。
 5      * 两两比较,将最小的放到前面去。
 6      * 重复2、3步,直到循环次数完毕。
 7      *
 8      * @param array
 9      */
10     private static void bubbleSort(int[] array) {
11         int length = array.length;
12         int temp;
13         for (int i = 0; i < length; i++) {
14             for (int j = 0; j < length - i - 1; j++) {
15                 if (array[j] > array[j + 1]) {
16                     temp = array[j];
17                     array[j] = array[j + 1];
18                     array[j + 1] = temp;
19                 }
20             }
21         }
22     }
 

 

6 快速排序

使用场景:

对排序时间要求较高的情况下可以考虑使用快排。

实现思想:

a、选择第一个数为p,小于p的数放在左边,大于p的数放在右边;

b、递归的将p左边和右边的数都按照第一步进行,直到不能递归。

 代码实现:

 1 /**
 2      * 快速排序:
 3      * 选择第一个数为p,小于p的数放在左边,大于p的数放在右边;
 4      * 递归的将p左边和右边的数都按照第一步进行,直到不能递归。
 5      *
 6      * @param array
 7      * @param start
 8      * @param end
 9      */
10     private static void quicklySort(int[] array, int start, int end) {
11         System.out.println("***********快速排序*************");
12         if (start < end) {
13             // 选定的基准值(第一个数值作为基准值)
14             int base = array[start];
15             // 记录临时中间值
16             int temp;
17             int i = start, j = end;
18             do {
19                 while ((array[i] < base) && (i < end)) {
20                     i++;
21                 }
22                 while ((array[j] > base) && (j > start)) {
23                     j--;
24                 }
25                 if (i <= j) {
26                     temp = array[i];
27                     array[i] = array[j];
28                     array[j] = temp;
29                     i++;
30                     j--;
31                 }
32             } while (i <= j);
33             if (start < j) {
34                 quicklySort(array, start, j);
35             }
36             if (end > i) {
37                 quicklySort(array, i, end);
38             }
39         }
40     }
 

 

7 归并排序

使用场景:

速度仅次于快排,在内存少的时候使用、可以进行并行计算的时候使用。

实现思想:

a、选择相邻两个数组成一个有序序列;

b、选择相邻的两个有序序列组成一个有序序列;

c、重复第二步,直到全部组成一个有序序列。

1  /**
 2      * 归并排序:
 3      * 选择相邻两个数组成一个有序序列;
 4      * 选择相邻的两个有序序列组成一个有序序列;
 5      * 重复第二步,直到全部组成一个有序序列。
 6      *
 7      * @param arr
 8      * @param l
 9      * @param r
10      */
11     private static void mergeSort(int[] arr, int l, int r) {
12         System.out.println("***********归并排序*************");
13         if (l < r) {
14             int q = (l + r) / 2;
15             mergeSort(arr, l, q);
16             mergeSort(arr, q + 1, r);
17             merge(arr, l, q, r);
18         }
19     }
20 
21     /**
22      * @param arr 排序数组
23      * @param l   数组最左边下标
24      * @param q   数组中间位置下标
25      * @param r   数组最右位置下标
26      */
27     private static void merge(int[] arr, int l, int q, int r) {
28         /**
29          * 因为每次切割后左边下标都是(l,q),右边数组的下标是(q+1,r)
30          * 所以左边数组的元素个数就是q - l + 1
31          * 右边的数组元素个数就是r - q
32          */
33         // 切割后左边数组的数据长度
34         final int n1 = q - l + 1;
35         // 切割后右边数组的数据长度
36         final int n2 = r - q;
37         /**创建两个新数组将切割后的数组分别放进去,长度加1是为了放置无穷大的数据标志位**/
38         // 加一操作是增加无穷大标志位
39         final int[] left = new int[n1 + 1];
40         // 加一操作是增加无穷大标志位
41         final int[] right = new int[n2 + 1];
42         //两个循环将数据添加至新数组中
43         /**左边的数组下标是从l到q**/
44         /**遍历左边的数组*/
45         for (int i = 0; i < n1; i++) {
46             left[i] = arr[l + i];
47         }
48         for (int i = 0; i < n2; i++) {
49             right[i] = arr[q + 1 + i];
50         }
51 
52         // 将最大的正整数放在两个新数组的最后一位
53         left[n1] = Integer.MAX_VALUE;
54         right[n2] = Integer.MAX_VALUE;
55 
56         int i = 0, j = 0;
57         // 将小的放在前面
58         for (int k = l; k <= r; k++) {
59             if (left[i] <= right[j]) {
60                 arr[k] = left[i];
61                 i = i + 1;
62             } else {
63                 arr[k] = right[j];
64                 j = j + 1;
65             }
66         }
67     }
 

8 基数排序

使用场景:

适用于数目量较大、很长的数进行排序。(排序队列存在负数除外)

实现思想:

a、将所有的数的个位数取出,按照个位数进行排序,构成一个序列;

b、将新构成的所有的数的十位数取出,按照十位数进行排序,构成一个序列。

 代码实现:

 

1  /**
 2      * 基数排序:
 3      * 将所有的数的个位数取出,按照个位数进行排序,构成一个序列;
 4      * 将新构成的所有的数的十位数取出,按照十位数进行排序,构成一个序列。
 5      *
 6      * @param array 排序队列中存在负数除外
 7      */
 8     private static void baseSort(int[] array) {
 9         System.out.println("***********基数排序*************");
10         // 首先确定排序的趟数;
11         int max = array[0];
12         for (int i = 1; i < array.length; i++) {
13             if (array[i] > max) {
14                 max = array[i];
15             }
16         }
17         int time = 0;
18         // 判断位数;
19         while (max > 0) {
20             max /= 10;
21             time++;
22         }
23         // 建立10个队列;
24         List<ArrayList> queue = new ArrayList<ArrayList>();
25         for (int i = 0; i < 10; i++) {
26             ArrayList<Integer> queue1 = new ArrayList<Integer>();
27             queue.add(queue1);
28         }
29         // 进行time次分配和收集;
30         for (int i = 0; i < time; i++) {
31             //分配数组元素;
32             for (int j = 0; j < array.length; j++) {
33                 // 得到数字的第time+1位数;
34                 int x = array[j] % (int) Math.pow(10, i + 1) / (int) Math.pow(10, i);
35                 ArrayList<Integer> queue2 = queue.get(x);
36                 queue2.add(array[j]);
37                 queue.set(x, queue2);
38             }
39             // 元素计数器;
40             int count = 0;
41             // 收集队列元素;
42             for (int k = 0; k < 10; k++) {
43                 while (queue.get(k).size() > 0) {
44                     ArrayList<Integer> queue3 = queue.get(k);
45                     array[count] = queue3.get(0);
46                     queue3.remove(0);
47                     count++;
48                 }
49             }
50         }
51     }