各种排序方法以及JAVA实现

preview

先给出一张表,今天这个博客介绍的就是这10种排序方法,都是从互联网上其他经典讲解中搜刮过来的,所谓稳定度,指的就是如果原先数组中有相同的元素,他们之间的相对顺序如果变了就是不稳定,反之稳定。

1、插入排序

这个我就是始终和选择排序混淆,现在定义这个插入排序的功能是将无序段中的第一个数不断往前平移,直到在有序段中找到适合它的位置。

public void order(int[] s) {
    for (int i = 1; i < s.length; i++) {
        for (int j = i; j > 0; j--) {
            if(s[j] < s[j-1]){
                int temp = s[j];
                s[j] = s[j-1];
                s[j-1] = temp;
            }
        }
    }
}

 2、希尔排序

希尔排序相当于直接插入排序的一种优化方法,他提出了分组的概念,组数从大到小,最后只有一组,但是因为有了前面的分组并对组内元素进行了插入排序,所以最后一次对整个数组中的插入排序就没有那么大的工程量了,只需要动少数的元素即可。

https://www.cnblogs.com/chengxiao/p/6104371.html

public static void shell_sort(int[] arr){
        for (int gap = arr.length / 2; gap > 0; gap /= 2) {
            //从gap个元素,逐个对其所在组进行直接插入排序操作
            for (int i = gap; i < arr.length; i++) {
                int j = i;
                while(j-gap >= 0 && arr[j] < arr[j-gap]){
                    swap(arr, j, j-gap);
                    j -= gap;
                }
            }
        }
    }
    public static void swap(int []arr,int a,int b){
        arr[a] = arr[a]+arr[b];
        arr[b] = arr[a]-arr[b];
        arr[a] = arr[a]-arr[b];
    }

 3、选择排序

选择排序老是和插入排序傻傻分不清楚,选择排序的思想就是在剩下未排序的序列中选择一个最小的数与未排序的序列的第一个元素交换位置。

public int[] order(int[] s) {
            for (int i = 0; i < s.length; i++) {
                int min = s[i];
                for (int j = i; j < s.length; j++) {
                    //这里s[i]和min总相等
                    if(min>s[j]){
                        s[i] = s[j];
                        s[j] = min;
                        min = s[i];
                    }
                }
            }
            return s;
        }

 4、堆排序

堆排序还是有些复杂了,具体的操作步骤可以视为:

1、用数组先组成一个完全二叉树

2、构造初始堆,要确保两个孩子节点都要比父节点要小。

3、交换第一个元素和最后一个元素,然后输出最后一个元素,重新将新树变为大根堆

https://www.cnblogs.com/jingmoxukong/p/4303826.html

public static void sort(int []arr){
        //1.构建大顶堆
        for(int i=arr.length/2 - 1;i>=0;i--){
            //从第一个非叶子结点从下至上,从右至左调整结构
            adjustHeap(arr,i,arr.length);
        }
        //2.调整堆结构+交换堆顶元素与末尾元素
        for(int j=arr.length-1; j>0; j--){
            swap(arr,0, j);//将堆顶元素与末尾元素进行交换
            adjustHeap(arr,0, j);//重新对堆进行调整
        }

    }

    /**
     * 调整大顶堆(仅是调整过程,建立在大顶堆已构建的基础上)
     * @param arr
     * @param i
     * @param length
     */
    public static void adjustHeap(int []arr,int i,int length){
        int temp = arr[i];//先取出当前元素i
        for(int k=i*2+1;k<length;k=k*2+1){//从i结点的左子结点开始,也就是2i+1处开始
            if(k+1<length && arr[k]<arr[k+1]){//如果左子结点小于右子结点,k指向右子结点
                k++;
            }
            if(arr[k] >temp){//如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
                arr[i] = arr[k];
                i = k;
            }else{
                break;
            }
        }
        arr[i] = temp;//将temp值放到最终的位置
    }

    public static void swap(int []arr,int a ,int b){
        int temp=arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }

5、冒泡排序

冒泡排序相对来说是最简单的、最直观的一种排序方式了,直接就是比较相邻两个元素,最后做到大的上浮,小的下沉

public void order(int[] s) {
            for (int i = 0; i < s.length; i++) {
                for (int j = 0; j < s.length-i-1; j++) {
                    if(s[j+1] < s[j]){
                        int temp = s[j+1];
                        s[j+1] = s[j];
                        s[j] = temp;
                    }
                }
            }
        }

 6、快速排序

快速排序的主要思想就是寻找一个基准值,然后分别从前往后以及从后往前遍历数组,大于基准值的就放在后面,小于基准值的就放在前面,这样基准值的位置就确定了,而我们现在只需要分别处理基准值前面的和基准值后面的。再以同样的方法进行排序

