java:排序算法(下) 小白讲法------------ 快速排序,堆排序,归并排序

本文介绍了快速排序和堆排序算法。快速排序采用分治算法,重点是将区间分成三部分,有Hover法、挖坑法、前后下标法三种分组方法。堆排序用于解决选择排序重复比较问题,需先建大堆,再对大堆做向下调整,文中还给出了两种排序的代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 快速排序
    快速排序总体采用了分治算法,可以分为三步:
      ① 找一个基准值,一般选数组最后一个元素为基准
      ② 遍历整个区间,每个数都和基准值作比较,并且发生一定的交换,遍历结束后使得比基准值大的(包括等于)数都在基准值的右边比基准值小的(包括等于)数都在基准值左边
      ③ 分治算法
      分别对基准值左右两个区间的数做相同处理
      直到所有小区间内没有元素了,或小区间内元素已经有序

  快速排序的重点就在于第二步,我们如何能将区间分成三部分。一般我们有三种方法来分组,分别是Hover法、挖坑法、前后下标法,下面来一一介绍。
  Hover法:就是分别用两个下标索引begin、end指向数组的第一个元素和最后一个元素,从begin开始与基准值比较,begin下标处的元素要是小于基准值,begin下标++,往后走,当走到的位置的数大于基准值时,begin停下来,此时end从最后面往前走,若是end处的元素大于基准值,则end- -往前走,若是走到了所在元素大于基准值时,end停下来。此时begin和end都遇到了瓶颈走不动了,我们只需要交换begin和end处的元素即可继续进行,直到begin和end相遇为止,此时即是基准值应该处的位置,我们交换begin(或end)下标处的元素和基准值即可。
  挖坑法:挖坑法首先将区间最后边的基准值保存起来,此处就像形成了一个坑,和Hover法一样,也是用两个下标索引begin和end,分别放在数组最左边和最右边。从begin开始和基准值比较,如果小于基准值,begin++往前走,若是大于基准值,则将该值放入坑中,此时begin处就变成了一个坑,再从end开始,end往前走,若是大于基准值则end- -往前走,若是小于基准值,则将end处的值填在begin处的坑中,重复上述步骤,直到begin和end相遇,相遇处即是基准值所应该在的地方。将基准值填在这里即可。
  前后坐标法:前后坐标法是用了两个下标索引div和i,这两个索引都在left处,将i处的值与基准值进行比较,当该值小于等于基准值时,交换div和i处的值,div和i同时++向后走,如果坐标为i处的值大于基准值时,只让i++向后走,当i遍历完时,div所在的位置就是基准值的位置。
  此处只是对将数组分成三部分做了文字描述,推荐这篇文章,作者利用动画将快速排序讲的更为细致。快速排序优秀文章

快速排序代码如下:

public class Test {
    // 交换两个数
    private static void swap(int[] array, int x, int y){
        int temp = array[x];
        array[x] = array[y];
        array[y] = temp;
    }
    // 快速排序--升序
    // Hover法
    private static int partion(int[] array, int left, int right){
        int begin = left;
        int end = right;
        while(begin < end){
            while(begin < end && array[begin] <= array[right]){
                begin++;
            }
            while(begin< end && array[end] >= array[right]){
                end--;
            }
            swap(array,begin,end);
        }
        swap(array,begin,right);
        return begin;
    }
    // 挖坑法
    private static int partion1(int[] array,int left,int right){
        int begin = left;
        int end = right;
        int pivort = array[right];
        while(begin < end){
            while(begin < end && array[begin] <= pivort){
                begin++;
            }
            array[end] = array[begin];
            while(begin < end && array[right] >= pivort){
                end--;
            }
            array[begin] = array[end];
        }
        array[begin] = pivort;
        return begin;
    }
    // 前后下标法
    private static int partion2(int[] array,int left,int right){
        int div = left;
        int i = left;
        while(i < right){
            if(array[i] > array[right]){
                swap(array,div,i);
                div++;
                i++;
            }else{
                i++;
            }
        }
        swap(array,div,right);
        return div;
    }
    public static void quickSort(int[] array,int left,int right){
        // size == 1
        if(left == right){
            return;
        }
        // size == 0
        if(left < right){
            return;
        }
        int stand = partion(array,left,right); 
        quickSort(array,0,stand-1); 
        quickSort(array,stand+1,right);
    }
    private static void quick(int[] array) {
        if(array.length>0){
            quickSort(array,0,array.length-1);
        }
    }
    public static void main(String[] args) {
        int[] array = {9,5,-1,10,0,2,7,3,8,6};
//        selectSort(array);
        quick(array);
        for(int i = 0; i < array.length; i++){
            System.out.print(array[i]+"、");
        }
    }
}

  1. 堆排序:由于选择排序在遍历过程中,会进行多次重复的比较,因此我们可以采用堆排序来解决这种问题。首先我们把数组建成一个大堆,再对这个大堆做向下调整,向下调整的前提是该堆中只有一个位置不满足堆的性质,其余位置都满足堆的性质了。向下调整分为三步:
    ① 我们首先需要判断传进来的下标是不是叶子节点
    ② 找出该节点的孩子中较大的那一个孩子
    ③ 比较较大的孩子和父节点的大小,若是孩子节点大,则交换,然后继续做向下调整
    代码如下:
public static  void heapSort(int[] array) {
        for (int i = 0; i < array.length; i++) {
            createMaxHeap(array, array.length - 1 - i);
            swap(array, 0, array.length-1-i);
        }
    }
    public static void createMaxHeap(int[] data, int lastIndex) {
        // 从lastIndex处节点(最后一个节点)的父节点开始
        for (int i = (lastIndex-1)/2; i >= 0; i--) {
            int k = i;
            while (2 * k + 1 <= lastIndex) {
                int biggerIndex = 2 * k + 1;
                if (biggerIndex + 1 <= lastIndex) {
                    if (data[biggerIndex] < data[biggerIndex + 1]) {
                        biggerIndex++;
                    }
                }
                if (data[k] < data[biggerIndex]) {
                    swap(data, k, biggerIndex);
                    k = biggerIndex;
                } else {
                    break;
                }
            }
        }
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值