十大排序算法

https://www.cxyxiaowu.com/2026.html、
https://www.cxyxiaowu.com/725.html

1、冒泡排序

从序列的一端往另一端冒泡,依次比较相邻的两个数的大小。
在这里插入图片描述

public int[] sortMP(int[] arr) {
        for(int i = arr.length-1;i > 0;i--) {
            boolean isSort = true;
            for(int j = arr.length-1;j > arr.length-i-1;j--) {
                int temp;
                if(arr[j] < arr[j-1]) {
                    temp = arr[j-1];
                    arr[j-1] = arr[j];
                    arr[j] = temp;
                    isSort = false;
                }
            }
            if(isSort) {
                break;
            }
        }
        return arr;
    }

时间复杂度:O(n^2)

2、选择排序

在未排序序列中找到最小(大)元素,存放到的已排序序列的起始位置;再从剩下的未排序序列中继续找到最小(大)元素,放到已排序序列的末尾。重复操作直至所有元素均已排序完毕。
在这里插入图片描述

    public int[] sortXZ(int[] arr) {
        for(int i = 0;i<arr.length-1;i++) {
            int minIndex = i;
            for(int j = i+1;j<arr.length;j++) {
                if(arr[j] < arr[minIndex]) {
                    minIndex = j;
                }
            }
            int temp = arr[i];
            arr[i] = arr[minIndex];
            arr[minIndex] = temp;
        }
        return arr;
    }

时间复杂度:O(n^2)

3、插入排序

将序列的第一个元素看做一个有序序列,第二个元素到最后一个元素看做未排序序列。在未排序序列选择元素插入已排序序列的适当位置
如序列【9,1,8,4,6】:
第一轮:【9,1,8,4,6】(整个序列都是未排序序列)
第二轮:【1,9,8,4,6】(已排序序列:1,9;未排序序列:8,4,6)
第三轮:【1,8,9,4,6】(已排序序列:1,8,9;未排序序列:4,6)
第四轮:【1,4,8,9,6】(已排序序列:1,4,8,9;未排序序列:6)
第五轮:【1,4,6,8,9】(整个序列都是已排序序列)
在这里插入图片描述

    public int[] sortCR(int[] arr) {
        for(int i = 1;i<arr.length;i++) {
            int min = arr[i];
            for(int j = i-1;j >= 0;j--) {
                if(arr[j] > min) {
                    arr[j+1] = arr[j];
                }else {
                    break;
                }
            }
            arr[j+1] = min;
        }
        return arr;
    }

时间复杂度:O(n^2)

4、希尔排序

选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;按增量序列个数k,对序列进行k趟排序;每趟排序,根据对应的增量ti,将待排序序列分割成若干长度为m的子序列,分别对各子表进行直接插入排序。仅增量因子为1时,整个序列作为一个表来处理。
在这里插入图片描述

    public int[] sortXE(int[] arr) {
        int gap = 1;
        while (gap < arr.length) {
            gap = gap * 3 + 1;
        }
        while (gap > 0) {
            for (int i = gap; i < arr.length; i++) {
                int temp = arr[i];
                int j = i - gap;
                while (j >= 0 && arr[j] > temp) {
                    arr[j + gap] = arr[j];
                    j -= gap;
                }
                arr[j+gap] = temp;
            }
            gap = gap / 3;
        }
        return arr;
    }

5、归并排序

核心思想是分治法,将一个数组分为两部分,递归分,直至分为单个元素,然后重组合并,单个元素合并成小数组,小数组合并成大数组,直到最后合并完成,排序完毕。
在这里插入图片描述

public int[] sortGB(int[] arr){
        if(arr.length < 2 ){
            return arr;
        }
        int middle = arr.length/2;
        int[] left = Arrays.copyOfRange(arr,0,middle);
        int[] right = Arrays.copyOfRange(arr,middle,arr.length);

        return merge(sortGB(left),sortGB(right));
    }

    /**
     * 合并
     * @param left
     * @param right
     * @return
     */
    public int[] merge(int[] left,int[] right){
        int[] result = new int[left.length + right.length];
        int l = 0;
        int r = 0;
        for(int i = 0;i<result.length;i++){
            if(l > left.length-1){
                result[i] = right[r++];
            }else if(r > right.length-1){
                result[i] = left[l++];
            }else if(left[l] < right[r]){
                result[i] = left[l++];
            }else{
                result[i] = right[r++];
            }
        }
        return result;
    }

