数据结构之排序基础知识笔记

概述

最近在温习数据结构,现在针对排序算法写一篇随笔,其中附带原理说明和代码。

插入排序

直接插入排序(Straight Insertion Sort)的基本思想是:把n个待排序的元素看成为一个有序表和一个无序表。开始时有序表中只包含1个元素,无序表中包含有n-1个元素,排序过程中每次 从无序表中取出第一个元素,将它插入到有序表中的适当位置,使之成为新的有序表,重复n-1次可完成排序过程。

假设{20,30,40,10,60,50}中的前3个数已经排列过,是有序的了;接下来对10进行排列。示意图如下:

 图中将数列分为有序区和无序区。我们需要做的工作只有两个:(1)取出无序区中的第1个数,并找出它在有序区对应的位置。(2)将无序区的数据插入到有序区;若有必要的话,则对有序区中的相关数据进行移位。

时间复杂度和稳定性

直接插入排序的时间复杂度是O(N2)。

假设被排序的数列中有N个数。遍历一趟的时间复杂度是O(N),需要遍历多少次呢?N-1!因此,直接插入排序的时间复杂度是O(N*N)。

直接插入排序是稳定的算法,它满足稳定算法的定义。

算法稳定性 -- 假设在数列中存在a[i]=a[j],若在排序之前,a[i]在a[j]前面;并且排序之后,a[i]仍然在a[j]前面。则这个排序算法是稳定的。

插入排序JAVA实现

 1 import static javaTest.SortUtils.less;
 2 
 3 /**
 4  * ClassName InsertionSort.java
 5  * author Rhett.wang
 6  * version 1.0.0
 7  * Description TODO
 8  * createTime 2020年01月16日 16:00:00
 9  */
10 public class InsertionSort implements SortAlgorithm{
11     public static void main(String[] args) {
12         Integer[] a= {22,14,35,45,67};
13         InsertionSort sort =new InsertionSort();
14         sort.sort(a);
15 
16     }
17     /**
18      * Main method arrays sorting algorithms
19      *
20      * @param array - an array should be sorted
21      * @return a sorted array
22      */
23     @Override
24     public <T extends Comparable<T>> T[] sort(T[] array) {
25         for (int j = 1; j < array.length; j++) {
26 
27             // Picking up the key(Card)
28             T key = array[j];
29             int i = j - 1;
30 
31             while (i >= 0 && less(key, array[i])) {
32                 array[i + 1] = array[i];
33                 i--;
34             }
35             // Placing the key (Card) at its correct position in the sorted subarray
36             array[i + 1] = key;
37         }
38         return array;
39     }
40 
41 }

实现基类接口

 1 import java.util.Arrays;
 2 import java.util.List;
 3 
 4 import static javafx.scene.input.KeyCode.T;
 5 
 6 /**
 7  * ClassName SortAlgorithm.java
 8  * author Rhett.wang
 9  * version 1.0.0
10  * Description TODO
11  * createTime 2020年01月16日 14:29:00
12  */
13 public interface SortAlgorithm {
14     /**
15      * Main method arrays sorting algorithms
16      *
17      * @param unsorted - an array should be sorted
18      * @return a sorted array
19      */
20     <T extends Comparable<T>> T[] sort(T[] unsorted);
21 
22 
23     /**
24      * Auxiliary method for algorithms what wanted to work with lists from JCF
25      *
26      * @param unsorted - a list should be sorted
27      * @return a sorted list
28      */
29     default <T extends Comparable<T>> List<T> sort(List<T> unsorted){
30        return Arrays.asList(sort(unsorted.toArray((T[]) new Comparable[unsorted.size()])));
31     }
32 }

插入排序SCALA实现

 1 /**
 2   * ClassName InsertionSort.java
 3   * author Rhett.wang
 4   * version 1.0.0
 5   * Description TODO
 6   * createTime 2020年01月18日 11:25:00
 7   */
 8 object InsertionSort {
 9   def main(args: Array[String]) {
10 
11   }
12 
13   def sort(nums: Array[Int]): Array[Int] = {
14     for (j <- 0 until nums.length -1) {
15       var temp = nums(j)
16       var i = j - 1
17       while (i >= 0 && temp < nums(i)) {
18         nums(i + 1) = nums(i)
19         i-=1
20       }
21       nums(i + 1) = temp
22     }
23     nums
24   }
25 
26 }

插入排序PYTHON实现

 1 def insert_sort(collection):
 2     """Pure implementation of the insertion sort algorithm in Python
 3     :param collection: some mutable ordered collection with heterogeneous
 4     comparable items inside
 5     :return: the same collection ordered by ascending
 6     Examples:
 7     >>> insertion_sort([0, 5, 3, 2, 2])
 8     [0, 2, 2, 3, 5]
 9     >>> insertion_sort([])
10     []
11     >>> insertion_sort([-2, -5, -45])
12     [-45, -5, -2]
13     """
14     for loop_index in range(1,len(collection)):
15         insertion_index=loop_index
16         while(
17             insertion_index>0
18             and collection[insertion_index -1] > collection[insertion_index-1]
19         ):
20             collection[insertion_index],collection[insertion_index -1] =(
21                 collection[insertion_index -1],
22                 collection[insertion_index],
23             )
24             insertion_index -=1
25     return collection
26 
27 if __name__=="__main__":
28      user_input= input("Enter numbers separated by a comma:\n").strip()
29      unsorted=[int(item) for item in user_input.split(",")]
30      print(insert_sort(unsorted))

希尔排序

希尔(Shell)排序又称为缩小增量排序,它是一种插入排序。它是直接插入排序算法的一种威力加强版。该方法因DL.Shell于1959年提出而得名,

把记录按步长 gap 分组,对每组记录采用直接插入排序方法进行排序。

随着步长逐渐减小,所分成的组包含的记录越来越多,当步长的值减小到 1 时,整个数据合成为一组,构成一组有序记录,则完成排序。

我们来通过演示图,更深入的理解一下这个过程。

 在上面这幅图中:

初始时,有一个大小为 10 的无序序列。

在第一趟排序中,我们不妨设 gap1 = N / 2 = 5,即相隔距离为 5 的元素组成一组,可以分为 5 组。接下来,按照直接插入排序的方法对每个组进行排序。

在第二趟排序中,我们把上次的 gap 缩小一半,即 gap2 = gap1 / 2 = 2 (取整数)。这样每相隔距离为 2 的元素组成一组,可以分为 2 组。按照直接插入排序的方法对每个组进行排序。

在第三趟排序中,再次把 gap 缩小一半,即gap3 = gap2 / 2 = 1。 这样相隔距离为 1 的元素组成一组,即只有一组。按照直接插入排序的方法对每个组进行排序。此时,排序已经结束。

