Java实现排序算法 10种排序方法基本思路 冒泡排序 快速排序 插入排序 希尔排序 选择排序 堆排序 归并排序 基数排序 桶排序 计数排序

基本的排序算法

在这里插入图片描述

1. 最常见简单的冒泡排序:

基本思想:

对当前还未排序好的所有数值,依次对相邻的两个数进行比较和调整。比较发现他们的排序和排序要求相反时,就将他们互换位置。
在这里插入图片描述
算法如下:

    public void bubbleSort(@NotNull int[] a) {
        //r:顺序两两比较,最终进行数组长度-1次
        int r = a.length - 1;
        for (int i = 0; i < r; i++) {
            for (int j = 0; j < r - i; j++) {
                //正序排序, 当前数比后一个数大,交换位置
                if (a[j] > a[j + 1]) {
                    exchangeArray(a, j, j + 1);
                }
            }
        }
    }
    public void exchangeArray(int[] a, int j, int k) {
        int temp = a[j];
        a[j] = a[k];
        a[k] = temp;
    }

2. 快速排序

基本思想:

选择一个元素,将待排序的元素和这个基元素比大小分成两部分,再以同样方法处理这两个部分。
在这里插入图片描述
算法如下:

     /**
     * 快速排序(二分法),小的放左边 大的放右边
     *
     * @param a 需要排序的数据
     * @param l 左边界索引
     * @param r 右边界索引
     */
    public void quickSort(@NotNull int[] a, int l, int r) {
        int middle = a[(l + r) / 2], lp = l, rp = r, temp;
        do {
            //从左边遍历到大于middle的数的索引
            while (a[lp] < middle && lp < r) {
                lp++;
            }
            //从右边遍历到小于middle的数的索引
            while (a[rp] > middle && rp > l) {
                rp--;
            }
            if (lp <= rp) {
                //大的放到右边 小的放到左边
                exchangeArray(a, lp, rp);
            }
        } while (lp <= rp);
        //右边重复动作
        if (lp < r) {
            quickSort(a, lp, r);
        }
        //左边重复动作
        if (rp > l) {
            quickSort(a, l, rp);
        }
    }
    public void exchangeArray(int[] a, int j, int k) {
        int temp = a[j];
        a[j] = a[k];
        a[k] = temp;
    }

3. 直接插入排序

基本思想:将未排序的数值直接插入有序的一组数中,使得插入后的这组数还是有序的。

在这里插入图片描述
算法如下:

    /**
     * 插入排序:将未排序的数值直接插入有序的一组数中,使得插入后的这组数还是有序的
     *
     * @param a 待排序数组
     */
    public void insertSort(int[] a) {
        int temp;
        int i = 0;
        while (i < a.length) {
            int j = i - 1;
            temp = a[i];
            //将大于temp的值整体后移一个位置,并获取到temp在当前有序数组的索引位置
            while (j >= 0 && a[j] > temp) {
                a[j + 1] = a[j];
                j--;
            }
            //将 temp值放入当前有序数组的索引位置
            a[j + 1] = temp;
            i++;
        }
    }

4. 希尔排序(最小增量排序)

基本思想:

先将要排序的一组数按增量d(n/2,n为数组长度)分成若干组,每组中记录的下标相差d,对每组中全部元素进行直接插入排序,然后再用一个较小的增量(d/2取奇数)对它进行分组,再在每组中进行插入排序,当增量减小到1时,进行插入排序,就完成了。
在这里插入图片描述
算法如下:

     /**
     * 希尔排序(最小增量排序):先将要排序的一组数按增量d(n/2,n为数组长度)分成若干组,<br/>
     * 每组中记录的下标相差d,对每组中全部元素进行直接插入排序,<br/>
     * 然后再用一个较小的增量(d/2取奇数)对它进行分组,<br/>
     * 再在每组中进行插入排序,当增量减小到1时,进行插入排序,就完成了
     *
     * @param a
     */
    public void shellSort(int[] a) {
        double d1 = a.length;
        while (true) {
            //d:分组增量  x:分组内索引
            int d = a.length / 2, x = 0;
            while (x < d) {
                //分组内索引增量
                int i = x + d;
                while (i < a.length) {
                    //以分组为单位进行插入排序
                    int j = i - d;
                    int temp = a[i];
                    while (j >= 0 && a[j] > temp) {
                        a[j + d] = a[j];
                        j += d;
                    }
                    a[j + d] = temp;
                    i += d;
                }
                x++;
            }
            if (d == 1) {
                break;
            }
        }
    }

