重学常见排序算法

最常见的有冒(冒泡)择(选择)路(插入)希(希尔)快(快速)归(归并)堆(堆排序)。 这一次把所有的常见的排序熟悉一遍,后面就一劳永逸了。

冒泡算法

连接:https://www.bilibili.com/video/BV1Mi4y1k7QT/

冒泡排序算法的文字描述:

  1. 一次比较数组中相邻两个元素大小,若 a[j] > a[j+1] , 则交换两个元素,两两都比较一遍为一轮排序,结果是让最大的元素排至最后。
  2. 重复以上步骤,指导整个数组有序。

先实现一版最简单。

import java.util.Arrays;
public class BubbleSort {

    /**
     * 用来记录比较的次数。
     * */
    private static int compareCnt = 0 ;

    /**
     * 用来记录交换的次数。
     * */
    private static int swapCnt = 0 ;

    /**
     * 用来记录冒泡的次数的次数。
     * */
    private static int bubleCnt = 0 ;

    public static void sort(int[] array){
        boolean isSwap = Boolean.TRUE;

        for (int i = 0; i < array.length -1 ; i++) {
            bubleCnt++;
            for(int j = 0 ; j < array.length -1 ;j++){
                if(compare(array[j] , array[j+1]) ){
                    swap(array,j,j+1);
                }
            }
        }
    }
    public static boolean compare(int a , int b){
        compareCnt++;
        return a > b ;
    }
    public static void swap(int[] array , int i , int j){
        swapCnt++;
        int swap = 0 ;
        swap = array[i];
        array[i] = array[j];
        array[j] = swap;
    }
    public static void main(String[] args) {
        int[] a = { -1 , -2 ,  8 , 3 ,4 ,2 ,1};

        System.out.println(Arrays.toString(a));
        sort(a);
        System.out.println("compareCnt:" + compareCnt);
        System.out.println("swapCnt:" + swapCnt);
        System.out.println("bubleCnt:" + bubleCnt);
        System.out.println(Arrays.toString(a));
    }
}

执行上面的代码,得到如下结果:

[-1, -2, 8, 3, 4, 2, 1]
compareCnt:36
swapCnt:10
bubleCnt:6
[-2, -1, 1, 2, 3, 4, 8]

接下来,我想一个问题,我们经过第一躺的结果是将最大的数字排到最后一个位置。就像赶羊,把最大个的羊感到最后的位置。这里有个视频讲解。所以经过 n 次冒泡后,倒数 n 个位置上,都是有序的,这样的话就不需要比较了。所以代码改成下面的样子,

import java.util.Arrays;
public class BubbleSort {

    /**
     * 用来记录比较的次数。
     * */
    private static int compareCnt = 0 ;

    /**
     * 用来记录交换的次数。
     * */
    private static int swapCnt = 0 ;

    /**
     * 用来记录冒泡的次数的次数。
     * */
    private static int bubleCnt = 0 ;

    public static void sort(int[] array){
        boolean isSwap = Boolean.TRUE;

        for (int i = 0; i < array.length -1 ; i++) {
            bubleCnt++;
            // 改了这里
            for(int j = 0 ; j < array.length -1 - i;j++){
                if(compare(array[j] , array[j+1]) ){
                    swap(array,j,j+1);
                }
            }
        }
    }
    public static boolean compare(int a , int b){
        compareCnt++;
        return a > b ;
    }
    public static void swap(int[] array , int i , int j){
        swapCnt++;
        int swap = 0 ;
        swap = array[i];
        array[i] = array[j];
        array[j] = swap;
    }
    public static void main(String[] args) {
        int[] a = { -1 , -2 ,  8 , 3 ,4 ,2 ,1};

        System.out.println(Arrays.toString(a));
        sort(a);
        System.out.println("compareCnt:" + compareCnt);
        System.out.println("swapCnt:" + swapCnt);
        System.out.println("bubleCnt:" + bubleCnt);
        System.out.println(Arrays.toString(a));
    }
}

我们在 j 的右边界做了优化,每次比较移动都回减小 1 ,排好序的部分就不会在进行比较了。下面展示一下执行的效果,可以看到比较的次数减少了。