需要注意一下的是,图中有两个相等数值的元素 5 和 5 。我们可以清楚的看到,在排序过程中,两个元素位置交换了。

所以,希尔排序是不稳定的算法。

算法分析

算法性能

 时间复杂度

步长的选择是希尔排序的重要部分。只要最终步长为1任何步长序列都可以工作。

算法最开始以一定的步长进行排序。然后会继续以一定步长进行排序,最终算法以步长为1进行排序。当步长为1时,算法变为插入排序,这就保证了数据一定会被排序。

Donald Shell 最初建议步长选择为N/2并且对步长取半直到步长达到1。虽然这样取可以比O(N2)类的算法(插入排序)更好,但这样仍然有减少平均时间和最差时间的余地。

可能希尔排序最重要的地方在于当用较小步长排序后,以前用的较大步长仍然是有序的。比如,如果一个数列以步长5进行了排序然后再以步长3进行排序,那么该数列不仅是以步长3有序,而且是以步长5有序。如果不是这样,那么算法在迭代过程中会打乱以前的顺序,那就

不会以如此短的时间完成排序了。

 算法稳定性:由上文的希尔排序算法演示图即可知,希尔排序中相等数据可能会交换位置,所以希尔排序是不稳定的算法。

插入排序和希尔排序比较:

直接插入排序是稳定的;而希尔排序是不稳定的。

直接插入排序更适合于原始记录基本有序的集合。

希尔排序的比较次数和移动次数都要比直接插入排序少,当N越大时,效果越明显。 

在希尔排序中,增量序列gap的取法必须满足:最后一个步长必须是 1 。 

直接插入排序也适用于链式存储结构;希尔排序不适用于链式结构。

希尔排序JAVA实现

 1 import java.util.Arrays;
 2 
 3 import static javaTest.SortUtils.less;
 4 
 5 /**
 6  * ClassName ShellSort.java
 7  * author Rhett.wang
 8  * version 1.0.0
 9  * Description TODO
10  * createTime 2020年01月18日 12:21:00
11  */
12 public class ShellSort implements SortAlgorithm {
13 
14     /**
15      * This method implements Generic Shell Sort.
16      *
17      * @param array the array to be sorted
18      */
19     @Override
20     public <T extends Comparable<T>> T[] sort(T[] array) {
21         int gap = array.length / 2;
22 
23         while (1 <= gap) {
24             // 把距离为 gap 的元素编为一个组,扫描所有组
25             for (int i = gap; i < array.length; i++) {
26                 int j = 0;
27                 T temp = array[i];
28 
29                 // 对距离为 gap 的元素组进行排序
30                 for (j = i - gap; j >= 0 &&less(temp,array[j]); j = j - gap) {
31                     array[j + gap] = array[j];
32                 }
33                 array[j + gap] = temp;
34             }
35 
36             System.out.format("gap = %d:\t", gap);
37             printAll(array);
38             gap = gap / 2; // 减小增量
39         }
40         return array;
41     }
42 
43     // 打印完整序列
44     public <T extends Comparable<T>> void printAll(T[] list) {
45         for (T value : list) {
46             System.out.print(value + "\t");
47         }
48         System.out.println();
49     }
50 
51     /* Driver Code */
52     public static void main(String[] args) {
53         Integer[] toSort = {4, 23, 6, 78, 1, 54, 231, 9, 12};
54 
55         ShellSort sort = new ShellSort();
56         System.out.println(Arrays.toString(sort.sort(toSort)));
57     }
58 }

希尔排序SCALA实现

 1 package scala
 2 
 3 /**
 4   * ClassName ShellSort.java
 5   * author Rhett.wang
 6   * version 1.0.0
 7   * Description TODO
 8   * createTime 2020年01月18日 13:25:00
 9   */
10 object ShellSort {
11   def main(args: Array[String]) {
12     var nums: Array[Int] = Array(2, 3, 8, 5, 4)
13     sort(nums)
14     nums.foreach(x => println(x))
15   }
16 
17   def sort(nums: Array[Int]): Array[Int] = {
18     var gap = nums.length / 2
19     while (1 <= gap) {
20       for (i <- gap until nums.length) {
21         var j = i
22         while (j >= 0 && nums(j-gap) > nums(j)) {
23           var temp = nums(j-gap)+nums(j)
24           nums(j - gap) =temp- nums(j-gap)
25           nums(j)=temp- nums(j-gap)
26           j=j-gap
27         }
28       }
29       gap = gap / 2
30     }
31     nums
32   }
33 }

希尔排序PYTHON实现

 1 def shell_sort(collection):
 2     gap = len(collection) // 2
 3     while (1 <= gap):
 4         for i in range(gap, len(collection)):
 5             j = i
 6             while (j >= 0 and collection[j - gap] > collection[j]):
 7                 tmp = collection[j - gap] + collection[j]
 8                 collection[j - gap] = tmp - collection[j - gap]
 9                 collection[j] = tmp - collection[j - gap]
10                 j = j- gap
11         gap = gap // 2
12     return collection
13 if __name__=="__main__":
14 
15      print(shell_sort([2, 3, 8, 5, 4, 9]))

简单选择排序

选择排序(Selection sort)是一种简单直观的排序算法。