5. 简单选择排序

基本思想:

在要排序的一组数中,选出最小的数和第一个数交互位置,剩下的中再挑最小的放第二位,以此类推。
在这里插入图片描述
算法如下:

    public void selectSort(int[] a){
        int position=0;
        for (int i = 0; i < a.length; i++) {
            int j=i+1;
            position=i;
            int temp=a[i];
            for (; j <a.length ; j++) {
                if (a[j]<temp){
                    temp=a[j];
                    position=j;
                }
            }
            a[position]=a[i];
            a[i]=temp;
        }
    }

6. 堆排序

基本思想:

树形选择排序,对简单选择排序的有效改进。
根的数最大,将根和一个叶交换,踢出最大数,再重新建堆依次类推。
在这里插入图片描述
算法如下:

    public void heapSort(int[] a){
        for (int i = 0; i < a.length-1; i++) {
        	//建大顶堆
            buildMaxHeap(a,a.length-1-i);
            swap(a,0,a.length-1-i);
        }
    }
    private void buildMaxHeap(int[] data,int lastIndex){
	    //从最后一个节点的父节点开始
	    for (int i = (lastIndex-1)/2; i >=0; i--) {
	        //k保存正在判断的节点
	        int k=i;
	        //如果当前k节点的子节点存在
	        while (k*2+1<=lastIndex){
	            	//k节点的左子节点的索引
	            int biggerIndex=2*k+1;
	            //如果biggerIndex<lastIndex,
	            //即biggerIndex+1代表的k节点的右子节点存在
	            if (biggerIndex<lastIndex){
	                //若右子节点的值较大
	                if (data[biggerIndex]<data[biggerIndex+1]){
	                    //总是记录较大子节点的索引
	                    biggerIndex++;
	                }
	            }
	            //如果k节点的值小于其较大子节点的值
	            if (data[k]<data[biggerIndex]){
	                //交换它们
	                swap(data,k,biggerIndex);
	                //将biggerIndex 赋予给k,开始while循环的下一个循环
	                //重新包装k节点的值大于其左右节点的值
	                k=biggerIndex;
	            }else {
	                break;
	            }
	        }
	    }
	}
    private void swap(int[] data, int i, int j) {
        int tmp=data[i];
        data[i]=data[j];
        data[j]=tmp;
    }

7. 归并排序

基本思想:

将两个或以上有序表合并成一个新的有序表。
即把待排序的数组分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
在这里插入图片描述
算法如下:

    public void mergeSort(int[] a, int left, int right) {
        if (left < right) {
            //找出中间索引
            int center = (left + right) / 2;
            //对左边数组进行递归
            mergeSort(a, left, center);
            //对右边数组进行递归
            mergeSort(a, center + 1, right);
            //合并
            merge(a, left, center, right);
        }
    }
    private void merge(int[] a, int left, int center, int right) {
        int[] tmpArr = new int[a.length];
        int mid = center + 1;
        //third记录中间数组索引
        int third = left;
        int tmp = left;
        //从两个数组中取出最小的放入中间数组
        while (left <= center && mid <= right) {
            if (a[left] <= a[mid]) {
                tmpArr[third++] = a[left++];
            } else {
                tmpArr[third++] = a[mid++];
            }
        }
        //剩余部分依次放入中间数组
        while (mid <= right) {
            tmpArr[third++] = a[mid++];
        }
        while (left <= center) {
            tmpArr[third++] = a[left++];
        }
        //将中间数组中的内容复制回原数组
        while (tmp <= right) {
            a[tmp] = tmpArr[tmp++];
        }
    }

8. 计数排序

基本思想:
  1. 找出最大数
  2. 统计数组中每个值为i出现的次数,存入数组arrCount的第i项
  3. 对所有计数进行累加
  4. 将每个元素i放在目标数组的第(arrCount(i))项,每放一个元素就将arrCount(i)–
    计数排序动图演示
	public void countSort(int[] arr){
        int arrMax=findMax(arr);
        int index=0;
        int[] arrCount = new int[arrMax+1];

        for (int i = 0; i < arr.length; i++) {
           arrCount[arr[i]]++;
        }
        for (int i = 0; i < arrCount.length; i++) {
            while (arrCount[i] > 0) {
                arr[index++]=i;
                arrCount[i]--;
            }
        }
    }
    public int findMax(int[] arr){
        int max=0;
        for (int i : arr ) {
            if (i>max){
                max=i;
            }
        }
        return max;
    }

