算法(java)--十大经典排序

在这里插入图片描述

1. 冒泡排序

主要思想:外层循环从1到n-1,内循环从当前外层的元素的下一个位置开始,依次和外层的元素比较,出现逆序就交换。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。
特点:stable sort(稳定性排序)、In-place sort(不占用额外的空间,只是交换元素)
最优复杂度:当输入数组就是排好序的时候,复杂度为O(n),而快速排序在这种情况下会产生O(n^2)的复杂度。
最差复杂度:当输入数组为倒序时,复杂度为O(n^2)
插入排序比较适合用于“少量元素的数组”。

其实插入排序的复杂度和逆序对的个数一样,当数组倒序时,逆序对的个数为n(n-1)/2,因此插入排序复杂度为O(n^2)。

1.1 算法步骤

  • 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
  • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
  • 针对所有的元素重复以上的步骤,除了最后一个。
  • 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

1.2 代码

public class BubbleSort{
	public int[] sort(int[] sourceArray){
		int[] a = Arrays.copyOf(sourceArray,sourceArray.length);
		for(int i=1;i<a.length;i++){
			for(int j=0;j<a.length-i;j++){
				if(a[j]>a[j+1]){
					int temp = a[j+1];
					a[j+1] = a[j];
					a[j] = temp;
				}
			}
		}
		return a;
	}
}

2. 选择排序

特性:In-place sort,unstable sort。
思想:每次找一个最小值。
最好情况时间:O(n^2)。
最坏情况时间:O(n^2)。

2.1 算法步骤

  • 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置

  • 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。

  • 重复第二步,直到所有元素均排序完毕。

2.2 代码

public class selectionSort{
	public static void sort(int[] array){
		//一共需要n-1次
        for(int i = 0;i<array.length-1;i++){
            int temp = i;
            // 每轮需要比较的次数 N-i
            for(int j = i+1;j<array.length;j++){
                if(array[j]<array[temp]){
                // 记录目前能找到的最小值元素的下标
                    temp = j;
                }
            }
            // 将找到的最小值和i位置所在的值进行交换
            if(temp !=i){
                int a = array[temp];
                array[temp] = array[i];
                array[i] = a;
            }
        }
    }
}

3. 插入排序

主要思想:
特点:stable sort(稳定性排序)、In-place sort(不占用额外空间)
最优复杂度:当输入数组就是排好序的时候,复杂度为O(n),而快速排序在这种情况下会产生O(n^2)的复杂度。
最差复杂度:当输入数组为倒序时,复杂度为O(n^2)
插入排序比较适合用于“少量元素的数组”。

其实插入排序的复杂度和逆序对的个数一样,当数组倒序时,逆序对的个数为n(n-1)/2,因此插入排序复杂度为O(n^2)。

3.1 算法步骤

  • 将待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。

  • 从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)

3.2 代码

public class InsertSort {
    public static void main(String []args){
        int[] arr = {9,8,7,4,3,5,2,3,1,6,2};
        sort(arr);
        System.out.println(Arrays.toString(arr));
    }