它的基本思想是:首先在未排序的数列中找到最小(or最大)元素,然后将其存放到数列的起始位置;接着,再从剩余未排序的元素中继续寻找最小(or最大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

下面以数列{20,40,30,10,60,50}为例,演示它的选择排序过程(如下图):

第1趟:i=0。找出a[1...5]中的最小值a[3]=10,然后将a[0]和a[3]互换。 数列变化:20,40,30,10,60,50 -- > 10,40,30,20,60,50

第2趟:i=1。找出a[2...5]中的最小值a[3]=20,然后将a[1]和a[3]互换。 数列变化:10,40,30,20,60,50 -- > 10,20,30,40,60,50

第3趟:i=2。找出a[3...5]中的最小值,由于该最小值大于a[2],该趟不做任何处理。 

第4趟:i=3。找出a[4...5]中的最小值,由于该最小值大于a[3],该趟不做任何处理。 

第5趟:i=4。交换a[4]和a[5]的数据。 数列变化:10,20,30,40,60,50 -- > 10,20,30,40,50,60。

时间复杂度和稳定性

选择排序的时间复杂度是O(N2)。

假设被排序的数列中有N个数。遍历一趟的时间复杂度是O(N),需要遍历多少次呢?N-1!因此,选择排序的时间复杂度是O(N2)。

选择排序是稳定的算法,它满足稳定算法的定义。

算法稳定性 -- 假设在数列中存在a[i]=a[j],若在排序之前,a[i]在a[j]前面;并且排序之后,a[i]仍然在a[j]前面。则这个排序算法是稳定的!

选择排序JAVA实现

 1 import java.util.Arrays;
 2 
 3 import static javaTest.SortUtils.less;
 4 import static javaTest.SortUtils.swap;
 5 
 6 /**
 7  * ClassName SelectionSort.java
 8  * author Rhett.wang
 9  * version 1.0.0
10  * Description TODO
11  * createTime 2020年01月18日 17:10:00
12  */
13 public class SelectionSort implements SortAlgorithm {
14     public static void main(String[] args) {
15         Integer[] arr = {4, 23, 6, 78, 1, 54, 231, 9, 12};
16         SelectionSort sort = new SelectionSort();
17         System.out.println(Arrays.toString(sort.sort(arr)));
18     }
19     /**
20      * Main method arrays sorting algorithms
21      *
22      * @param unsorted - an array should be sorted
23      * @return a sorted array
24      */
25     @Override
26     public <T extends Comparable<T>> T[] sort(T[] unsorted) {
27         int n=unsorted.length;
28         for(int i=0;i<n-1;i++){
29             int min =i;
30             for(int j=i+1;j<n;j++){
31                 if(less(unsorted[j],unsorted[i])){
32                    min=j;
33                 }
34             }
35             if(min != i){
36                 swap(unsorted,i,min);
37             }
38         }
39         return unsorted;
40     }
41 }

工具类SortUtils

 1 /**
 2  * ClassName SortUtils.java
 3  * author Rhett.wang
 4  * version 1.0.0
 5  * Description TODO
 6  * createTime 2020年01月16日 17:49:00
 7  */
 8 import java.util.Arrays;
 9 import java.util.List;
10 
11 /**
12  * The class contains util methods
13  *
14  * @author Podshivalov Nikita (https://github.com/nikitap492)
15  **/
16 final class SortUtils {
17 
18     /**
19      * Helper method for swapping places in array
20      *
21      * @param array The array which elements we want to swap
22      * @param idx   index of the first element
23      * @param idy   index of the second element
24      */
25     static <T> boolean swap(T[] array, int idx, int idy) {
26         T swap = array[idx];
27         array[idx] = array[idy];
28         array[idy] = swap;
29         return true;
30     }
31 
32 
33     /**
34      * This method checks if first element is less then the other element
35      *
36      * @param v first element
37      * @param w second element
38      * @return true if the first element is less then the second element
39      */
40     static <T extends Comparable<T>> boolean less(T v, T w) {
41         return v.compareTo(w) < 0;
42     }
43 
44 
45     /**
46      * Just print list
47      *
48      * @param toPrint - a list which should be printed
49      */
50     static void print(List<?> toPrint) {
51         toPrint.stream()
52                 .map(Object::toString)
53                 .map(str -> str + " ")
54                 .forEach(System.out::print);
55 
56         System.out.println();
57     }
58 
59 
60     /**
61      * Prints an array
62      *
63      * @param toPrint - the array  which should be printed
64      */
65     static void print(Object[] toPrint) {
66         System.out.println(Arrays.toString(toPrint));
67     }
68 
69 
70     /**
71      * Swaps all position from {@param left} to @{@param right} for {@param array}
72      *
73      * @param array is an array
74      * @param left  is a left flip border of the array
75      * @param right is a right flip border of the array
76      */
77     static <T extends Comparable<T>> void flip(T[] array, int left, int right) {
78         while (left <= right) {
79             swap(array, left++, right--);
80         }
81     }
82 }

 选择排序SCALA实现

 1 /**
 2   * ClassName SelectionSort.java
 3   * author Rhett.wang
 4   * version 1.0.0
 5   * Description TODO
 6   * createTime 2020年01月18日 19:28:00
 7   */
 8 object SelectionSort {
 9   def main(args: Array[String]) {
10     var nums: Array[Int] = Array(2, 3, 8, 5, 4, 9)
11     sort(nums)
12     nums.foreach(x=>print(x))
13 
14   }
15   def sort(nums:Array[Int]):Array[Int]={
16     for(i <- 0 until nums.length){
17       var min:Int=i
18       var minVal=nums(i)
19       for(j <- i+1 to nums.length-1){
20         if(nums(j) < minVal){
21           min = j
22           minVal=nums(j)
23         }
24       }
25       val temp :Int=nums(i)
26       nums(i)=nums(min)
27       nums(min)=temp
28     }
29     nums
30   }
31 
32 }

选择排序PYTHON实现

 1 def selection_sort(arr):
 2     for i in range(1, len(arr)):
 3         key = arr[i]
 4         j = i - 1
 5         while j >= 0 and key < arr[j]:
 6             arr[j + 1] = arr[j]
 7             j -= 1
 8         arr[j + 1] = key
 9     return arr
10 if __name__=="__main__":
11 
12      print(selection_sort([2, 3, 8, 5, 4, 9, 2, 1]))

冒泡排序

冒泡排序(Bubble Sort),又被称为气泡排序或泡沫排序。

它是一种较简单的排序算法。它会遍历若干 次要排序的数列,每次遍历时,它都会从前往后依次的比较相邻两个数的大小;如果前者比后者大,则交换它们的位置。这样,一次遍历之后,最大的元素就在数列 的末尾! 采用相同的方法再次遍历时,第二大的元素就被排列在最大元素之前。重复此操作,直到整个数列都有序为止!

下面以数列{20,40,30,10,60,50}为例,演示它的冒泡排序过程(如下图)

当i=5,j=0时,a[0]<a[1]。此时,不做任何处理!

当i=5,j=1时,a[1]>a[2]。此时,交换a[1]和a[2]的值;交换之后,a[1]=30,a[2]=40。

当i=5,j=2时,a[2]>a[3]。此时,交换a[2]和a[3]的值;交换之后,a[2]=10,a[3]=40。

当i=5,j=3时,a[3]<a[4]。此时,不做任何处理!

当i=5,j=4时,a[4]>a[5]。此时,交换a[4]和a[5]的值;交换之后,a[4]=50,a[3]=60。

于是,第1趟排序完之后,数列{20,40,30,10,60,50}变成了{20,30,10,40,50,60}。此时,数列末尾的值最大。

时间复杂度和稳定性

冒泡排序的时间复杂度是O(N2)。

假设被排序的数列中有N个数。遍历一趟的时间复杂度是O(N),需要遍历多少次呢?N-1次!因此,冒泡排序的时间复杂度是O(N2)。

冒泡排序是稳定的算法,它满足稳定算法的定义。

算法稳定性 -- 假设在数列中存在a[i]=a[j],若在排序之前,a[i]在a[j]前面;并且排序之后,a[i]仍然在a[j]前面。则这个排序算法是稳定的!

冒泡排序JAVA实现

 1 import java.util.Arrays;
 2 
 3 import static javaTest.SortUtils.less;
 4 import static javaTest.SortUtils.swap;
 5 
 6 /**
 7  * ClassName BubbleSort.java
 8  * author Rhett.wang
 9  * version 1.0.0
10  * Description TODO
11  * createTime 2020年01月18日 20:06:00
12  */
13 class BubbleSort implements SortAlgorithm {
14     /**
15      * This method implements the Generic Bubble Sort
16      *
17      * @param array The array to be sorted
18      *              Sorts the array in increasing order
19      **/
20 
21     @Override
22     public <T extends Comparable<T>> T[] sort(T[] array) {
23         for (int i = 0, size = array.length; i < size - 1; ++i) {
24             boolean swapped = false;
25             for (int j = 0; j < size - 1 - i; ++j) {
26                 if (less(array[j], array[j + 1])) {
27                     swap(array, j, j + 1);
28                     swapped = true;
29                 }
30             }
31             if (!swapped) {
32                 break;
33             }
34         }
35         return array;
36     }
37 
38     // Driver Program
39     public static void main(String[] args) {
40 
41         // Integer Input
42         Integer[] integers = {4, 23, 6, 78, 1, 54, 231, 9, 12};
43         BubbleSort bubbleSort = new BubbleSort();
44         bubbleSort.sort(integers);
45 
46         // Output => 231, 78, 54, 23, 12, 9, 6, 4, 1
47         System.out.println(Arrays.toString(integers));
48 
49 
50         // String Input
51         String[] strings = {"c", "a", "e", "b", "d"};
52         //Output => e, d, c, b, a
53         System.out.println(Arrays.toString(strings));
54     }
55 }

冒泡排序SCALA实现

 1 import util.control.Breaks._
 2 /**
 3   * ClassName BubbleSort.java
 4   * author Rhett.wang
 5   * version 1.0.0
 6   * Description TODO
 7   * createTime 2020年01月18日 20:23:00
 8   */
 9 object BubbleSort {
10   def main(args: Array[String]) {
11     var nums: Array[Int] = Array(2, 3, 8, 5, 4, 9)
12     bubbleSort(nums)
13     nums.foreach(x=>print(x))
14   }
15 
16   def bubbleSort(array: Array[Int]) :  Array[Int] = {
17     breakable {
18       for (i <- 0 to array.length - 1) {
19         var swap = false
20 
21         for (j <- 0 to array.length - 2) {
22           if (array(j) > array(j + 1)) {
23             val temp = array(j)
24             array(j) = array(j + 1)
25             array(j + 1) = temp
26             swap = true
27           }
28         }
29 
30         if (!swap) {
31           break
32         }
33       }
34     }
35     array
36   }
37 }

冒泡排序PYTHON实现

 1 def bubble_sort(collection):
 2     length = len(collection)
 3     for i in range(length - 1):
 4         swapped = False
 5         for j in range(length - 1 - i):
 6             if collection[j] > collection[j + 1]:
 7                 swapped = True
 8                 collection[j], collection[j + 1] = collection[j + 1], collection[j]
 9         if not swapped:
10             break  # Stop iteration if the collection is sorted.
11     return collection
12 if __name__=="__main__":
13 
14      print(bubble_sort([2, 3, 8, 5, 4, 9, 2, 1]))

快速排序

快速排序(Quick Sort)使用分治法策略。

它的基本思想是:选择一个基准数,通过一趟排序将要排序的数据分割成独立的两部分;其中一部分的所有数据都比另外一部分的所有数据都要小。然后,再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

排序流程:

从数列中挑出一个基准值。

将所有比基准值小的摆放在基准前面,所有比基准值大的摆在基准的后面(相同的数可以到任一边);在这个分区退出之后,该基准就处于数列的中间位置。

递归地把"基准值前面的子数列"和"基准值后面的子数列"进行排序

下面以数列a={30,40,60,10,20,50}为例,演示它的快速排序过程(如下图):

上图只是给出了第1趟快速排序的流程。在第1趟中,设置x=a[i],即x=30。

从"右 --> 左"查找小于x的数:找到满足条件的数a[j]=20,此时j=4;然后将a[j]赋值a[i],此时i=0;接着从左往右遍历。

从"左 --> 右"查找大于x的数:找到满足条件的数a[i]=40,此时i=1;然后将a[i]赋值a[j],此时j=4;接着从右往左遍历。

从"右 --> 左"查找小于x的数:找到满足条件的数a[j]=10,此时j=3;然后将a[j]赋值a[i],此时i=1;接着从左往右遍历。

从"左 --> 右"查找大于x的数:找到满足条件的数a[i]=60,此时i=2;然后将a[i]赋值a[j],此时j=3;接着从右往左遍历。

从"右 --> 左"查找小于x的数:没有找到满足条件的数。当i>=j时,停止查找;然后将x赋值给a[i]。此趟遍历结束!

按照同样的方法,对子数列进行递归遍历。最后得到有序数组。

快速排序的时间复杂度和稳定性

快速排序稳定性

快速排序是不稳定的算法,它不满足稳定算法的定义。

算法稳定性 -- 假设在数列中存在a[i]=a[j],若在排序之前,a[i]在a[j]前面;并且排序之后,a[i]仍然在a[j]前面。则这个排序算法是稳定的!

快速排序时间复杂度

快速排序的时间复杂度在最坏情况下是O(N2),平均的时间复杂度是O(N*lgN)。

这句话很好理解:假设被排序的数列中有N个数。遍历一次的时间复杂度是O(N),需要遍历多少次呢?至少lg(N+1)次,最多N次。

(01) 为什么最少是lg(N+1)次?快速排序是采用的分治法进行遍历的,我们将它看作一棵二叉树,它需要遍历的次数就是二叉树的深度,而根据完全二叉树的定义,它的深度至少是lg(N+1)。因此,快速排序的遍历次数最少是lg(N+1)次。

(02) 为什么最多是N次?这个应该非常简单,还是将快速排序看作一棵二叉树,它的深度最大是N。因此,快读排序的遍历次数最多是N次。

快速排序JAVA实现

  1 import static Sorts.SortUtils.*;
  2 
  3 /**
  4  * @author Varun Upadhyay (https://github.com/varunu28)
  5  * @author Podshivalov Nikita (https://github.com/nikitap492)
  6  * @see SortAlgorithm
  7  */
  8 class QuickSort implements SortAlgorithm {
  9 
 10     /**
 11      * This method implements the Generic Quick Sort
 12      *
 13      * @param array The array to be sorted
 14      *              Sorts the array in increasing order
 15      **/
 16 
 17     @Override
 18     public <T extends Comparable<T>> T[] sort(T[] array) {
 19         doSort(array, 0, array.length - 1);
 20         return array;
 21     }
 22 
 23 
 24     /**
 25      * The sorting process
 26      *
 27      * @param left  The first index of an array
 28      * @param right The last index of an array
 29      * @param array The array to be sorted
 30      **/
 31 
 32     private static <T extends Comparable<T>> void doSort(T[] array, int left, int right) {
 33         if (left < right) {
 34             int pivot = randomPartition(array, left, right);
 35             doSort(array, left, pivot - 1);
 36             doSort(array, pivot, right);
 37         }
 38     }
 39 
 40     /**
 41      * Ramdomize the array to avoid the basically ordered sequences
 42      * 
 43      * @param array The array to be sorted
 44      * @param left  The first index of an array
 45      * @param right The last index of an array
 46      * @return the partition index of the array
 47      */
 48 
 49     private static <T extends Comparable<T>> int randomPartition(T[] array, int left, int right) {
 50         int randomIndex = left + (int)(Math.random()*(right - left + 1));
 51         swap(array, randomIndex, right);
 52         return partition(array, left, right);
 53     }
 54 
 55     /**
 56      * This method finds the partition index for an array
 57      *
 58      * @param array The array to be sorted
 59      * @param left  The first index of an array
 60      * @param right The last index of an array
 61      *              Finds the partition index of an array
 62      **/
 63 
 64     private static <T extends Comparable<T>> int partition(T[] array, int left, int right) {
 65         int mid = (left + right) / 2;
 66         T pivot = array[mid];
 67 
 68         while (left <= right) {
 69             while (less(array[left], pivot)) {
 70                 ++left;
 71             }
 72             while (less(pivot, array[right])) {
 73                 --right;
 74             }
 75             if (left <= right) {
 76                 swap(array, left, right);
 77                 ++left;
 78                 --right;
 79             }
 80         }
 81         return left;
 82     }
 83 
 84     // Driver Program
 85     public static void main(String[] args) {
 86 
 87         // For integer input
 88         Integer[] array = {3, 4, 1, 32, 0, 1, 5, 12, 2, 5, 7, 8, 9, 2, 44, 111, 5};
 89 
 90         QuickSort quickSort = new QuickSort();
 91         quickSort.sort(array);
 92 
 93         //Output => 0 1 1 2 2 3 4 5 5 5 7 8 9 12 32 44 111
 94         print(array);
 95 
 96         String[] stringArray = {"c", "a", "e", "b", "d"};
 97         quickSort.sort(stringArray);
 98 
 99         //Output => a    b    c    d    e
100         print(stringArray);
101     }
102 }

快速排序SCALA实现

 1 object QuickSort {
 2   /**
 3     *
 4     * @param array - a sequence of unsorted integers
 5     * @return - sequence of sorted integers @array
 6     */
 7 
 8   def quickSort(array: Array[Int]): Array[Int] = {
 9 
10     def quickSortImpl(array: Array[Int], first: Int, last: Int): Array[Int] = {
11       var pivot: Int = 0
12       var i: Int = 0
13       var j: Int = 0
14       var temp: Int = 0
15 
16       if (first < last) {
17         pivot = first
18         i = first
19         j = last
20 
21         while (i < j) {
22           while (array(i) <= array(pivot) && i < last) {
23             i += 1
24           }
25 
26           while (array(j) > array(pivot)) {
27             j -= 1
28           }
29 
30           if (i < j) {
31             temp = array(i)
32             array(i) = array(j)
33             array(j) = temp
34           }
35         }
36 
37         temp = array(pivot)
38         array(pivot) = array(j)
39         array(j) = temp
40         quickSortImpl(array, first, j - 1)
41         quickSortImpl(array, j + 1, last)
42       }
43 
44       array
45     }
46 
47     quickSortImpl(array,0, array.length-1)
48   }
49 }

快速排序PYTHON实现

 1 def quick_sort_3partition(sorting, left, right):
 2     if right <= left:
 3         return
 4     a = i = left
 5     b = right
 6     pivot = sorting[left]
 7     while i <= b:
 8         if sorting[i] < pivot:
 9             sorting[a], sorting[i] = sorting[i], sorting[a]
10             a += 1
11             i += 1
12         elif sorting[i] > pivot:
13             sorting[b], sorting[i] = sorting[i], sorting[b]
14             b -= 1
15         else:
16             i += 1
17     quick_sort_3partition(sorting, left, a - 1)
18     quick_sort_3partition(sorting, b + 1, right)
19 
20 
21 if __name__ == "__main__":
22     user_input = input("Enter numbers separated by a comma:\n").strip()
23     unsorted = [int(item) for item in user_input.split(",")]
24     quick_sort_3partition(unsorted, 0, len(unsorted) - 1)
25     print(unsorted)

归并排序

归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分 治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶 段得到的各答案"修补"在一起,即分而治之)。

 可以看到这种结构很像一棵完全二叉树,本文的归并排序我们采用递归去实现(也可采用迭代的方式去实现)。分阶段可以理解为就是递归拆分子序列的过程,递归深度为log2n。