9. 基数排序

基本思想:
  1. 取得数组中的最大数,并且取得最大数的位数;
  2. 从原始数组最低位开始以每个数的【位】(个十百~~)进行分组成radix数组;
  3. 对radix数组进行计数排序
    基数排序动图演示

算法如下:

public class RadixSort {
    /**
     * @Description 进位值
     **/
    final int MOD = 10;

    public void radixSort(int[] arr) {
        //获取最大位数对应值
        int maxBit = maxBit(arr);
        //代表位数对应的数1,10,100,,,
        int mod = 1;
        //保存每一位排序后的结果用于下一位的排序输入
        int index = 0;
        //排序桶用于保存每次排序后的结果,这一位上排序结果相同的数字放在同一个桶里
        int[][] bucket = new int[MOD][arr.length];
        //用于保存每个桶里有多少个数字(10个桶)10进制
        int[] order = new int[MOD];
        while (maxBit > mod) {
            //将数组arr的每个数放在对应桶里
            for (int num : arr) {
                int digit = (num / mod) % 10;
                bucket[digit][order[digit]] = num;
                order[digit]++;
            }
            //将桶里的数据覆盖到原数组中用于保护这一位的排序结果
            for (int i = 0; i < MOD; i++) {
                //桶里有数据,则从上到下遍历这个桶数据保存到原数组
                if (order[i] != 0) {
                    for (int j = 0; j < order[i]; j++) {
                        arr[index] = bucket[i][j];
                        index++;
                    }
                }
                order[i] = 0;
            }
            mod *= MOD;
            index = 0;

        }
    }

    /**
     * @Description 获取数组中的最大位数对应值
     * @Param int[] arr
     * @Return int maxBit 最大位数对应值 1 10 100 ,,,
     **/
    public int maxBit(int[] arr) {
        int maxData = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] > maxData) {
                maxData = arr[i];
            }
        }
        int maxBit = 1;
        while (maxData >= MOD) {
            maxData /= MOD;
            maxBit *= 10;
        }
        return maxBit;
    }
}

10. 桶排序

基本思想:

1.找出数组中的max、min
2.使用 动态数组ArrayList 作为桶,桶里放的元素也用 ArrayList 存储。桶的数量为(max-min)/arr.length+1
3.遍历数组 arr,计算每个元素 arr[i] 放的桶
4.每个桶各自排序
5.遍历桶数组,把排序好的元素放进输出数组
在这里插入图片描述

桶排序原文链接:https://blog.csdn.net/weixin_44026997/article/details/104330955

    public void bucketSort(int[] arr) {
        //计算最大值与最小值
        // -2147483648
        int max = Integer.MIN_VALUE;
        //2147483647
        int min = Integer.MAX_VALUE;
        for (int i = 0; i < arr.length; i++) {
            max = Math.max(max, arr[i]);
            min = Math.min(min, arr[i]);
        }
        //计算桶的数量
        int bucketNum = (max - min) / arr.length + 1;
        ArrayList<ArrayList<Integer>> bucket = new ArrayList<>(bucketNum);
        for (int i = 0; i < bucketNum; i++) {
            bucket.add(new ArrayList<Integer>());
        }
        //将元素放入桶
        for (int i = 0; i < arr.length; i++) {
            int num = (arr[i] - min) / (arr.length);
            bucket.get(num).add(arr[i]);
        }
        //每个桶进行排序
        for (int i = 0; i < bucket.size(); i++) {
            Collections.sort(bucket.get(i));
        }
        //将桶中元素赋值到原数组
        int index = 0;
        for (int i = 0; i < bucket.size(); i++) {
            for (int j = 0; j < bucket.get(i).size(); j++) {
                arr[index++] = bucket.get(i).get(j);
            }
        }

    }

参考:
部分动图来源:https://www.cnblogs.com/onepixel/p/7674659.html
如有错误,欢迎留言!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RyanBruce

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值