zoukankan      html  css  js  c++  java
  • 数据结构之排序基础知识笔记

    概述

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

    插入排序

    直接插入排序(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:
    ").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:	", 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 + "	");
    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:
    ").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:
    ").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 + "	");
    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("排序前:		");
    69        radix.printAll(array);
    70        radix.sort(array);
    71        System.out.print("排序后:		");
    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

  • 相关阅读:
    别再乱升级 MySQL 驱动了。。
    Spring Boot + MyBatis + MySQL 实现读写分离
    多线程环境下,HashMap 为什么会出现死循环?
    亿级流量架构怎么做资源隔离?写得太好了!
    refdeveloptools for developers
    how to setup ppc2003 or smartphone 2003 to connect to internet
    转载:一篇java与C#的对比文章(英文)
    在sqlexpress中添加DB和在sql analyzer中操作DB.
    windows 2003下配置IIS6为iis5方式的隔离模式运行
    开源的pop3和smtp组件(支持中文及SSL)
  • 原文地址:https://www.cnblogs.com/boanxin/p/12208642.html
Copyright © 2011-2022 走看看