[-1, -2, 8, 3, 4, 2, 1]
compareCnt:21
swapCnt:10
bubleCnt:6
[-2, -1, 1, 2, 3, 4, 8]

其实,还有一个特殊的情况,如果在做完一个冒泡之后,正好和原来有序的数列连成片,那是不是就可以减少冒泡的次数了。

public class BubbleSort {

    /**
     * 用来记录比较的次数。
     * */
    private static int compareCnt = 0 ;

    /**
     * 用来记录交换的次数。
     * */
    private static int swapCnt = 0 ;

    /**
     * 用来记录冒泡的次数的次数。
     * */
    private static int bubleCnt = 0 ;

    public static void sort(int[] array){
        boolean isSwap = Boolean.TRUE;
        // 最后一次交换的位置
        int lastSwapPosition = 0 ;

        for (int i = 0; i < array.length -1 ; i++ ) {
            bubleCnt++;
            for(int j = 0 ; j < array.length -1 - i ;j++){
                if(compare(array[j] , array[j+1]) ){
//                    isSwap = Boolean.TRUE;
                    swap(array,j,j+1);
                    lastSwapPosition = j + 1;
                }else {
//                    isSwap = Boolean.FALSE ;
                }
            }
//            i += array.length - lastSwapPosition - 1;
        }
    }
    public static boolean compare(int a , int b){
        compareCnt++;
        return a > b ;
    }
    public static void swap(int[] array , int i , int j){
        swapCnt++;
        int swap = 0 ;
        swap = array[i];
        array[i] = array[j];
        array[j] = swap;
    }
    public static void main(String[] args) {
        int[] a = { -1 , -2 ,  8 ,2 ,1 , 3 , 4};

        System.out.println(Arrays.toString(a));
        sort(a);
        System.out.println("compareCnt:" + compareCnt);
        System.out.println("swapCnt:" + swapCnt);
        System.out.println("bubleCnt:" + bubleCnt);
        System.out.println(Arrays.toString(a));
    }
}

修改后的代码:

public class BubbleSort {

    /**
     * 用来记录比较的次数。
     * */
    private static int compareCnt = 0 ;

    /**
     * 用来记录交换的次数。
     * */
    private static int swapCnt = 0 ;

    /**
     * 用来记录冒泡的次数的次数。
     * */
    private static int bubleCnt = 0 ;

    public static void sort(int[] array){
        boolean isSwap = Boolean.TRUE;
        // 最后一次交换的位置
        int lastSwapPosition = 0 ;

        for (int i = 0; i < array.length -1 ; ) {

//            if(!isSwap){
//               break;
//            }
            bubleCnt++;
            for(int j = 0 ; j < array.length -1 - i ;j++){
                if(compare(array[j] , array[j+1]) ){
//                    isSwap = Boolean.TRUE;
                    swap(array,j,j+1);
                    lastSwapPosition = j + 1;
                }else {
//                    isSwap = Boolean.FALSE ;
                }
            }
            i += array.length - lastSwapPosition - 1;
        }
    }
    public static boolean compare(int a , int b){
        compareCnt++;
        return a > b ;
    }
    public static void swap(int[] array , int i , int j){
        swapCnt++;
        int swap = 0 ;
        swap = array[i];
        array[i] = array[j];
        array[j] = swap;
    }
    public static void main(String[] args) {
        int[] a = { -1 , -2 ,  8 ,2 ,1 , 3 , 4};

        System.out.println(Arrays.toString(a));
        sort(a);
        System.out.println("compareCnt:" + compareCnt);
        System.out.println("swapCnt:" + swapCnt);
        System.out.println("bubleCnt:" + bubleCnt);
        System.out.println(Arrays.toString(a));
    }
}

执行结果如下所示:

修改前的结果:
[-1, -2, 8, 2, 1, 3, 4]
compareCnt:21
swapCnt:6
bubleCnt:6
[-2, -1, 1, 2, 3, 4, 8]
修改后的结果:
[-1, -2, 8, 2, 1, 3, 4]
compareCnt:15
swapCnt:6
bubleCnt:3
[-2, -1, 1, 2, 3, 4, 8]