合并相邻有序子序列

再来看看治阶段,我们需要将两个已经有序的子序列合并成一个有序序列,比如上图中的最后一次合并,要将[4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终序列[1,2,3,4,5,6,7,8],来看下实现步骤。

归并排序JAVA实现

 1 import static Sorts.SortUtils.print;
 2 
 3 /**
 4  * This method implements the Generic Merge Sort
 5  *
 6  * @author Varun Upadhyay (https://github.com/varunu28)
 7  * @author Podshivalov Nikita (https://github.com/nikitap492)
 8  * @see SortAlgorithm
 9  */
10 
11 class MergeSort implements SortAlgorithm {
12 
13     /**
14      * This method implements the Generic Merge Sort
15      *
16      * @param unsorted the array which should be sorted
17      * @param <T>      Comparable class
18      * @return sorted array
19      */
20     @Override
21     @SuppressWarnings("unchecked")
22     public <T extends Comparable<T>> T[] sort(T[] unsorted) {
23         doSort(unsorted, 0, unsorted.length - 1);
24         return unsorted;
25     }
26 
27     /**
28      * @param arr   The array to be sorted
29      * @param left  The first index of the array
30      * @param right The last index of the array
31      *              Recursively sorts the array in increasing order
32      **/
33     private static <T extends Comparable<T>> void doSort(T[] arr, int left, int right) {
34         if (left < right) {
35             int mid = left + (right - left) / 2;
36             doSort(arr, left, mid);
37             doSort(arr, mid + 1, right);
38             merge(arr, left, mid, right);
39         }
40 
41     }
42 
43     /**
44      * This method implements the merge step of the merge sort
45      *
46      * @param arr   The array to be sorted
47      * @param left  The first index of the array
48      * @param mid   The middle index of the array
49      * @param right The last index of the array
50      *              merges two parts of an array in increasing order
51      **/
52 
53     private static <T extends Comparable<T>> void merge(T[] arr, int left, int mid, int right) {
54         int length = right - left + 1;
55         T[] temp = (T[]) new Comparable[length];
56         int i = left;
57         int j = mid + 1;
58         int k = 0;
59 
60         while (i <= mid && j <= right) {
61             if (arr[i].compareTo(arr[j]) <= 0) {
62                 temp[k++] = arr[i++];
63             } else {
64                 temp[k++] = arr[j++];
65             }
66         }
67 
68         while (i <= mid) {
69             temp[k++] = arr[i++];
70         }
71 
72         while (j <= right) {
73             temp[k++] = arr[j++];
74         }
75 
76         System.arraycopy(temp, 0, arr, left, length);
77     }
78 
79     // Driver program
80     public static void main(String[] args) {
81 
82         // Integer Input
83         Integer[] arr = {4, 23, 6, 78, 1, 54, 231, 9, 12};
84         MergeSort mergeSort = new MergeSort();
85         mergeSort.sort(arr);
86 
87         // Output => 1       4       6    9    12    23    54    78    231
88         print(arr);
89 
90         // String Inpu
91         String[] stringArray = {"c", "a", "e", "b", "d"};
92         mergeSort.sort(stringArray);
93         //Output => a    b    c    d    e
94         print(stringArray);
95     }
96 }

归并排序SCALA实现

 1 object MergeSort {
 2 
 3   /**
 4     *
 5     * @param array   - a sequence of unsorted integers
 6     * @return - sequence of sorted integers @array
 7     */
 8 
 9   def mergeSort(array: Array[Int]): Array[Int] = {
10 
11     def sort(array: Array[Int]): Array[Int] = {
12       MS(array, 0, array.length - 1)
13     }
14 
15     def MS(array: Array[Int], low: Int, high: Int): Array[Int] = {
16       if (low < high) {
17         val mid = (low + high) / 2
18         MS(array, low, mid)
19         MS(array, mid + 1, high)
20         merge(array, low, mid, high)
21       } else {
22         array
23       }
24     }
25 
26     def merge(array: Array[Int], low: Int, mid: Int, high: Int): Array[Int] = {
27       // copy subarrays
28       val left = array.slice(low, mid + 1)
29       val right = array.slice(mid + 1, high + 1)
30 
31       var i = 0
32       var j = 0
33       var k = low
34       while (k < high + 1) {
35         // must check if empty to avoid exceptions
36         if (i > left.length - 1) {
37           array(k) = right(j)
38           j = j + 1
39         } else if (j > right.length - 1) {
40           array(k) = left(i)
41           i = i + 1
42         } else if (left(i) <= right(j)) {
43           array(k) = left(i)
44           i = i + 1
45         } else {
46           array(k) = right(j)
47           j = j + 1
48         }
49         k = k + 1
50       }
51 
52       array
53 
54     }
55 
56     sort(array)
57   }
58 
59 }

归并排序PYTHON实现

 1 def merge_sort(collection):
 2     """Pure implementation of the merge sort algorithm in Python
 3     :param collection: some mutable ordered collection with heterogeneous
 4     comparable items inside
 5     :return: the same collection ordered by ascending
 6     Examples:
 7     >>> merge_sort([0, 5, 3, 2, 2])
 8     [0, 2, 2, 3, 5]
 9     >>> merge_sort([])
10     []
11     >>> merge_sort([-2, -5, -45])
12     [-45, -5, -2]
13     """
14 
15     def merge(left, right):
16         """merge left and right
17         :param left: left collection
18         :param right: right collection
19         :return: merge result
20         """
21         result = []
22         while left and right:
23             result.append((left if left[0] <= right[0] else right).pop(0))
24         return result + left + right
25 
26     if len(collection) <= 1:
27         return collection
28     mid = len(collection) // 2
29     return merge(merge_sort(collection[:mid]), merge_sort(collection[mid:]))
30 
31 
32 if __name__ == "__main__":
33     user_input = input("Enter numbers separated by a comma:\n").strip()
34     unsorted = [int(item) for item in user_input.split(",")]
35     print(*merge_sort(unsorted), sep=",")

堆排序

堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。首先简单了解下堆结构。

堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。如下图:

 同时,我们对堆中的结点按层进行编号,将这种逻辑结构映射到数组中就是下面这个样子:

 该数组从逻辑上讲就是一个堆结构,我们用简单的公式来描述一下堆的定义就是:

大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]  