https://blog.csdn.net/nrsc272420199/article/details/82587933

public void quickSort(int[] arr, int left, int right){
            if(left < right){
                //真正排序的过程就是在这个函数中,这里是获取基准值应该在数组中的正确位置
                int partitionIndex = partition(arr, left, right);
                //请注意这个时候我们就只需要将基准数两端的给排好就行了
                quickSort(arr, left, partitionIndex - 1);
                quickSort(arr, partitionIndex + 1, right);
            }
        }
        public int partition(int[] arr, int left, int right){
            //选取最左侧的一个数为基准值
            int pivot = arr[left];
            while(left < right){
                //当队尾元素大于等于基准数据时,向前挪动high指针,注意这里跳出循环的判断条件
                //也是left = right
                while(left < right && arr[right] >= pivot){
                    right--;
                }
                //当对位元素小于pivot时,需要将其赋给left
                arr[left] = arr[right];
                //当队首元素小于等于pivot时,向后挪动right指针
                while(left < right && arr[left] <= pivot){
                    left++;
                }
                arr[right] = arr[left];
            }
            //跳出循环是right和left是相等的,此时right或high就是tmp的正确索引位置
            //由原理部分可以很清楚的指导low的位置并不是tmp,所以这个时候我们应该将pivot的值
            //赋给arr[low];
            arr[left] = pivot;
            return right;
        }

7、归并排序

归并排序是分治的思想,分治算法有“分”也有“治”,主要的排序是在“治”中实现的

https://www.cnblogs.com/chengxiao/p/6194356.html

public void order(int[] s) {
            int[] temp = new int[s.length];
            sort(s, 0, s.length-1, temp);
        }
        public void sort(int[] arr, int left, int right, int[] temp){
            if(left < right){
                //这里是分的一个过程
                //通过递归对没一个子序列进行分组并进行合并(排序是在合并的时候进行的)
                int mid = (left + right) / 2;
                sort(arr, left, mid, temp);//左边归并排序,使左子序列有序
                sort(arr, mid + 1, right, temp);
                merge(arr, left, mid, right, temp);
            }
        }
        private void merge(int[] arr, int left, int mid, int right, int[] temp){
            int i = left;//左序列指针
            int j = mid + 1;//右序列指针
            int t = 0;//临时数组指针
            while(i <= mid && j <= right){
                if(arr[i] <= arr[j]){
                    temp[t++] = arr[i++];
                }else{
                    temp[t++] = arr[j++];
                }
            }
            //还有某个子序列没有遍历完
            while(i<=mid){
                temp[t++] = arr[i++];
            }
            while(j<=right){
                temp[t++] = arr[j++];
            }
            t = 0;
            //将temp中的元素全部拷贝到原数组中
            while(left <= right){
                arr[left++] = temp[t++];
            }
        }

剩下的这三种排序方法就比较简单了,但是空间复杂度比较高

8、计数排序

https://www.cnblogs.com/xiaochuan94/p/11198610.html

public static void countSort(int[] A){
        //找出数组A中的最大值
        int max = Integer.MIN_VALUE;
        for (int num : A){
            if(num > max){
                max = num;
            }
        }
        //初始化计数数组count
        int[] count = new int[max+1];
        //对计数数组各元素赋值
        for (int num : A){
            count[num]++;
        }
        // 创建结果数组的起始索引
        int index = 0;
        // 遍历计数数组,将计数数组的索引填充到结果数组中
        for (int i=0; i<count.length; i++) {
            while (count[i]>0) {
                A[index++] = i;
                count[i]--;
            }
        }
    }

9、桶排序

https://blog.csdn.net/qq_27124771/article/details/87651495

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

10、基数排序

基数排序适合对整数进行排序,从各位到最高位分别排完序之后就是最后的结果

https://www.cnblogs.com/luomeng/p/10639926.html

private static void radixSort(int[] arr){
        //待排序列最大值
        int max = arr[0];
        int exp;
        //计算最大值
        for (int num : arr) {
            if(num > max){
                max = num;
            }
        }
        //从个位开始,对数组进行排序
        for (exp = 1; max / exp > 0 ; exp *= 10) {
            //分桶个数
            ArrayList<ArrayList<Integer>> list = new ArrayList<>(10);
            for (int i = 0; i < 10; i++) {
                list.add(new ArrayList<Integer>());
            }
            //将数据出现的次数存储在buckets中
            for (int value : arr) {
                list.get((value / exp) % 10).add(value);
            }
            int index = 0;
            for (int i = 0; i < list.size(); i++) {
                for (int j = 0; j < list.get(i).size(); j++) {
                    arr[index++] = list.get(i).get(j);
                }
            }
        }
    }

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值