这次输入的数组特点是 3 和 4 是有序的,而且可以和 8 连成片。经过优化后,bubleCnt 的次数减少了三次。

我们可以把此数组看成两个不断变化的数组,可能经过几次排序之后,其实无序的数组已经有序,只是程序不知道而已,问题的关键在于让程序知道无序数组已经是有序的,可以设置一个变量来记录在无序数组中是否发生了狡猾,如果没有发生交换 ,则说明无序的数列就是有序的了。就不需要进行后面的冒泡了。

选择排序

连接:https://www.bilibili.com/video/BV18q4y1Y7AE/

过程描述:

  1. 将无序的数组分成两个子集,一个是有序的,另外一个是无序的,每次都从无序子集中取出最大值放到有序子集的最后面
  2. 重复上面的过程

代码实现:

import java.util.Arrays;

public class SelectSort {
    private int[] array ;
    public SelectSort(int[] array){
        this.array = array;
    }
    public void sort(){
        int minIndex = 0 ;
        int temp = 0 ;
        for (int i = 0; i < this.array.length - 1 ; i++) {
            temp = array[i];
            minIndex = i+1;
            for(int j = i+1 ; j < array.length ; j++){
                if(temp > array[j]){
                    minIndex = j ;
                    temp = array[j];
                }
            }
            if(temp < array[i]){
                swap(minIndex , i);
            }
        }
    }

    private void swap(int minIndex, int i) {
        int temp = 0 ;
        temp = array[minIndex];
        array[minIndex] = array[i];
        array[i] = temp;
    }

    @Override
    public String toString() {
        return "SelectSort{" +
                "array=" + Arrays.toString(array) +
                '}';
    }

    public static void main(String[] args) {
        SelectSort ss = new SelectSort(new int[]{1, 22, 11, 23, 32, 43});
        System.out.println("the original order:");
        System.out.println(ss.toString());
        ss.sort();
        System.out.println("the ordered array:");
        System.out.println(ss.toString());
    }
}

插入排序

连接:https://www.bilibili.com/video/BV19L411w7XM/
插入排序的过程描述:

  1. 将数组分成两个子集,一个有序另外一个无序,每次从无序子集中选取出一个元素,然后遍历有序子集中,找到第一个大于此元素的位置,然后插入到这个位置,其他元素依次向右移动。
  2. 重复上面的过程,直到整个数组都有序为止。

代码:

import java.util.Arrays;

public class InsertSort {

    public static void main(String[] args) {
        int[] a = { -1 , -2 ,  8 ,2 ,1 , 18 , 21 , 20 , 3 , 4};
        sort(a);
        System.out.println("swapCnt:" + swapCnt);
    }
    /**
     * 交换的次数
     * */
    private static int swapCnt = 0 ;
    public static void sort(int[] array){
        if(array.length <= 1){
            return;
        }
        int insertPosition = 0 ;
        int temp = 0 ;
        for (int i = 0; i < array.length; i++) {
            System.out.print("index:" + i + "====>");
            temp = array[i];
            insertPosition = findInsertPosition( array , i);
            moveAndInsert(array , insertPosition , i , temp );
            System.out.println(Arrays.toString(array));
        }
    }
    private static void swap(int[] array , int from , int to){
        swapCnt++;
        int temp = array[from];
        array[from] = array[to];
        array[to] = temp;
    }
    /**
     * 移动有序子集,给插入元素挪开地方,并将元素插入到相关的位置
     * */
    private static void moveAndInsert(int[] array, int insertPosition , int bound, int temp) {
        for (int i = bound; i > insertPosition  ; i--) {
              swap(array,i , i-1);
        }
        array[insertPosition] = temp ;
    }


    /**
     * 找到插入的位置
     * */
    private static int findInsertPosition(int[] array, int sortedBound) {
        for (int i = 0; i <= sortedBound; i++) {
            if(array[i] >= array[sortedBound]){
               return i ;
            }
        }
        return 0;
    }
}