小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]  

堆排序基本思想及步骤

 堆排序的基本思想是:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。

步骤一 构造初始堆。将给定无序序列构造成一个大顶堆(一般升序采用大顶堆,降序采用小顶堆):

1.假设给定无序序列结构如下:

 2.此时我们从最后一个非叶子结点开始(叶结点自然不用调整,第一个非叶子结点 arr.length/2-1=5/2-1=1,也就是下面的6结点),从左至右,从下至上进行调整。

 3.找到第二个非叶节点4,由于[4,9,8]中9元素最大,4和9交换。

这时,交换导致了子根[4,5,6]结构混乱,继续调整,[4,5,6]中6最大,交换4和6。

 

此时,我们就将一个无需序列构造成了一个大顶堆。

步骤二 将堆顶元素与末尾元素进行交换,使末尾元素最大。然后继续调整堆,再将堆顶元素与末尾元素交换,得到第二大元素。如此反复进行交换、重建、交换。

a.将堆顶元素9和末尾元素4进行交换。

b.重新调整结构,使其继续满足堆定义

 

c.再将堆顶元素8与末尾元素5进行交换,得到第二大元素8.

 

 后续过程,继续进行调整,交换,如此反复进行,最终使得整个序列有序

再简单总结下堆排序的基本思路:

将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;

将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;

重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。

堆排序是一种选择排序,整体主要由构建初始堆+交换堆顶元素和末尾元素并重建堆两部分组成。其中构建初始堆经推导复杂度为O(n),在交换并重建堆的过程中,需交换n-1次,而重建堆的过程中,根据完全二叉树的性质,[log2(n-1),log2(n-2)...1]逐步递减,近似为nlogn。所以堆排序时间复杂度一般认为就是O(nlogn)级。

堆排序JAVA实现

 1 package javaTest;
 2 
 3 import java.util.ArrayList;
 4 import java.util.Arrays;
 5 import java.util.List;
 6 
 7 import static javaTest.SortUtils.less;
 8 import static javaTest.SortUtils.swap;
 9 import static javafx.scene.input.KeyCode.T;
10 
11 /**
12  * ClassName HeapSort.java
13  * author Rhett.wang
14  * version 1.0.0
15  * Description TODO
16  * createTime 2020年02月06日 09:19:00
17  */
18 public class HeapSort implements SortAlgorithm {
19     public static void main(String[] args) {
20         Integer[] heap = {4, 23, 6, 78, 1, 54, 231, 9, 12};
21         HeapSort heapSort = new HeapSort();
22         System.out.println(heapSort.sort(heap));
23     }
24     /**
25      * Main method arrays sorting algorithms
26      *
27      * @param unsorted - an array should be sorted
28      * @return a sorted array
29      */
30     @Override
31     public <T extends Comparable<T>> T[] sort(T[] unsorted) {
32         return sort(Arrays.asList(unsorted)).toArray(unsorted);
33     }
34     @Override
35     public <T extends Comparable<T>> List<T> sort(List<T> unsorted){
36         int size = unsorted.size();
37         Heap<T> heap=new Heap<>(unsorted.toArray((T[]) new Comparable[unsorted.size()]));
38         heap.makeMinHeap(0);
39         List<T> sorted=new ArrayList<>(size);
40         while(size>0){
41             T min =heap.getRoot(--size);
42             sorted.add(min);
43         }
44         return sorted;
45     }
46     private static class Heap<T extends Comparable<T>>{
47         private T[] heap;
48         public Heap(T[] heap){
49             this.heap=heap;
50         }
51         public T getRoot(int size){
52             swap(heap,0,size);
53             heapSubtree(0,size-1);
54             return heap[size];
55         }
56         private void heapSubtree(int rootIndex,int lastChild){
57             int leftIndex=rootIndex*2 +1;
58             int rightIndex=rootIndex*2 +2;
59             T root =heap[rootIndex];
60             if(rightIndex<=lastChild){
61                 T left=heap[leftIndex];
62                 T right=heap[rightIndex];
63                 if(less(left,right) && less(left,root)){
64                     swap(heap,leftIndex,rootIndex);
65                     heapSubtree(leftIndex,lastChild);
66                 }else if(less(right,root)){
67                     swap(heap,rightIndex,rootIndex);
68                     heapSubtree(rightIndex,lastChild);
69                 }
70             }else if(leftIndex<=lastChild){
71                 T left=heap[leftIndex];
72                 if(less(left,root)){
73                     swap(heap,leftIndex,rootIndex);
74                     heapSubtree(leftIndex,lastChild);
75                 }
76             }
77         }
78         private void makeMinHeap(int root){
79             int leftIndex=root*2+1;
80             int rightIndex=root*2+2;
81             boolean hasLeftChild=leftIndex<heap.length;
82             boolean hasRightChild=rightIndex<heap.length;
83 
84             if(hasRightChild){
85                 makeMinHeap(leftIndex);
86                 makeMinHeap(rightIndex);
87                 heapSubtree(root,heap.length-1);
88             }else if(hasLeftChild){
89                 heapSubtree(root,heap.length-1);
90             }
91         }
92 
93     }
94 }

