排序算法 下

目录

1.快速排序

2.归并排序

3.计数排序


1.快速排序

快速排序是Hoare在1962年提出的一种二叉树结构的交换排序的方法,采用了递归的思想

思想:任取待排序的元素序列中的某元素作为基准值,按照原来的顺序将序列分为两个子序列,

左子序列中的所有元素均小于基准直,右子树的所有序列中的元素均大于基准直,然后左右子序列重复该过程,直到所有元素都排在相应的位置上。

先写出大致的框架,与二叉树的前序遍历非常之像,写递归框架可以照着二叉树前序遍历写出来,

后续只要分析如何按照基准直对区间中的数据划分即可

public static void  QuickSort(int[] array,int start,int end){
        //递归结束的条件
        if(start >= end){
            return;
        }

        //如果子区间的数据越来越少了,直接采用 范围插入排序 更快
        if(end-start+1 < 10){
            insertSort(array,start,end);
            return;
        }

        //三数取中原因:
        //如果这个序列是接近有序的,1 2 3 4 5 6 7 8 9 11 10
        //基准值一般选取最左侧的数据 1,那么每次递归1的左侧没有子序列,只有右侧
        //所以会大大提高时间复杂度,
        //那么就取最左,最有,最中三个数据的中位数,
        //将中位数与第一个数交换,这样返回的基准直就不是1了,而是与1交换的数
        int index = midTreeNum(array,start,end);
        swap(array,start,index);

        //寻找基准直位置的下标
        //该方法有很多种,等下面我们一一介绍
        int par = paririon(array,start,end);

        //按照基准直,将其左右两个子区间进行排序
        QuickSort(array,start,par-1);
        QuickSort(array,par+1,end);
    }
    //挖坑法
    private static int paririon(int[]array,int left,int right){
        int temp = array[left];
        while (left < right){
            while (left < right && array[right]<=temp){
                right--;
            }
            array[left] = array[right];
            while (left < right && array[left] > temp){
                left++;
            }
            array[right] =array[left];
        }
        array[left] = temp;
        return left;
    }

    //找到中间值的下标
    private static int midTreeNum(int[]array,int left,int right){
        //中间位置下标
        int mid = left+(right-left)/2;

        if(array[left]<array[right]){
            if(array[mid]<array[left]){
                return left;
            }else  if(array[mid]>array[right]){
                return right;
            }else {
                return mid;
            }
        }else {
            if(array[mid]>array[left]){
                return left;
            }else if(array[mid]<array[right]){
                return right;
            }else {
                return mid;
            }
        }
    }
    private static void insertSort(int[]array,int left,int right){
        for(int i=left+1;i<=right;i++){
            int temp = array[i];
            int j = i-1;
            for(;j>=0;j--){
                if(array[j] > temp){
                    array[j+1] = array[j];
                }else {
                    break;
                }
            }
            array[j+1] = temp;
        }
    }

paririon 方法使用用来找到基准直的,通过找到的基准直将序列化分为两个子区间,再通过递归不断排序,缩小子区间,直到子区间就一个数字。

int index = midTreeNum(array,start,end);

这条语句什么意思? 就是取到三个数的中位数

三数取中原因:
如果这个序列是接近有序的,1 2 3 4 5 6 7 8 9 11 10
基准值一般选取最左侧的数据 1,那么每次递归1的左侧没有子序列,只有右侧
所以会大大提高时间复杂度,
那么就取最左,最有,最中三个数据的中位数,
将中位数与第一个数交换,这样返回的基准直就不是1了,而是与1交换的数

上面查找基准值的paririon方法是挖坑法

下面例举Hoare法查找基准值

//Hoare法
    private static int paririon2(int[]array,int left,int right){
        int i = left;
        int temp = array[left];
        
        while (left < right){
            while (left < right && array[right] >= temp){
                right--;
            }
            while (left < right && array[left]<=temp){
                left++;
            }
            swap(array,left,right);
        }
        swap(array,left,i);
        return left;
    }

快速排序总结:

1.整体综合性能与使用场景都是比较好的,才敢较快排

2.时间复杂度:O(N*logN);

3.空间复杂度:O(logN);

4.稳定性:不稳定


2.归并排序

建立在归并操作上的有效排序算法,该算法采用分治法的一个典型的应用。将已有的子序列合并,得到完全有序的序列。

使每个子序列有序,再使每个子序列之间有序。

归并排序:

更多是解决磁盘中的外排序问题。

时间复杂度:O(N*logN)

空间复杂度:O(N)

稳定性:稳定

代码实现

//归并排序
    public static void mergeSort(int[]array){
        megeFun(array,0,array.length-1);
    }
    public static void megeFun(int[]array,int left,int right){
        if(left >=right){
            return;
        }
        //分解
        int mid = left+(right-left)/2;
        megeFun(array,left,mid);
        megeFun(array,mid+1,right);
        //合并
        merge(array,left,mid,right);
    }
    public static void merge(int[]array,int left,int mid,int right){
        int[] temp = new int[right-left+1];
        int sl = left;
        int el = mid;
        int sr = mid+1;
        int er = right;
        int k = 0;
        while (sl<=el && sr<=er){
            if(array[sl] <= array[sr]){
                temp[k++] = array[sl++];
            }else{
                temp[k++] = array[sr++];
            }
        }
        while (sl<=el){
            temp[k++] = array[sl++];
        }
        while (sr<=er){
            temp[k++] = array[sr++];
        }

        for (int i = 0; i < k; i++) {
            array[i+left] = temp[i];
        }
    }


3.计数排序

又叫做鸽巢原理,是对哈希直接定址法的变形应用

1.统计相同元素的出现的次数

2.根据统计结果将序列收回到原来的序列中

时间复杂度:O(max(N,范围))

空间复杂度:O(范围)

稳定性:稳定

代码:

public static void countSort(int[]array){
        //遍历数组找到最大最小值
        int mindex= array[0];
        int maxdex = array[0];

        for (int i = 0; i < array.length; i++) {
            if(maxdex<array[i]){
                maxdex = array[i];
            }
            if(mindex>array[i]){
                mindex = array[i];
            }
        }
        //已经找到最大与最小值了,定义数组
        int[]count = new int[maxdex-mindex+1];
        for (int i = 0; i < array.length; i++) {
            int val = array[i]-mindex;
            count[val]++;
        }
        //count数组以数据为下标,出现的次数为值
        int index = 0;//array的下标
        for (int i = 0; i < count.length ; i++) {
            while (count[i]>0){
                array[index] = i+mindex;
                index++;
                count[i]--;
            }
        }
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值