希尔排序

希尔排序是堆插入排序的改进,在插入排序中,如果大的元素都在后面的话,移动元素的次数会小很多,但是如果较大元素放到前面,例如放到了第一个位置,则需要移动 n - 1 次移动。如果我们能够又一种方法将降低这样的移动次数,是不是就可以达到优化的效果了。这个方法和跳表的方法差不多,我们先选择一个 interval(步长),使用步长选择出一个子集,然后对子集做插入排序。

在这里插入图片描述

如上图所示,通过步长选子集的方式,就把前后的元素直接的放到了一起,这样就能减少移动的次数。

https://www.bilibili.com/video/BV1M44y1K7S1/

希尔排序的代码,我使用链表实现,但是太过复杂,还没有写好,所以就不再这里贴出来了。另外,不会考代码实现。

归并排序

连接:https://www.bilibili.com/video/BV1bP4y1T7je/

定义:

  1. 使用二分法,把集合两个集合,然后再对这两个集合做同样的切分,直到每个集合中只要一个元素
  2. 然后将相邻两个集合合并排序,并将保证有序性
  3. 从下至上,重复 2 的操作

代码:

import java.util.Arrays;

public class MergeSort {
    public static void main(String[] args) {
        int[] A1 = {4 , 6 , 1 , 8 , 3 , -1};
        int[] A2 = { 9 , 17 , 34 , 22 , 90};
        int[] merge = {4 , 6 , 1 , 8 , 3 , -1 , 9 , 17 , 34 , 22 , 90};
        System.out.println(Arrays.toString(sort(merge , 0 , merge.length-1)));
    }
    public static int[] sort(int[] array , int from , int to){
        int[] rs = null ;
        if(from == to){
            rs = new int[1];
            rs[0] = array[from];
            return rs ;
        }
        int mid = (from + to)/2;
        int[] firstHalf = sort(array, mid + 1  , to);
        int[] secordHafl = sort(array , from ,  mid);

        return merge(firstHalf , secordHafl);
    }
    public static int[] merge( int[] A1 , int[] A2){
        int[] rs = new int[A1.length + A2.length];
        int i = 0 ;
        int j = 0 ;
        int a = 0 ;
        while(i < A1.length && j < A2.length){
           if(A1[i] <= A2[j]){
               rs[a++] = A1[i++];
           }else{
               rs[a++] = A2[j++];
           }
        }
        while(i < A1.length){
           rs[a++] = A1[i++];
        }
        while (j < A2.length){
            rs[a++] = A2[j++];
        }
        return rs ;
    }
}

合并排序的优点:

它在合并的时候,会利用原来有序性来,避免不必要的比较和移动

缺点:

需要使用额外的存储

快速排序

连接:

定义:

  1. 任意选择一个元素,令所有大于它的元素都放到它的右面,所有小于它的元素都放到它的左面,
  2. 在选定元素的左边集合中,重复 1 .
  3. 在选定元素的右边集合中,重复 1
  4. 重复 1 ~3 的过程。直到递归到最小的子集。再一一返回。

代码:

import java.util.Arrays;

public class QuikSort {
    public static void main(String[] args) {
        int[] A1 = {4 , 6 , 1 , 8 , 3 , -1};
        int[] A2 = { 9 , 17 , 34 , 22 , 90};
        int[] merge = {4 , 6 , 1 , 8 , 3 , -1 , 9 , 17 , 34 , -33 , 1 ,  22 , 90 , -100};
        sort(merge , 0 , merge.length - 1);
        System.out.println(Arrays.toString(merge));;
    }
    public static void swap(int[] array , int from , int to){
        int temp = array[from];
        array[from] = array[to];
        array[to] = temp ;
    }
    public static void sort(int[] array , int from , int to){
         if(from >= to){
             return;
         }
         int i = from + 1;
         int j = to ;
         int key = array[from];
         while(i < j){
             // 从左到右找到第一比 key 小的
             while(key <= array[j] && j > i){
                 j--;
             }
             // 从右到左第一个比 key 大的
             while(key > array[i] && j > i){
                i++;
             }
             if(i<j){
                 swap(array , i , j);
                 i++;
                 j--;
             }
         }
         if(array[i] <= key){
           swap(array , from , i);
         }else{
             swap(array , from , i -1);
         }
         // 接收为 i -1  i 的位置其实有序了,不需要移动了,所以不需要参与到下次的排序了。
         sort(array , from , i - 1 );
         // 同理,开始的位置事 i+1 
         sort(array , i+1 , to);
    }
}