java第二种方式实现

 1 package javaTest;
 2 
 3 import java.util.Arrays;
 4 
 5 /**
 6  * ClassName HeapSort1.java
 7  * author Rhett.wang
 8  * version 1.0.0
 9  * Description TODO
10  * createTime 2020年02月06日 10:57:00
11  */
12 public class HeapSort1 {
13     public static void main(String[] args) {
14         int []arr = {9,8,7,6,5,4,3,2,1};
15         sort(arr);
16         System.out.println(Arrays.toString(arr));
17     }
18     public static void swap(int[] arr,int a,int b){
19         int temp=arr[a];
20         arr[a]=arr[b];
21         arr[b]=temp;
22     }
23     public static void adjustHeap(int[] arr,int i,int length){
24         int temp=arr[i];
25         for(int k=i*2+1;k<length;k=k*2+1){
26             if(k+1<length && arr[k]<arr[k+1]){
27                 k++;
28             }
29             if(arr[k]>temp){
30                 arr[i]=arr[k];
31                 i=k;
32             }else{
33                 break;
34             }
35         }
36         arr[i]=temp;
37     }
38     public static void sort(int[] arr){
39         for(int i=arr.length/2-1;i>=0;i--){
40             adjustHeap(arr,i,arr.length);
41         }
42         for(int j=arr.length-1;j>0;j--){
43             swap(arr,0,j);
44             adjustHeap(arr,0,j);
45         }
46     }
47 }

堆排序SCALA实现

 1 package scala
 2 
 3 /**
 4   * ClassName HeapSort1.java
 5   * author Rhett.wang
 6   * version 1.0.0
 7   * Description TODO
 8   * createTime 2020年02月05日 10:27:00
 9   */
10 object HeapSort1 {
11   def main(args: Array[String]) {
12      println(heapsort(Array(8,3,2,4,1,9,7,19,18,14,15)).toList)
13   }
14   def heapsort(arr:Array[Int]):Array[Int]={
15 
16     val sortedArray=arr.clone()
17     def sift(start:Int,count:Int): Unit ={
18       var root=start
19 
20       while(root*2+1<count){
21         var child =root*2+1
22         if(child<count-1 &&sortedArray(child)<sortedArray(child+1)){
23           child +=1
24         }
25         if(sortedArray(root)<sortedArray(child)){
26           val t=sortedArray(root)
27           sortedArray(root)=sortedArray(child)
28           sortedArray(child)=t
29           root=child
30         }else return
31       }
32     }
33     var count=sortedArray.length
34     var start=count/2-1
35     var end=count-1
36     while(start>=0){
37       sift(start,count)
38       start -=1
39     }
40     println(sortedArray.toList)
41     while(end>0){
42       val t=sortedArray(end)
43       sortedArray(end)=sortedArray(0)
44       sortedArray(0)=t
45       sift(0,end)
46       end -=1
47     }
48 
49     sortedArray
50   }
51 
52 }