    public static void sort(int[] arr){
        for(int i=1;i<arr.length;i++){
            for(int j=i;j>0 && arr[j]<arr[j-1];j--){
                swap(arr,j-1,j);
            }
        }
    }
    /**
     * 交换数组中两个元素
     * @param arr
     * @param i
     * @param j
     */
    public static void swap(int[] arr,int i ,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

插入排序的改进:内循环发现逆序不交换,采用整体右移,直到没有逆序的时候把元素放在该位置

public class InsertSort2 {
    public static void main(String[] args) {
        int[] array = new int[]{2, 3, 5, 8, 9, 0, 7, 5, 1, 6, 8, 7};
        sort(array);
        System.out.println(Arrays.toString(array));
    }

    private static void sort(int[] array) {
        int n = array.length;
        for (int i = 1; i < n; i++) {
            int key = array[i];
            int j = i -1;
            while (j >= 0 && array[j]>key) {
                array[j + 1] = array[j];
                j--;
            }
            array[j+1] = key;
        }
    }
}

4. 希尔排序

思想:基于插入排序,交换不相邻的元素已对数组的局部进行排序,并最终用插入排序将局部有序的数组排序。思想是使数组中任意间隔为h的元素都是有序的,这样的数组称为h有序数组.
特性:In-place sort,unstable sort。
思想:每次找一个最小值。
最好情况时间:O(n)。
最坏情况时间:O(n^2)。

4.1 算法步骤

  • 选择一个增量序列 t1,t2,……,tk,其中 ti > tj, tk = 1;

  • 按增量序列个数 k,对序列进行 k 趟排序;

  • 每趟排序,根据对应的增量 ti,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

在此我们选择增量gap=length/2,缩小增量继续以gap = gap/2的方式,这种增量选择我们可以用一个序列来表示,{n/2,(n/2)/2…1},称为增量序列。希尔排序的增量序列的选择与证明是个数学难题,我们选择的这个增量序列是比较常用的,也是希尔建议的增量,称为希尔增量,但其实这个增量序列不是最优的。此处我们做示例使用希尔增量。
在这里插入图片描述

4.2代码

public class Shell {
    public static void main(String[] args){
        int[] arr = {9,8,7,4,3,5,2,3,1,6,2};
        sort(arr);
        System.out.println(Arrays.toString(arr));
    }

    public static void sort(int[] arr){
        int gap = 1;
        while(gap<arr.length/3) gap=3*gap+1;//一个递增序列gap=1,4,13,40,121,364......
        while(gap >= 1){ //注意这一块
            for(int i = gap;i<arr.length;i++){
                //这里就是插入排序;将a[i]插入到a[i-gap]、a[i-2*gap]、a[i-3*gap]......中去
                for(int j=i; j>=gap && arr[j]<arr[j-gap]; j-=gap){
                    swap(arr,j,j-gap);
                }
            }
            gap = gap/3;
        }
    }
    /**
     * 交换数组中两个元素
     * @param arr
     * @param i
     * @param j
     */
    public static void swap(int[] arr,int i ,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

5. 归并排序

特点:stable sort、Out-place sort
思想:运用分治法思想解决排序问题。
最坏情况运行时间:O(nlgn)
最佳运行时间:O(nlgn)
虽然与快排渐近复杂度一样,但是归并排序的系数比快排大。

程序中merge的精髓(也就是排序):左半边用尽,则取右半边元素;右半边用尽,则取左半边元素;右半边的当前元素小于左半边的当前元素,则取右半边元素;右半边的当前元素大于左半边的当前元素,则取左半边的元素。实际上大部分发生的都是后面两句话,前面两句只是特殊情况而已。

5.1 算法步骤

  • 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;

  • 设定两个指针,最初位置分别为两个已经排序序列的起始位置;

  • 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;

  • 重复步骤 3 直到某一指针达到序列尾;

  • 将另一序列剩下的所有元素直接复制到合并序列尾。
    在这里插入图片描述

5.2 代码

在这里插入图片描述

自顶向下
//mergeSort(a,0,a.length-1);
static void mergeSort(int[] arr,int lo, int hi){
        if(lo>=hi) return;
        int mid = lo + (hi-lo)/2;
        mergeSort(arr,lo,mid);
        mergeSort(arr,mid+1,hi);
        mergeLR(arr,lo,mid,hi);
    }
    static void mergeLR(int[] arr,int lo ,int mid,int hi){
         int[] aux = new int[arr.length];
        for(int i=lo;i<=hi;i++){
            aux[i] = arr[i];
        }
        int l=lo,r=mid+1;
        for(int k=lo;k<=hi;k++){
            if(l>mid){
                arr[k] = aux[r++];
            }else if(r>hi){
                arr[k] = aux[l++];
            }else if(aux[l]<aux[r]){
                arr[k] = aux[l++];
            }else {
                arr[k] = aux[r++];
            }
        }
    }

在这里插入图片描述
首先两两归并,然后四四归并,然后八八归并,一直下去。

自底向上
public class MergeSort2 {

    public static void main(String[] args) {
        int[] array = new int[]{2, 3, 5, 8, 9, 0, 7, 5, 1, 6, 8, 7};
        sort(array);
        System.out.println(Arrays.toString(array));
    }

    public static void sort(int[] array) {
        int N = a.length;
        int[] aux = new int[N];
        for (int n = 1; n < N; n = n+n) {
            for (int i = 0; i < N-n; i += n+n) {
                int lo = i;
                int m  = i+n-1;
                int hi = Math.min(i+n+n-1, N-1);
                merge(array, aux, lo, m, hi);
            }
        }
    }

    private static void merge(int[] array, int[] aux, int lo, int mid, int hi) {
        for (int k = lo; k <= hi; k++) {
            aux[k] = array[k];
        }
        // merge back to a[]
        int i = lo, j = mid+1;
        for (int k = lo; k <= hi; k++) {
            if(i > mid) array[k] = aux[j++];  // this copying is unneccessary
            else if (j > hi) array[k] = aux[i++];
            else if (aux[j]<aux[i]) array[k] = aux[j++];
            else  array[k] = aux[i++];
        }
    }
}

6.快速排序

特性:unstable sort、In-place sort。
最坏运行时间:当输入数组已排序时,时间为O(n^2),当然可以通过随机化来改进(shuffle array 或者 randomized select pivot),使得期望运行时间为O(nlgn)。
最佳运行时间:O(nlgn)
快速排序的思想也是分治法。
当输入数组的所有元素都一样时,不管是快速排序还是随机化快速排序的复杂度都为O(n^2),

6.1 算法步骤

  • 从数列中挑出一个元素,称为 “基准”(pivot);
  • 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。 此过程可以使用两个哨兵i与j。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
  • 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

6.2 代码

public class QuickSort{
    
    public static void quickSort(int[] a,int left,int right){
    	//终止条件
        while(left>right) return;
		//先确定一个基准,以左边第一个元素为基准
        int temp = a[left];
        //指定两个哨兵,分别从左右两端出发
        int i = left,j = right;

        while(i!=j){
        	 //右指针先行,找到一个比基准小的值
             while(a[j]>=temp && i<j) j--;
             //右指针找到后停下,左指针开始向右移动找到一个比基准大的值
       		 while(a[i]<=temp && i<j) i++;
            //右指针找到后停下,如果i,j,不相遇,交换i,j位置上的数字
             if(i<j){
                int t = a[i];
                a[i] = a[j];
                a[j] = t;
             }
        }
		//当i,j相遇后,跳出循环,基准归位,该基准就到了自己的最终位置了
        a[left] = a[i];//右指针先行,i和j交换使得a[left] > a[i]      
        a[i] = temp;//然后就可以交换left和i的值了
	//分别对子序列进行快排
        quickSort(a,left,i-1);
        quickSort(a,j+1,right);
    }
    public static void main(String[] args) {
        int [] array = {5,2,3,1,6,4,7,8,0,9};
        QuickSort.quickSort(array,0,array.length - 1);
        for (int i = 0; i < array.length;i++)
            System.out.print(array[i] + " ");
    }
}

使用荷兰国旗优化后的快排:

public class Code_04_QuickSort {

	public static void quickSort(int[] arr) {
		if (arr == null || arr.length < 2) {
			return;
		}
		quickSort(arr, 0, arr.length - 1);
	}

	public static void quickSort(int[] arr, int l, int r) {
		if (l < r) {
			//随机选择一个数字
			swap(arr, l + (int) (Math.random() * (r - l + 1)), r);
			//先分区,找到等于的区域
			int[] p = partition(arr, l, r);
			//分别对大于和小于的区域快排
			quickSort(arr, l, p[0] - 1);
			quickSort(arr, p[1] + 1, r);
		}
	}
	//less左边(包括less)都是小于的,more右边都是大于的,中间还有等于区域
	public static int[] partition(int[] arr, int l, int r) {
		int less = l - 1;
		int more = r;
		//该步骤可以画图助理解
		while (l < more) {
			//小于,则less右移一位
			if (arr[l] < arr[r]) {
				//这种情况下:less右边紧邻的只会是小于或者等于的数字
				swap(arr, ++less, l++);
			//大于,则more左移一位
			} else if (arr[l] > arr[r]) {
				swap(arr, --more, l);
			//等于,不用交换,直接l右移一位
			} else {
				l++;
			}
		}
		//最后交换more和r上的数字,则more位置变成等于的数字
		swap(arr, more, r);
		//返回等于的位置区间
		return new int[] { less + 1, more };
	}

	public static void swap(int[] arr, int i, int j) {
		int tmp = arr[i];
		arr[i] = arr[j];
		arr[j] = tmp;
	}

7.堆排序

特性:unstable sort、In-place sort。
最优时间:O(nlgn)
最差时间:O(nlgn)

堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。如下图:
在这里插入图片描述
对堆中的结点按层进行编号,将这种逻辑结构映射到数组中就是下面这个样子
在这里插入图片描述
该数组从逻辑上讲就是一个堆结构,我们用简单的公式来描述一下堆的定义就是:

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

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

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

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

7.1 算法步骤

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

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

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

7.2 代码

public class HeapSort2 {
    public static void main(String[] args){
        int[] arr = {1,3,2,6,4,8,5,9,3,5,0};
        sort(arr);
        System.out.print(Arrays.toString(arr));
    }

    public static void sort(int[] arr){
        int N = arr.length;
        //1.构建最大堆
        //为了复用sink()函数,可以从数组最后由右向左下沉元素,构建子堆(从倒数第二层开始,因为叶子节点已经是最大堆了),当然也可以由左向右上浮元素;
        for(int j=N/2;j>0;j--){
        	//这里堆顶下标从1开始
            sink(arr,j,N);
        }
       
        //2.将最大堆的堆顶元素与尾部元素交换,重新调整平衡
        while(N>1){//N代表前N个元素
            exch(arr,1,N--);//(1-N)对应数组(0 - N-1)
            //将堆顶的元素下沉,调整最大堆
            sink(arr,1,N);
        }
    }

    //元素下沉(堆元素序号从 1 开始,简化操作
    public static void sink(int[] arr,int k,int N){
        while(2*k<=N){
            int j=2*k;
            if(j<N && less(arr,j,j+1)) j++;//j<N说明存在j+1=N下标(下标从1 - N)
            if(!less(arr,k,j)) break;
            exch(arr,k,j);
            k=j;
        }
    }
    //元素上浮
//    public static void swim(int[] arr,int k,int N){
//        while(k>1 && less(arr,k/2,k)){
//            exch(arr,k,k/2);
//            k = k/2;
//        }
//    }
    //比较方法
    private static Boolean less(int[] arr,int i,int j){
        if(arr[i-1]<arr[j-1]) return true;
        else return false;
    }
    //交换方法
    private static void exch(int[] arr,int i,int j){
        int temp = arr[i-1];
        arr[i-1] = arr[j-1];
        arr[j-1] = temp;
    }
}
public class Code_03_HeapSort {

	public static void heapSort(int[] arr) {
		if (arr == null || arr.length < 2) {
			return;
		}
		for (int i = 0; i < arr.length; i++) {
			//构建一个大根堆,抽象一个二叉树,物理上是数组
			heapInsert(arr, i);
		}
		int size = arr.length;
		//堆顶元素和最后一个元素交换,则物理数组最后一个是最大的数字
		swap(arr, 0, --size);
		while (size > 0) {
			//将新的堆顶元素下沉,重新构建大顶堆
			heapify(arr, 0, size);
			//循环交换堆顶和堆尾元素
			swap(arr, 0, --size);
		}
	}
	
	//元素上浮插入形成大根堆
	public static void heapInsert(int[] arr, int index) {
		while (arr[index] > arr[(index - 1) / 2]) {
			swap(arr, index, (index - 1) / 2);
			index = (index - 1) / 2;
		}
	}
	//元素下沉构建大根堆
	public static void heapify(int[] arr, int index, int size) {
		int left = index * 2 + 1;
		while (left < size) {
			int largest = left + 1 < size && arr[left + 1] > arr[left] ? left + 1 : left;
			largest = arr[largest] > arr[index] ? largest : index;
			if (largest == index) {
				break;
			}
			swap(arr, largest, index);
			index = largest;
			left = index * 2 + 1;
		}
	}

	public static void swap(int[] arr, int i, int j) {
		int tmp = arr[i];
		arr[i] = arr[j];
		arr[j] = tmp;
	}

8.计数排序

特性:stable sort、out-place sort。
最坏情况运行时间:O(n+k)
最好情况运行时间:O(n+k)

计数排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数

8.1 算法步骤

  • 找出待排序的数组中最大和最小的元素;
  • 统计数组中每个值为i的元素出现的次数,存入数组C的第i项;
  • 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加);
  • 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1。

8.2 代码

public class CountingSort {
    public static void main(String[] args) throws Exception {
        int[] array = { 9, 9, 8, 8, 7, 5, 3, 2, 6, 0, 5 };
        int[] sort = sort(array, 9);
        System.out.println(Arrays.toString(sort));
    }
    /**
     * 输入数组的元素都是介于0..k之间的
     * @param data 待排序数组
     * @param k 最大元素
     * @return 排序结果
     */
    public static int[] sort(int[] data, int k) {
        // 存放临时数据的数组tmp,初始元素都是0;k为数组中最大元素
        int[] tmp = new int[k + 1];

        // 计算数组中每个元素i出现的次数,存入数组tmp中的第i项,即原数组中的元素值为tmp数组中的下标
        for (int i = 0; i <= data.length - 1; i++) {
            tmp[data[i]]++;
        }
        // 计算数组中小于等于每个元素的个数,即从tmp中的第一个元素开始,每一项和前一项相加
        for (int j = 1; j <= k; j++) {
            tmp[j] = tmp[j] + tmp[j - 1];
        }
        // result数组用来来存放排序结果
        int[] result = new int[data.length];
        for (int i = data.length - 1; i >= 0; i--) {
            result[tmp[data[i]] - 1] = data[i];
            tmp[data[i]]--;
        }
        return result;
    }
}

9.桶排序

假设输入数组的元素都在[0,1)之间。
特性:out-place sort、stable sort。
最坏情况运行时间:当分布不均匀时,全部元素都分到一个桶中,则O(n^2),当然[算法导论8.4-2]也可以将插入排序换成堆排序、快速排序等,这样最坏情况就是O(nlgn)。
最好情况运行时间:O(n)
桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。

9.1 算法步骤

设置一个定量的数组当作空桶;
遍历输入数据,并且把数据一个一个放到对应的桶里去;
对每个不是空的桶进行排序;
从不是空的桶里把排好序的数据拼接起来。
在这里插入图片描述

9.2代码

public static void bucketSort(int[] arr) {
		if (arr == null || arr.length < 2) {
			return;
		}
		int max = Integer.MIN_VALUE;
		for (int i = 0; i < arr.length; i++) {
			max = Math.max(max, arr[i]);
		}
		int[] bucket = new int[max + 1];
		for (int i = 0; i < arr.length; i++) {
			bucket[arr[i]]++;
		}
		int i = 0;
		for (int j = 0; j < bucket.length; j++) {
			while (bucket[j]-- > 0) {
				arr[i++] = j;
			}
		}
	}

10.基数排序

特性:stable sort、Out-place sort。
最坏情况运行时间:O((n+k)d)
最好情况运行时间:O((n+k)d)
基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。

10.1 算法步骤

取得数组中的最大数,并取得位数;
arr为原始数组,从最低位开始取每个位组成radix数组;
对radix进行计数排序(利用计数排序适用于小范围数的特点);
在这里插入图片描述

10.2 代码

//基数排序
public class Code_07_RadixSort {

	// only for no-negative value
	public static void radixSort(int[] arr) {
		if (arr == null || arr.length < 2) {
			return;
		}
		radixSort(arr, 0, arr.length - 1, maxbits(arr));
	}

	public static int maxbits(int[] arr) {
		int max = Integer.MIN_VALUE;
		for (int i = 0; i < arr.length; i++) {
			max = Math.max(max, arr[i]);
		}
		int res = 0;
		while (max != 0) {
			res++;
			max /= 10;
		}
		return res;
	}

	public static void radixSort(int[] arr, int begin, int end, int digit) {
		final int radix = 10;
		int i = 0, j = 0;
		int[] count = new int[radix];
		int[] bucket = new int[end - begin + 1];
		for (int d = 1; d <= digit; d++) {
			for (i = 0; i < radix; i++) {
				count[i] = 0;
			}
			for (i = begin; i <= end; i++) {
				j = getDigit(arr[i], d);
				count[j]++;
			}
			for (i = 1; i < radix; i++) {
				count[i] = count[i] + count[i - 1];
			}
			for (i = end; i >= begin; i--) {
				j = getDigit(arr[i], d);
				bucket[count[j] - 1] = arr[i];
				count[j]--;
			}
			for (i = begin, j = 0; i <= end; i++, j++) {
				arr[i] = bucket[j];
			}
		}
	}

	public static int getDigit(int x, int d) {
		return ((x / ((int) Math.pow(10, d - 1))) % 10);
	}

	



// for test
	public static void comparator(int[] arr) {
		Arrays.sort(arr);
	}

	// for test
	public static int[] generateRandomArray(int maxSize, int maxValue) {
		int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
		for (int i = 0; i < arr.length; i++) {
			arr[i] = (int) ((maxValue + 1) * Math.random());
		}
		return arr;
	}

	// for test
	public static int[] copyArray(int[] arr) {
		if (arr == null) {
			return null;
		}
		int[] res = new int[arr.length];
		for (int i = 0; i < arr.length; i++) {
			res[i] = arr[i];
		}
		return res;
	}

	// for test
	public static boolean isEqual(int[] arr1, int[] arr2) {
		if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) {
			return false;
		}
		if (arr1 == null && arr2 == null) {
			return true;
		}
		if (arr1.length != arr2.length) {
			return false;
		}
		for (int i = 0; i < arr1.length; i++) {
			if (arr1[i] != arr2[i]) {
				return false;
			}
		}
		return true;
	}

	// for test
	public static void printArray(int[] arr) {
		if (arr == null) {
			return;
		}
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i] + " ");
		}
		System.out.println();
	}

	// for test
	public static void main(String[] args) {
		int testTime = 500000;
		int maxSize = 100;
		int maxValue = 100000;
		boolean succeed = true;
		for (int i = 0; i < testTime; i++) {
			int[] arr1 = generateRandomArray(maxSize, maxValue);
			int[] arr2 = copyArray(arr1);
			radixSort(arr1);
			comparator(arr2);
			if (!isEqual(arr1, arr2)) {
				succeed = false;
				printArray(arr1);
				printArray(arr2);
				break;
			}
		}
		System.out.println(succeed ? "Nice!" : "Fucking fucked!");

		int[] arr = generateRandomArray(maxSize, maxValue);
		printArray(arr);
		radixSort(arr);
		printArray(arr);

	}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值