6、快速排序

核心思想也是分治法。每次从序列中选出一个基准值,其他元素和基准值比较,比基准值大的放右边,比基准值小的放左边,然后再对左边和右边的两组数分别选出一个基准值,进行同样的比较,重复直至最后都变成单个元素。
在这里插入图片描述

    public int[] sortKS(int[] arr){
        sortKS(arr,0,arr.length-1);
        return arr;
    }

    private int[] sortKS(int[] arr,int left,int right){
        if(left < right){
            int partitionIndex = patition(arr,left,right);
            sortKS(arr,left,partitionIndex - 1);
            sortKS(arr,partitionIndex + 1,right);
        }
        return arr;
    }

    public int patition(int[] arr,int left,int right){
        int pivot = left;
        int index = pivot + 1;
        for(int i = index;i<= right;i++){
            if(arr[i] < arr[pivot]) {
                swap(arr,i,index);
                index++;
            }
        }
        swap(arr,pivot,index-1);
        return index-1;
    }

    public int[] swap(int[] arr,int i,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
        return arr;
    }

7、堆排序

对待排序序列创建最大堆,将堆首和堆尾互换;待排序序列减1,重新构建最大堆,再取堆顶的元素;重复步骤,直到堆只剩下一个元素。
在这里插入图片描述

    public int[] sortD(int[] arr){
        int len = arr.length;
        /**
         * 构建最大堆
         */
        buildMaxHeap(arr,len);

        for(int i = len-1;i >0;i--){
            swap(arr,0,i);
            len--;
            heapify(arr,0,len);
        }
        return arr;
    }

    /**
     * 构建最大堆
     * @param arr
     */
    public void buildMaxHeap(int[] arr,int len){
        for(int i = len/2;i >=0;i--){
            heapify(arr,i,len);
        }
    }

    public void heapify(int[] arr,int index,int len){
        int left = index * 2 + 1;//左子节点下标
        int right = index * 2 + 2;//右子节点下标
        int preset = index;
        if(left < len && arr[left] > arr[preset]){
            preset = left;
        }
        if(right < len && arr[right] > arr[preset]){
            preset = right;
        }
        if(preset != index) {
            swap(arr, preset, index);
            heapify(arr, preset, len);
        }
    }

8、计数排序

计数排序是一种非基于比较的排序算法。算法:
扫描整个序列,找到最大值max,创建长度为max的新数组,新数组中元素记录的值是index元素出现的次数。最后遍历新数组,输出相应元素以及对应的个数。
在这里插入图片描述

 public int[] sortJS(int[] arr) {
     int[] newArr = new int[getMax(arr)+1];
     for(int value:arr) {
         newArr[value] ++;
     }
     
     int index=0;
     for(int i = 0;i < newArr.length;i++) {
         while(newArr[i] > 0) {
             arr[index++] = i;
             newArr[i]--;
         }
     }
     return arr;
 }
public int getMax(int[] arr) {
     int max = arr[0];
     for(int i = 1;i < arr.length;i++) {
         if(arr[i] > max) {
             max = arr[i];
         }
     }
     return max;
 }

计数排序的局限性:
如果要拍的数据范围比较大,比如[1,9999],如果用计数排序,两个数创建一个int[10000]的数组;如果是[9998,9999]这种虽然数值大但相差范围不大的数据可以用偏移量解决,比如减掉9997后只需要申请int[3]的数组就可以计数。

计数排序只适用于正整数并且取值范围相差不大的数组排序使用,其排序速度快于任何比较型的排序算法。

9、桶排序

桶排序可以看成计数排序的升级版,他将要排序的数据分到多个有序的桶里,每个桶里的数据再单独排序,并把每个桶的数据依次取出。