堆排序PYTHON实现

 1 def heapif(unsorted,index,heap_size):
 2     largest=index
 3     left_index = 2*index +1
 4     right_index=2*index + 2
 5     if left_index < heap_size and unsorted[left_index] >unsorted[largest]:
 6         largest = left_index
 7     if right_index < heap_size and unsorted[right_index] > unsorted[largest]:
 8         largest=right_index
 9 
10     if largest != index:
11         unsorted[largest] , unsorted[index] = unsorted[index],unsorted[largest]
12         heapif(unsorted,largest,heap_size)
13 
14 def heap_sort(unsorted):
15     n =len(unsorted)
16     for i in range(n//2-1,-1,-1):
17         heapif(unsorted,i,n)
18     for i in range(n-1,0,-1):
19         unsorted[0],unsorted[i] =unsorted[i],unsorted[0]
20         heapif(unsorted,0,i)
21 
22     return unsorted
23 
24 if __name__ == "__main__":
25     unsorted =[9,5,8,3,2,7]
26     test = heap_sort(unsorted)
27     print(test)

基数排序

基数排序与本系列前面讲解的七种排序方法都不同,它不需要比较关键字的大小

它是根据关键字中各位的值,通过对排序的N个元素进行若干趟“分配”与“收集”来实现排序的。 

不妨通过一个具体的实例来展示一下,基数排序是如何进行的。 设有一个初始序列为: R {50, 123, 543, 187, 49, 30, 0, 2, 11, 100}。

我们知道,任何一个阿拉伯数,它的各个位数上的基数都是以0~9来表示的。所以我们不妨把0~9视为10个桶。 

我们先根据序列的个位数的数字来进行分类,将其分到指定的桶中。例如:R[0] = 50,个位数上是0,将这个数存入编号为0的桶中。

分类后,我们在从各个桶中,将这些数按照从编号0到编号9的顺序依次将所有数取出来。这时,得到的序列就是个位数上呈递增趋势的序列。 

按照个位数排序: {50, 30, 0, 100, 11, 2, 123, 543, 187, 49}。接下来,可以对十位数、百位数也按照这种方法进行排序,最后就能得到排序完成的序列。

算法分析

时间复杂度

通过上文可知,假设在基数排序中,r为基数,d为位数。则基数排序的时间复杂度为O(d(n+r))。我们可以看出,基数排序的效率和初始序列是否有序没有关联。

空间复杂度

在基数排序过程中,对于任何位数上的基数进行“装桶”操作时,都需要n+r个临时空间。

算法稳定性

在基数排序过程中,每次都是将当前位数上相同数值的元素统一“装桶”,并不需要交换位置。所以基数排序是稳定的算法。

基数排序JAVA实现

 1 package notes.javase.algorithm.sort;
 2 public class RadixSort {
 3    // 获取x这个数的d位数上的数字
 4    // 比如获取123的1位数,结果返回3
 5    public int getDigit(int x, int d) {
 6        int a[] = {
 7                1, 1, 10, 100
 8        }; // 本实例中的最大数是百位数,所以只要到100就可以了
 9        return ((x / a[d]) % 10);
10    }
11 
12    public void radixSort(int[] list, int begin, int end, int digit) {
13        final int radix = 10; // 基数
14        int i = 0, j = 0;
15        int[] count = new int[radix]; // 存放各个桶的数据统计个数
16        int[] bucket = new int[end - begin + 1];
17        // 按照从低位到高位的顺序执行排序过程
18        for (int d = 1; d <= digit; d++) {
19            // 置空各个桶的数据统计
20            for (i = 0; i < radix; i++) {
21                count[i] = 0;
22            }
23            // 统计各个桶将要装入的数据个数
24            for (i = begin; i <= end; i++) {
25                j = getDigit(list[i], d);
26                count[j]++;
27            }
28 
29            // count[i]表示第i个桶的右边界索引
30            for (i = 1; i < radix; i++) {
31                count[i] = count[i] + count[i - 1];
32            }
33 
34            // 将数据依次装入桶中
35            // 这里要从右向左扫描,保证排序稳定性
36            for (i = end; i >= begin; i--) {
37                j = getDigit(list[i], d); 
38                // 求出关键码的第k位的数字, 例如:576的第3位是5
39                bucket[count[j] - 1] = list[i]; 
40                // 放入对应的桶中,count[j]-1是第j个桶的右边界索引
41                count[j]--; // 对应桶的装入数据索引减一
42            }
43            // 将已分配好的桶中数据再倒出来,此时已是对应当前位数有序的表
44            for (i = begin, j = 0; i <= end; i++, j++) {
45                list[i] = bucket[j];
46            }
47        }
48    }
49 
50    public int[] sort(int[] list) {
51        radixSort(list, 0, list.length - 1, 3);
52        return list;
53    }
54 
55    // 打印完整序列
56    public void printAll(int[] list) {
57        for (int value : list) {
58            System.out.print(value + "\t");
59        }
60        System.out.println();
61    }
62 
63    public static void main(String[] args) {
64        int[] array = {
65                50, 123, 543, 187, 49, 30, 0, 2, 11, 100
66        };
67        RadixSort radix = new RadixSort();
68        System.out.print("排序前:\t\t");
69        radix.printAll(array);
70        radix.sort(array);
71        System.out.print("排序后:\t\t");
72        radix.printAll(array);
73    }
74 }

基数排序PYTHON实现

 1 def radix_sort(lst):
 2     RADIX = 10
 3     placement = 1
 4 
 5     # get the maximum number
 6     max_digit = max(lst)
 7 
 8     while placement < max_digit:
 9         # declare and initialize buckets
10         buckets = [list() for _ in range(RADIX)]
11 
12         # split lst between lists
13         for i in lst:
14             tmp = int((i / placement) % RADIX)
15             buckets[tmp].append(i)
16 
17         # empty lists into lst array
18         a = 0
19         for b in range(RADIX):
20             buck = buckets[b]
21             for i in buck:
22                 lst[a] = i
23                 a += 1
24 
25         # move to next
26         placement *= RADIX

总结

感谢网络大神的分享:

https://github.com/TheAlgorithms/

https://mp.weixin.qq.com/s?__biz=MzAxNjk4ODE4OQ==&mid=2247487903&idx=3&sn=f482041f5b560ca85db9ad51c33f07f3&chksm=9bed30edac9ab9fbb523b1ce15e545d126e2b6a651951f8ea672d5f6d05809b9ae8f99d81411&mpshare=1&scene=1&srcid=0113MrSScIDzFwL6luR7bevY&sharer_sharetime=1579050754003&sharer_shareid=d40e8d2bb00008844e69867bcfc0d895#rd

posted on 2020-01-18 21:12  伯安知心  阅读(547)  评论(0编辑  收藏  举报

导航