数据结构之排序基础知识笔记
概述
最近在温习数据结构,现在针对排序算法写一篇随笔,其中附带原理说明和代码。
插入排序
直接插入排序(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