快排在实现 1) 功能的时候,其实是一个荷兰国旗问题的解题思路。

堆排序

连接:

定义:

  1. 将 a[0 , … , i] 看做是一个堆,从 i = 0 开始,将 a[i] 插入到堆中。i = a.length - 1 后,就把 a 构建成了一个堆。
  2. 将a[0 , … , i] 中的 root 位置和 i 位置上的数据进行交换,就把最大值或者最小值放入到最后的位置上。然后执行 i - 1 , 最后到了 0 结束排序了。

代码:

import java.util.Arrays;
import java.util.Random;
public class HeapSort {
    private static Logger logger = LoggerFactory.getLogger(HeapSort.class);
    public static void sort(int[] array){
        if(null == array && array.length < 2){
            return ;
        }
        // 1.弄一个大根堆
        int heapSize = 0 ;
        while(heapSize <= array.length -1){
            insertHeap(array ,heapSize++);
        }
        // 2. 将堆头和堆的最后一个元素交换,并调整大根堆的
        int tail = heapSize - 1 ;
        while(tail > 0){
            heapfy(array , tail--);
        }
    }
    public static void heapfy(int[] heap , int heapSize){
        int root = 0 ;
        int left = 2*root + 1 ;
        int max = 0 ;
        swap(heap , root , heapSize);
        while(left < heapSize){
           max = (left + 1 < heapSize && heap[left + 1] > heap[left])?left + 1: left;
           max = heap[max] > heap[root]?max : root ;
           if(max == root){
               break ;
           }
           swap(heap , root , max);
           root = max ;
           left = root*2 + 1 ;
        }


    }
    public static void insertHeap(int[] heap , int heapSize){
        int root  = (heapSize - 1)/2 ;
        int leaf = heapSize ;
        while(leaf > 0){
            if(heap[root] < heap[leaf]){
                swap(heap , root , leaf);
                leaf = root ;
                root = (leaf - 1)/2;
            }else{
                break ;
            }
        }
    }

    public static void swap(int[] array, int from , int to){
        if(from == to){
             return ;
        }
        array[from] = array[from]^array[to];
        array[to] = array[from]^array[to];
        array[from] = array[from]^array[to];
    }
    public static int[] randomArray(int range , int size){
        Random r = new Random();
        int s = r.nextInt(size) + 1;
        int[] ans = new int[s];
        for(int i = 0 ; i < s ; i++){
            ans[i] = r.nextInt(range);
        }
        return ans ;
    }
    public static int[] copyOf(int[] array){
        int[] ans = new int[array.length];
        for(int i = 0 ; i < array.length ; i++){
            ans[i] = array[i];
        }
        return ans ;
    }
    public static void compare(int range , int size , int times){
        int[] array = null ;
        int[] array2 = null ;
        int[] arrayBackup = null ;
        for(int i = 0 ; i < times ; i++){
           array = randomArray(range , size);
           array2 = copyOf(array);
           arrayBackup = copyOf(array);
           Arrays.sort(array);
           sort(array2);
           if(!Arrays.equals(array , array2)){
                System.out.println("Oops , array is:" + Arrays.toString(arrayBackup));
           }
        }

    }
    public static void main(String[] args){
        compare(100 , 34 , 1213231);
    }
}

桶排序

连接:

定义:

  1. 构建一个 hash 表。a[i]/k = h 计算出 hash 表中的下标值 h , 采用的是链表法解决 hash 碰撞的问题,并且在插入链表的时候,要保证有序性。
  2. 从左往有开始遍历 Hash 表,顺序的取出数据,放到原来的数组中,结束。