在这里插入图片描述

	public static int[] sortBucket(int[] arr) {
	    //获取最大值和最小值
	    int maxValue = arr[0];
	    int minValue = arr[0];
	    for(int value : arr) {
	        if(value > maxValue) {
	            maxValue = value;
	        }else if(value < minValue){
	            minValue = value;
	        }
	    }
	    
	    //桶列表
	    ArrayList<ArrayList<Integer>> bucketList = new ArrayList<>();
	    for(int i = 0; i < arr.length; i++){
	        bucketList.add(new ArrayList<>());
	    }

	    //每个桶的存数区间
	    int section  = (int) Math.floor((maxValue - minValue) / (arr.length - 1));
	    
	    //数据入桶
	    for(int i=0;i<arr.length;i++) {
	      //当前数除以区间得出存放桶的位置 减1后得出桶的下标
	        int num = (int)(arr[i]/section)-1;
	        if(num < 0){
	            num = 0;
	        }
	        bucketList.get(num).add(arr[i]);
	    }
	    
	    //桶内排序
	    for(int i = 0; i < bucketList.size(); i++) {
	        Collections.sort(bucketList.get(i));
	    }
	    
	  //写入原数组
	    int index = 0;
	    for(ArrayList<Integer> arrayList : bucketList){
	        for(int value : arrayList){
	            arr[index++] = value;
	        }
	    }
	    return arr;
	}

桶排序比较好理解,写代码时需要考虑的问题:

  • 桶用什么表示?
    桶是一个可以存放数据的集合,这里使用arrayList。
  • 怎么确定桶的数量?
    桶的数量设置为了原数组的长度,理想情况下每个数据装一个桶。
  • 桶内排序用什么方法排序?

桶排序的思考及其应用
在额外空间充足的情况下,尽量增大桶的数量,极限情况下每个桶只有一个数据时,或者是每只桶只装一个值时,完全避开了桶内排序的操作,桶排序的最好时间复杂度就能够达到 O(n)。
比如高考总分 750 分,全国几百万人,我们只需要创建 751 个桶,循环一遍挨个扔进去,排序速度是毫秒级。
但是如果数据经过桶的划分之后,桶与桶的数据分布极不均匀,有些数据非常多,有些数据非常少,比如[ 8,2,9,10,1,23,53,22,12,9000 ]这十个数据,我们分成十个桶装,结果发现第一个桶装了 9 个数据,这是非常影响效率的情况,会使时间复杂度下降到 O(nlogn),解决办法是我们每次桶内排序时判断一下数据量,如果桶里的数据量过大,那么应该在桶里面回调自身再进行一次桶排序。

10、基数排序

基数排序是一种非比较型整数排序的算法,其原理是将数据按位数切割成不同的数字,然后按每个位数分别比较。基数排序可以看成桶排序的扩展,也是用桶来辅助排序
在这里插入图片描述

	public static int[] sortJsByBucket(int[] arr) {
	    int maxDigit = getMaxDigit(arr);
	    return radixSort(arr, maxDigit);
    }
	
	private static int[] radixSort(int[] arr, int maxDigit) {
	    //桶列表
	    ArrayList<ArrayList<Integer>> bucketList = new ArrayList<>();
	    //长度为10 装入余数0-9的数据
	    for(int i = 0; i < 10; i++){
	        bucketList.add(new ArrayList());
	    }
	    
	    for(int i = 0;i < maxDigit;i++) {
	        //数据入桶
	        for(int j = 0;j < arr.length;j++) {
	            //计算余数
	            int bucket = ((arr[j] / (int)Math.pow(10,i)) % 10);
	            //放入相应的桶
	            bucketList.get(bucket).add(arr[j]);
	        }
	        //写回数组
	        int pos = 0;
	        int index = 0;
	        for (int k=0;k<10;k++){
	            int size = bucketList.get(k).size();
	            for(int l = 0;l < size;l ++){
	                arr[index++] = bucketList.get(k).get(l);
	            }
	            bucketList.get(k).clear();
	        }
	    }
	    return arr;
    }
    /**
	 * 获取最高位数
	 */
	public static int getMaxDigit(int[] arr) {
	    int maxValue = getMaxValue(arr);
	    return getNumLength(maxValue);
	}
	private static int getNumLength(long num) {
	    if(num == 0) {
	        return 1;
	    }
	    int length = 0;
	    for(long temp = num;temp != 0;temp /=10) {
	        length++;
	    }
	    return length;
	}
	/**
	 * 获取最大值
	 */
    public static int getMaxValue(int[] arr) {
        int maxValue = arr[0];
        for (int value : arr) {
            if (maxValue < value) {
                maxValue = value;
                }
            }
        return maxValue;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值