zoukankan      html  css  js  c++  java
  • 常用排序算法及Java实现

    排序算法,可以分为内部排序和外部排序两大种。这篇文章主要对内部排序进行介绍。内部排序又分为两类,基于比较的非线性时间类,和非比较的线性时间类。前一类又可以分为四种,交换排序(包括冒泡排序和快速排序),插入排序(包括简单插入排序和希尔排序),选择排序(包括简单选择排序和堆排序)以及归并排序;后者主要包含三种,计数排序,桶排序和基数排序。

    总体来说,快排、堆排和归并排序是非线性时间中最快的三种。一般认为,快排的时间效率会比堆排更好。另一方面,快排和堆排都是不稳定的算法,只有归并排序、冒泡排序和插入排序是稳定的算法,因此Java中的sort算法在实现的时候,有一个阈值,大概是60左右。数组长度低于这个阈值的,直接使用插入排序;高于这个阈值的,如果元素是基本数据类型,救使用快排,如果是引用数据类型,就使用归并排序。而对于基于比较的排序算法,都很依赖于数据本身的分布——在数据均匀分布的情况下,效率可以很高。计数排序是用来排序0到100之间的数字的最好的算法,但是它不适合按字母顺序排序人名;计数排序则要求对每一位使用的排序算法都是稳定的。

    下面我们对这九种算法进行详细的介绍。为了方便,我们设定所有的排序都基于整形数组,需要按照从小到大的顺序进行排列。在这些排序算法中,有一些公用的操作,比如元素交换,元素打印,寻找最大值最小值等,为了代码的复用,我们定义了工具类Tools,首先给出Tools类的代码。

     1 public class Tools {
     2     public static void swap(int[] arr, int i, int j) {
     3         int tmp = arr[i];
     4         arr[i] = arr[j];
     5         arr[j] = tmp;
     6     }
     7 
     8     public static void printArray(int[] arr) {
     9         int i = 0;
    10         System.out.print("[");
    11         for (; i < arr.length - 1; i++) {
    12             System.out.print(arr[i] + ",");
    13         }
    14         System.out.println(arr[i] + "]");
    15     }
    16 
    17     public static int findMax(int[] arr) {
    18         int max = Integer.MIN_VALUE;
    19         for (int num : arr) {
    20             max = Math.max(max, num);
    21         }
    22         return max;
    23     }
    24 
    25     public static int findMin(int[] arr) {
    26         int min = Integer.MAX_VALUE;
    27         for (int num : arr) {
    28             min = Math.min(min, num);
    29         }
    30         return min;
    31     }
    32 }

    1、交换算法

    1.1 冒泡算法

    整体思路:第i轮排序,从第0号元素到第(length-1-i)号元素,进行相邻元素的比较,并将较大的元素不断交换到后一位置。

    特点:第i轮排序完成后,第i个最大值出现在下标为(length-1-i)的位置。

    时间复杂度:最坏:O(n^2),平均:O(n^2),最好:O(n);

    空间复杂度:O(1)

    稳定性:稳定,但是当条件变为arr[j] >= arr[j + 1]时,就不稳定了

    Java实现:

     1 /**
     2  *  3  *
     4  *         以整型数组为例,通过冒泡排序将数组中的元素按从小到大的顺序进行排列
     5  *         思路:第i轮排序,从第0号元素到第(length-1-i)号元素,进行相邻元素的比较,并将较大的元素交换到后一位置。
     6  *         特点:第i轮排序结束后,第i个最大值出现在下标为(length-1-i)的位置
     7  *         时间复杂度:最坏:O(n^2),平均:O(n^2),最好:O(n);
     8  *         空间复杂度:O(1)
     9  *         稳定性:稳定,但是当条件变为arr[j] >= arr[j + 1]时,就不稳定了
    10  */
    11 public class BubbleSort {
    12     public static void bubbleSort(int[] arr) {
    13         for (int i = 0; i < arr.length - 1; i++) {
    14             for (int j = 0; j < arr.length - 1 - i; j++) {
    15                 if (arr[j] > arr[j + 1]) {
    16                     Tools.swap(arr, j, j + 1);
    17                 }
    18             }
    19         }
    20     }
    21 
    22     public static void main(String[] args) {
    23         int[] arr = { 5, 6, 8, 3, 2, 1, 9, 7, 2 };
    24         System.out.println("before sorting:");
    25         Tools.printArray(arr);
    26         bubbleSort(arr);
    27         System.out.println("after sorting:");
    28         Tools.printArray(arr);
    29     }
    30 }

    1.2 快速排序

    整体思路:通过递归的方式,不断将数组分为两部分,主元左边的都比主元小,右边的都比主元大。特点:每一轮的排序结束后,数组中的某一部分就会成为有序的序列。

    时间复杂度:最坏O(n^2),平均O(nlog2n),最好O(nlog2n)。

    空间复杂度:O(nlog2n),主要是由于递归调用造成的栈内存的使用。

    稳定性:不稳定。

    在每一轮的排序过程中,注意首先从右往左进行查找;在跳出循环后,将low索引指向的位置作为主元交换的位置。

    Java实现:

     1 /**
     2  *  3  *
     4  *         以整型数组为例,通过快速排序将数组中的元素按从小到大的顺序进行排列
     5  *         思路:通过递归的方式,不断将数组分为两部分,主元左边的都比主元小,右边的都比主元大。
     6  *         特点:每一轮的排序结束后,数组中的某一部分就会成为有序的序列。
     7  *         时间复杂度:最坏O(n^2),平均O(nlog2n),最好O(nlog2n)
     8  *         空间复杂度:O(nlog2n),主要是由于递归调用造成的栈内存的使用
     9  *         稳定性:不稳定
    10  *         
    11  *         在每一轮的排序过程中,注意首先从右往左进行查找;在跳出循环后,将low索引指向的位置作为主元交换的位置
    12  *         
    13  */
    14 public class QuickSort {
    15     public static void quickSort(int[] arr, int first, int last) {
    16         if (last < first) {
    17             return;
    18         }
    19         int low = first;
    20         int high = last;
    21         int pivot = arr[first];
    22         while (high > low) {
    23             while (high > low && arr[high] >= pivot)
    24                 high--;
    25             while (high > low && arr[low] <= pivot)
    26                 low++;
    27             if (high > low) {
    28                 Tools.swap(arr, low, high);
    29             }
    30         }
    31 
    32         Tools.swap(arr, first, low);
    33         quickSort(arr, first, low - 1);
    34         quickSort(arr, low + 1, last);
    35     }
    36 
    37     public static void quickSort(int[] arr) {
    38         quickSort(arr, 0, arr.length - 1);
    39     }
    40 
    41     public static void main(String[] args) {
    42         int[] arr = { 1, 5, 6, 8, 3, 2, 1, 9, 7, 2, 1, 1 };
    43         //        int[] arr = { 5, 6, 8, 3, 2, 1, 9, 7, 2 };
    44         System.out.println("before sorting:");
    45         Tools.printArray(arr);
    46         quickSort(arr);
    47         System.out.println("after sorting:");
    48         Tools.printArray(arr);
    49     }
    50 }

    2. 选择排序

    2.1 简单选择排序

    整体思路:第i轮排序,找到第i个最小值,将其交换到下标为i的位置。

    特点:第i轮排序结束后,第i个最小值出现在下标为i的位置。

    时间复杂度:三种情况都是O(n^2)。

    空间复杂度:O(1)。

    稳定性:不稳定

    在每一轮选择最小元素的过程中,可以在每次符合条件时都进行换位,也可以将这一轮中最小值的索引记下来,这一轮结束时进行一次换位。这样减少了在堆内存中的操作,更加高效。

    Java实现:

     1 /**
     2  * @author hr
     3  * 
     4  *         以整型数组为例,通过选择排序将数组中的元素按从小到大的顺序进行排列 
     5  *         思路:第i轮排序,找到第i个最小值,将其交换到下标为i的位置。
     6  *         特点:第i轮排序结束后,第i个最小值出现在下标为i的位置
     7  *         
     8  *         在每一轮选择最小元素的过程中,可以在每次符合条件时都进行换位,也可以将这一轮中最小值的
     9  *         索引记下来,这一轮结束时进行一次换位。这样减少了在堆内存中的操作,更加高效。
    10  *         时间复杂度:三种情况都是O(n^2)
    11  *         空间复杂度:O(1)
    12  *         稳定性:不稳定
    13  *         
    14  */
    15 public class SelectionSort {
    16     public static void selectionSort(int[] arr) {
    17         for (int i = 0; i < arr.length - 1; i++) {
    18             int minIndex = i;
    19             for (int j = i + 1; j < arr.length; j++) {
    20                 if (arr[j] < arr[minIndex])
    21                     minIndex = j;
    22             }
    23             if (minIndex != i)
    24                 Tools.swap(arr, i, minIndex);
    25         }
    26     }
    27 
    28     public static void main(String[] args) {
    29         int[] arr = { 5, 6, 8, 3, 2, 1, 9, 7, 2 };
    30         System.out.println("before sorting:");
    31         Tools.printArray(arr);
    32         selectionSort(arr);
    33         System.out.println("after sorting:");
    34         Tools.printArray(arr);
    35     }
    36 }

    2.2 堆排序

    整体思路:首先,将给定的数组建立起一个大顶堆,这也意味着找到了最大的元素;然后,将最大的元素换到堆的末尾(也就是数组的末尾),将剩下的元素重新建立起一个大顶堆,不断找到剩余元素中的最大值。

    特点:第i轮排序结束后,第i个最大值出现在下标为length - i的位置 。

    时间复杂度:三种情况都是O(nlog2n)。

    空间复杂度:O(1)。

    稳定性:不稳定。

    在最开始建立大顶堆时,只需要遍历前半部分数组即可,初始的循环遍历条件设为(length - 1) / 2,直到0为止。随后每次找最大值,也是从后面的元素开始向上遍历。而对大顶堆进行调整的时候,则是从给定的元素开始不断向下进行调整。每次对堆进行调整的循环停止条件为:当前节点不存在左孩子节点,或者当前节点值已经是三个节点中的最大值了。

    Java实现:

    /**
     * @author hr
     * 
     *         以整型数组为例,通过堆排序将数组中的元素按从小到大的顺序进行排列 
     *         思路:首先,将给定的数组建立起一个大顶堆,这也意味着找到了最大的元素;然后,将最大的元素换到堆的末尾
     *         (也就是数组的末尾),将剩下的元素重新建立起一个大顶堆,不断找到剩余元素中的最大值。
     *         特点:第i轮排序结束后,第i个最大值出现在下标为length - i的位置
     *         
     *         在最开始建立大顶堆时,只需要遍历前半部分数组即可,初始的循环遍历条件设为(length - 1) / 2,直到0为止
     *         随后每次找最大值,也是从后面的元素开始向上遍历。
     *         而对大顶堆进行调整的时候,则是从给定的元素开始不断向下进行调整。
     *         时间复杂度:三种情况都是O(nlog2n)
     *         空间复杂度:O(1)
     *         稳定性:不稳定
     *         
     */
    public class HeapSort {
        private static void heapify(int[] arr, int index, int heapSize) {
            int left = 2 * index + 1;
            int right = 2 * index + 2;
            int largest = index;
            while (left < heapSize) {
                if (arr[left] > arr[largest])
                    largest = left;
                if (right < heapSize && arr[right] > arr[index])
                    largest = right;
                if (index != largest) {
                    Tools.swap(arr, index, largest);
                    index = largest;
                    left = 2 * index + 1;
                    right = 2 * index + 2;
                } else
                    break;
            }
        }
    
        public static void buildHeap(int[] arr) {
            for (int i = (arr.length - 1) / 2; i >= 0; i--) {
                heapify(arr, i, arr.length);
            }
        }
    
        public static void heapSort(int[] arr) {
            buildHeap(arr);
            for (int i = arr.length - 1; i >= 0; i--) {
                Tools.swap(arr, 0, i);
                heapify(arr, 0, i);
            }
        }
    
        public static void main(String[] args) {
            int[] arr = { 5, 6, 8, 3, 2, 1, 9, 7, 2 };
            System.out.println("before sorting:");
            Tools.printArray(arr);
            heapSort(arr);
            System.out.println("after sorting:");
            Tools.printArray(arr);
        }
    
    }

    3. 插入排序

     3.1 简单插入排序

    整体思路:

    第i轮排序,是将第i号元素插入由0,1,2...(i-1)号元素组成的有序表中。

    特点:第i轮排序结束后,由0,1,2...i号元素组成的序列是有序的。

    时间复杂度:最坏(数组是反序的)O(n^2),平均O(n^2),最好(数组本身就是正序的)O(n)。

    空间复杂度:O(1)。

    稳定性:稳定。

    由于第i个元素之前都是有序的,因此在插入第i个元素的时候,可以从前往后遍历,找到合适的位置就停止。

    Java实现:

     1 /**
     2  * @author hr
     3  *
     4  *         以整型数组为例,通过插入排序将数组中的元素按从小到大的顺序进行排列
     5  *         思路:第i轮排序,是将第i号元素插入由0,1,2...(i-1)号元素组成的有序表中
     6  *         特点:第i轮排序结束后,由0,1,2...i号元素组成的序列是有序的
     7  *         时间复杂度:最坏(数组是反序的)O(n^2),平均O(n^2),最好(数组本身就是正序的)O(n)
     8  *         空间复杂度:O(1)
     9  *         稳定性:稳定
    10  *         
    11  *         由于第i个元素之前都是有序的,因此在插入第i个元素的时候,可以从前往后遍历,
    12  *         找到合适的位置就停止
    13  */
    14 public class InsertionSort {
    15     public static void insertionSort(int[] arr) {
    16         for (int i = 1; i < arr.length; i++) {
    17             int curNum = arr[i];
    18             int j;
    19             for (j = i - 1; j >= 0 && arr[j] > curNum; j--) {
    20                 arr[j + 1] = arr[j];
    21             }
    22             arr[j + 1] = curNum;
    23         }
    24     }
    25 
    26     public static void main(String[] args) {
    27         int[] arr = { 5, 6, 8, 3, 2, 1, 9, 7, 2 };
    28         System.out.println("before sorting:");
    29         Tools.printArray(arr);
    30         insertionSort(arr);
    31         System.out.println("after sorting:");
    32         Tools.printArray(arr);
    33     }
    34 }

    3.2 希尔排序

    整体思路:初始将数组均分为gap组,所有下标之差为gap的元素在同一组内,然后对每一组进行插入排序;最后不断调整gap的值进行循环,直到gap为0。 

    时间复杂度:最坏O(n^2),平均O(n^1.3),最好O(n)。

    空间复杂度:O(1)。

    稳定性:不稳定。

    实际实现的时候,并不是一组插入排序结束之后再进行另外一组,而是每一组交叉进行。

    Java实现:

     1 /**
     2  * @author hr
     3  * 
     4  *         以整型数组为例,通过希尔排序将数组中的元素按从小到大的顺序进行排列 
     5  *         思路:初始将数组均分为gap组,所有下标之差为gap的元素在同一组内,然后对每一组进行插入排序;
     6  *         最后不断调整gap的值进行循环。
     7  *        
     8  *         
     9  *         实际实现的时候,并不是一组插入排序结束之后再进行另外一组,而是每一组交叉进行
    10  *         时间复杂度:最坏O(n^2),平均O(n^1.3),最好O(n)
    11  *         空间复杂度:O(1)
    12  *         稳定性:不稳定
    13  *         
    14  */
    15 
    16 public class ShellSort {
    17     public static void ShellSort(int[] arr) {
    18         for (int gap = arr.length / 2; gap > 0; gap /= 2) {
    19             for (int i = gap; i < arr.length; i++) {
    20                 for (int j = i - gap; j >= 0; j -= gap) {
    21                     if (arr[j] > arr[j + gap]) {
    22                         Tools.swap(arr, j, j + gap);
    23                     }
    24                 }
    25             }
    26         }
    27     }
    28 
    29     public static void main(String[] args) {
    30         int[] arr = { 5, 6, 8, 3, 2, 1, 9, 7, 2 };
    31         System.out.println("before sorting:");
    32         Tools.printArray(arr);
    33         ShellSort(arr);
    34         System.out.println("after sorting:");
    35         Tools.printArray(arr);
    36     }
    37 }

    4. 归并排序

    整体思路:归并排序采用的是分治法。首先不断将数组分为左右两部分,直到每部分都只包含一个元素为止。然后对所有的子序列两两合并,最终得到有序序列。

    时间复杂度:最坏O(nlog2n),平均O(nlog2n),最好O(nlog2n)。

    空间复杂度:O(n)。

    稳定性:稳定。

    Java实现:

     1 /**
     2  * @author hr
     3  * 
     4  *         以整型数组为例,通过归并排序将数组中的元素按从小到大的顺序进行排列 
     5  *         思路:归并排序采用的是分治法。首先不断将数组分为左右两部分,直到每部分都只包含一个元素为止。
     6  *         然后对所有的子序列两两合并,最终得到有序序列。
     7  *        
     8  *         时间复杂度:最坏O(nlog2n),平均O(nlog2n),最好O(nlog2n)
     9  *         空间复杂度:O(n)
    10  *         稳定性:稳定
    11  *         
    12  */
    13 public class MergeSort {
    14     //将arr[first~mid]和arr[mid~last]合并到tmp中
    15     public static void mergeArray(int[] arr, int first, int mid, int last) {
    16         int[] tmp = new int[last - first + 1];
    17         int begin1 = first;
    18         int begin2 = mid + 1;
    19         int end1 = mid;
    20         int end2 = last;
    21         int k = 0;
    22         while (begin1 <= end1 && begin2 <= end2) {
    23             if (arr[begin1] < arr[begin2]) {
    24                 tmp[k++] = arr[begin1++];
    25             } else {
    26                 tmp[k++] = arr[begin2++];
    27             }
    28         }
    29         while (begin1 <= end1) {
    30             tmp[k++] = arr[begin1++];
    31         }
    32         while (begin2 <= end2) {
    33             tmp[k++] = arr[begin2++];
    34         }
    35         //将辅助数组tmp的数据写回arr
    36         for (begin1 = 0; begin1 < k; begin1++) {
    37             arr[first + begin1] = tmp[begin1];
    38         }
    39     }
    40 
    41     public static void mergeSort(int[] arr, int first, int last) {
    42         if (last - first > 0) {
    43             int mid = (last + first) / 2;
    44             mergeSort(arr, first, mid);
    45             mergeSort(arr, mid + 1, last);
    46             mergeArray(arr, first, mid, last);
    47         }
    48     }
    49 
    50     public static void mergeSort(int[] arr) {
    51         mergeSort(arr, 0, arr.length - 1);
    52     }
    53 
    54     public static void main(String[] args) {
    55         int[] arr = { 5, 6, 8, 3, 2, 1, 9, 7, 2 };
    56         System.out.println("before sorting:");
    57         Tools.printArray(arr);
    58         mergeSort(arr);
    59         System.out.println("after sorting:");
    60         Tools.printArray(arr);
    61     }
    62 }

    5.计数排序

    整体思路:统计出数组中每个元素出现的次数,然后将元素按顺序填入就可得到有序序列。

    时间复杂度:三种情况都是O(n + k)。

    空间复杂度:O(n + k),k代表数组的宽度。

    稳定性:稳定。

    在统计每个元素出现的次数时,首先找到数组的宽度(数组最大值和最小值之差再加一),这样,统计数组中的下标就和元素值联系在一起(相差为min)。得到统计值之后,统计数组中的下标可以找到原数组中对应的元素,统计数组的元素值代表原数组对应元素的出现次数

    Java实现:

     1 /**
     2  * @author hr
     3  * 
     4  *         以整型数组为例,通过计数排序将数组中的元素按从小到大的顺序进行排列 
     5  *         思路:统计出数组中每个元素出现的次数,然后将元素按顺序填入就可得到有序序列
     6  *         
     7  *         在统计每个元素出现的次数时,首先找到数组的宽度(数组最大值和最小值之差再加一),
     8  *         这样,统计数组中的下标就和元素值联系在一起(相差为min)。得到统计值之后,统计
     9  *         数组中的下标可以找到原数组中对应的元素,统计数组的元素值代表原数组对应元素的出现次数
    10  *        
    11  *         时间复杂度:三种情况都是O(n + k)
    12  *         空间复杂度:O(n + k),k代表数组的宽度
    13  *         稳定性:稳定
    14  *         
    15  */
    16 public class CountSort {
    17 
    18     public static void countSort(int[] arr) {
    19         int max = Tools.findMax(arr);
    20         int min = Tools.findMin(arr);
    21         int[] count = new int[max - min + 1];
    22         for (int num : arr) {
    23             count[num - min]++;
    24         }
    25         int index = 0;
    26         for (int i = 0; i < count.length; i++) {
    27             while (count[i] != 0) {
    28                 arr[index++] = i + min;
    29                 count[i]--;
    30             }
    31         }
    32     }
    33 
    34     public static void main(String[] args) {
    35         int[] arr = { 5, 6, 8, 3, 2, 1, 9, 7, 2 };
    36         System.out.println("before sorting:");
    37         Tools.printArray(arr);
    38         countSort(arr);
    39         System.out.println("after sorting:");
    40         Tools.printArray(arr);
    41     }
    42 }

    6. 桶排序

    整体思路:根据数组的宽度,生成数量合适的桶。遍历数组,将元素放入对应的桶中。然后对每个桶进行排序,这样,桶内和桶间就都是有序的了。

    时间复杂度:最坏:O(n^2),平均:O(n + k),最好:O(n)。

    空间复杂度:O(n + k),其中k为数组的宽度。

    稳定性:稳定。

    实现时,用list<list>代表一个桶,将桶的数量设置为(max - min) / arr.length + 1,这样,(num - min) / arr.length = i的元素就放在第i个桶中。桶内元素我们利用简单插入排序。

    Java实现:

     1 /**
     2  * @author hr
     3  *
     4  *         以整型数组为例,通过桶排序将数组中的元素按从小到大的顺序进行排列
     5  *         思路:根据数组的宽度,生成数量合适的桶。遍历数组,将元素放入对应的桶中。然后对每个桶进行排序,
     6  *         这样,桶内和桶间就都是有序的了。
     7  *         
     8  *         实现时,用list<list>代表一个桶,将桶的数量设置为(max - min) / arr.length + 1,这样,
     9  *         (num - min) / arr.length = i的元素就放在第i个桶中。桶内元素我们利用简单插入排序。
    10  *          
    11  *         时间复杂度:最坏:O(n^2),平均:O(n + k),最好:O(n);
    12  *         空间复杂度:O(n + k),其中k为数组的宽度
    13  *         稳定性:稳定
    14  */
    15 public class BucketSort {
    16     public static void insertionSort(ArrayList<Integer> bucket) {
    17         for (int i = 1; i < bucket.size(); i++) {
    18             int j;
    19             int curNum = bucket.get(i);
    20             for (j = i - 1; j >= 0 && bucket.get(j) > curNum; j--) {
    21 
    22                 bucket.set(j + 1, bucket.get(j));
    23 
    24             }
    25             bucket.set(j + 1, curNum);
    26         }
    27     }
    28 
    29     public static void bucketSort(int[] arr) {
    30         int max = Integer.MIN_VALUE;
    31         int min = Integer.MAX_VALUE;
    32         max = Tools.findMax(arr);
    33         min = Tools.findMin(arr);
    34         int bucketNum = (max - min) / arr.length + 1;
    35         ArrayList<ArrayList<Integer>> buckets = new ArrayList<>();
    36         for (int i = 0; i < bucketNum; i++) {
    37             buckets.add(new ArrayList<>());
    38         }
    39 
    40         for (int num : arr) {
    41             int index = (num - min) / arr.length;
    42             buckets.get(index).add(num);
    43         }
    44 
    45         int index = 0;
    46         for (int i = 0; i < buckets.size(); i++) {
    47             insertionSort(buckets.get(i));
    48             for (int num : buckets.get(i)) {
    49                 arr[index++] = num;
    50             }
    51         }
    52     }
    53 
    54     public static void main(String[] args) {
    55         int[] arr = { 5, 6, 8, 3, 2, 1, 9, 7, 2 };
    56         System.out.println("before sorting:");
    57         Tools.printArray(arr);
    58         bucketSort(arr);
    59         System.out.println("after sorting:");
    60         Tools.printArray(arr);
    61     }
    62 }

    7. 基数排序

    整体思路:本质上和桶排序是一样的,只是这个桶是固定的10个。排序的过程,就是将所有元素,从个位开始,不断进行桶排序。当所有的数位都排序一遍之后,就得到了有序序列。

    时间复杂度:三种情况都是O(n + k)。

    空间复杂度:O(n + k),其中k为数组的宽度。

    稳定性:稳定。

    实现时,可以用list<list>代表一个基数的计数桶;也可以用一个和原数组等长的临时数组,和一个大小为10的计数数组来进行统计。但是用后者会在一次排序的过程中,遍历两遍数组。

    Java实现:

     1 /**
     2  * @author hr
     3  *
     4  *         以整型数组为例,通过基数排序将数组中的元素按从小到大的顺序进行排列
     5  *         思路:本质上和桶排序是一样的,只是这个桶是固定的10个。排序的过程,就是将所有元素,从个位开始,
     6  *         不断进行桶排序。当所有的数位都排序一遍之后,就得到了有序序列。
     7  *         
     8  *         实现时,可以用list<list>代表一个基数的计数桶;也可以用一个和原数组等长的临时数组,
     9  *         和一个大小为10的计数数组来进行统计。但是用后者会在一次排序的过程中,遍历两遍数组
    10  *          
    11  *         时间复杂度:三种情况都是O(n + k);
    12  *         空间复杂度:O(n + k),其中k为数组的宽度
    13  *         稳定性:稳定
    14  */
    15 public class RadixSort {
    16     public static void radixSort(int[] arr) {
    17         ArrayList<ArrayList<Integer>> tmp = new ArrayList<>();
    18         for (int i = 0; i < 10; i++) {
    19             tmp.add(new ArrayList<>());
    20         }
    21 
    22         int maxNum = Tools.findMax(arr);
    23         int maxLength = Integer.toString(maxNum).length();
    24 
    25         int radix = 1;
    26         for (int i = 0; i < maxLength; i++) {
    27             for (int k = 0; k < 10; k++) {
    28                 tmp.add(new ArrayList<>());
    29             }
    30 
    31             for (int num : arr) {
    32                 int digit = (num / radix) % 10;
    33                 tmp.get(digit).add(num);
    34             }
    35 
    36             int index = 0;
    37             for (int j = 0; j < tmp.size(); j++) {
    38                 for (int num : tmp.get(j)) {
    39                     arr[index++] = num;
    40                 }
    41             }
    42 
    43             radix *= 10;
    44             tmp.clear();
    45         }
    46     }
    47 
    48     public static void main(String[] args) {
    49         int[] arr = { 15, 6, 8, 3, 2, 1, 9, 7, 2 };
    50         System.out.println("before sorting:");
    51         Tools.printArray(arr);
    52         radixSort(arr);
    53         System.out.println("after sorting:");
    54         Tools.printArray(arr);
    55     }
    56 }
  • 相关阅读:
    python初学第一节课
    关于float类型和u32类型问题
    今天的工作状态,规划未来一段时间内必须完成的事情(Record the working status of today,planning for the next period of time must be completed)
    STM32 硬件I2C初始化 I2C1_GPIO_AF_Config
    C语言编程规范--------12 宏
    C语言编程规范--------11 代码测试、维护
    C语言编程规范--------10 代码编辑、编译、审查
    C语言编程规范--------9 质量保证
    C语言编程规范--------8 效率
    C语言编程规范--------7 可测性
  • 原文地址:https://www.cnblogs.com/hrcnblogs/p/9277015.html
Copyright © 2011-2022 走看看