代码:

import java.util.Arrays;
import java.util.Random;

/**
 * @className: BucketSort
 * @Description:
 * @Author: wangyifei
 * @Date: 2022/10/8 16:53
 */
public class BucketSort {
    private static Logger logger = LoggerFactory.getLogger(BucketSort.class);
    public static class Node implements Comparable<Node> {
        public int num ;
        public Node next ;
        public static void insert(Node pre , Node cur){
            Node tmp = pre.next;
            pre.next = cur ;
            cur.next = tmp ;
        }

        public int compareTo(Node o) {
            return this.num - o.num;
        }
        public Node(int num){
            this.num = num ;
        }

    }
    public static void sort(int[] array){
        Node[] nodes = new Node[array.length];
        for(int i : array){
            put(nodes , i);
        }
        int idx = 0 ;
        for(Node node : nodes){
            idx = compact(array , idx ,node);
        }
    }
    public static int compact(int[] array , int idx , Node node){
        Node curr = node ;
        while(curr != null){
            array[idx++] = curr.num ;
            curr = curr.next ;
        }
        return idx ;
    }
    public static void put(Node[] nodes , int i){
        int idx = i/100;
        if(null == nodes[idx]){
            nodes[idx] = new Node(i);
        }else{
            Node cur = new Node(i);
            Node pre = null;
            Node next = nodes[idx] ;
            while(next != null){
                if(next.num >= i){
                    if(null == pre){
                        pre = nodes[idx];
                        nodes[idx] = cur ;
                        cur.next = pre ;
                    }else{
                        Node.insert(pre , cur);
                    }
                    break ;
                }
                pre = next ;
                next = next.next ;
            }
            if(null == next){
                pre.next = cur ;
            }
        }
    }
    public static int[] randomArray(int range , int size){
        Random r = new Random();
        int newSize = r.nextInt(size) + 1;
        int[] array = new int[newSize];
        for(int i = 0 ;i < newSize ; i++){
            array[i] = r.nextInt(range);
        }
        return array ;
    }
    public static int[] copyOf(int[] array){
        int[] ans = new int[array.length];
        for(int i = 0 ; i < array.length ; i++){
            ans[i] = array[i];
        }
        return ans ;
    }
    public static void compare(int range , int size , int times){
       int[] array = null ;
       int[] array2 = null ;
       int[] arrayBak = null ;
       for(int i = 0 ; i < times ; i++){
            array = randomArray(range , size);
            array2 = copyOf(array);
            arrayBak = copyOf(array);
            sort(array);
            Arrays.sort(array2);
            if(!Arrays.equals(array ,array2)){
                System.out.println("Oops");
            }
       }
    }
    public static void main(String[] args){
        compare(99 , 40 , 300000);
    }

}

计数排序

连接:

定义:

  1. 构造一个中间数组 A 。 通过 a[i]%A.length 计算出 a[i] 在 A 的下标值,与桶排序不同的是计数排序只是记录落在 A[a[i]%A.length] 位置上的数字的个数。
  2. 构造前缀和数组。通过 A[i] = A[i] + A[i+1] 公式计算出 A[i] 所在最后一个位置,这里为什么是最后一个位置呢?因为,A[i] 上的数字是 2 ,a[ii]%A.length 之前位置上有 8 个数据,所以 a[ii] 所在的位置是 9 和 10 。A[i] = A[i] + A[i+1] 是前缀和的算法。通过前缀就计算出来各个数字的排序位置。
  3. 从 a.length - 1 遍历 a 数组,通过前缀和数组判断 a[i] 所在排好序的位置。遍历完数组后结束。

代码:

public class CountSort {
    private static Logger logger = LoggerFactory.getLogger(CountSort.class);
    public static void sort(int[] array){
        if(null == array || array.length < 2){
            return ;
        }
        int max = 0 , min = 0 ;
        for(int i = 0 ; i < array.length ; i++){
            if(array[i] > max){
               max = array[i] ;
            }
            if(array[i] < min){
                min = array[i];
            }
        }
        int[] mid = new int[max - min + 1];
        for(int i = 0 ; i < array.length ; i++){
            mid[array[i] - min]++;
        }
        for(int i = 1 ; i < mid.length ; i++){
            mid[i] = mid[i-1] + mid[i];
        }
        int[] ans = new int[array.length];
        for(int i = 0 ; i < array.length ; i++){
            ans[mid[array[i] - min] - 1] = array[i];
            mid[array[i] - min]--;
        }
        for(int i = 0 ; i < ans.length ; i++){
            array[i] = ans[i];
        }
    }
    public static void main(String[] args){
        int[] array = {77 , 23 , 1 , -1 , 90 ,6 ,  11};
        sort(array);
        for(int i : array){
            System.out.print(i + ",");
        }
    }
}

注意:

计数排序不适用离散性非常大的情况。处理的方式可以是相对位置来处理,采用 a[i] - min 的值来计算下标值。

基数排序

连接:

定义:

  1. 从一个数组的最高位或者最低位开始,对这一位数字进行计数排序。
  2. 重复对第2高位上的数字进行排序。直到个位数字。

代码:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.Random;

/**
 * @className: RadixSort
 * @Description:
 * @Author: wangyifei
 * @Date: 2022/10/8 10:56
 */
public class RadixSort {
    private static Logger logger = LoggerFactory.getLogger(RadixSort.class);
    public static void sort(int[] array){
        int[] mid = new int[10];
        int[] help = new int[array.length];
        int max = 0 ;
        int tmp = 0 ;
        for(int e: array){
            if(max < ( tmp = hightest(e))){
                max = tmp ;
            }
        }
        for(int i = 1 ; i <= max ; i++){
            for(int e : array){
                mid[num(e,i)]++;
            }
            mid[1] = mid[1] + mid[0];
            for(int a = 2 ; a < mid.length ; a++){
                mid[a] = mid[a] + mid[a-1];
            }
            // 从左道右遍历,因为写入 help 的时候,也是从左道有插入的,这样就能能保持高位排序也是有序的
            // 例如,111 , 123 , 132
            // 当根据十位数拍好序是: 111 , 123 , 132
            // 然后,如果从左到右的顺序遍历 array , 则这几个数据插入后的顺序为 132,123,111
            // 所以给它来一个负负得正
            for(int a = array.length - 1 ; a >= 0 ; a--){
                help[--mid[num(array[a],i)]] = array[a] ;
            }
            for(int a = 0 ; a < help.length ; a++){
                array[a] = help[a];
            }
            for(int a = 0 ; a < mid.length ; a++){
                mid[a] = 0 ;
            }
        }
    }
    public static int hightest(int i){
        int ans = 0 ;
        while( (i = i/10) != 0){
            ans++;
        }
        return ans + 1;
    }

    public static int num(int i , int bit){
        if(bit <= 0){
            throw new RuntimeException("invalidate argument");
        }
        int a = 1 ;
        for(int e = 1 ; e < bit ; e++){
            a *= 10 ;
        }
        return (i/a)%10;
    }
    public static int[] randomArray(int range , int size){
        Random r = new Random();
        int randomSize = r.nextInt(size) + 1;
        int[] ans = new int[randomSize];
        for(int i = 0 ; i < randomSize ; i++){
            ans[i] = r.nextInt(range);
        }
        return ans ;
    }
    public static int[] copyOf(int[] array){
        int[] ans = new int[array.length];
        for(int i = 0 ; i < array.length ; i++){
            ans[i] = array[i];
        }
        return ans ;
    }
    public static void compare(int range , int size , int times){
        int[] array = null ;
        int[] array2 = null ;
        int[] arrayBak = null ;
        for(int i = 0 ; i < times ; i++){
            array = randomArray(range , size);
            array2 = copyOf(array);
            arrayBak = copyOf(array);
            sort(array);
            Arrays.sort(array2);
            for(int a = 0 ; a < array.length ; a++){
                if(array[a] != array2[a]){
                    System.out.println("Oops");
                }
            }
        }
    }

    public static void main(String[] args){
        compare(300 , 40 , 400000);
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值