C C++最全数据结构-排序篇_区间排序(2),2024年最新【一篇文章搞懂

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

public class ShellSort {
    public static void sort(int[] a){
        //1.根据a的长度确定增长量h
        int h = 1;
        while (h < a.length/2){
            h = 2*h+1;
        }
        //2.希尔排序
        while ( h>=1 ){
           //排序:找到待插入的元素,
            for (int i = h; i < a.length; i++) {
                for (int j = i; j >= h ; j-=h) {
                    if (a[j-h]>a[j]){
                        //交换元素
                        swap(a,j-h,j);
                    }else {//j-h 比 j 小,不用交换。
                        break;
                    }
                }
            }
            h=h/2;
        }
    }
    private static void swap(int[] a, int i, int j){
        int emp;
        emp = a[i];
        a[i] = a[j];
        a[j] = emp;
    }
}

2.3 稳定性:不稳定

3. 选择排序

3.1 直接选择排序-原理

【算法思想】
第一趟简单选择排序时,从第一个记录开始,通过 n-1 次关键字的比较,从 n 个记录中选出关键字最小的记录,并和第一个记录进行交换。
第二趟简单选择排序时,从第二个记录开始,通过 n-2 次关键字的比较,从 n-1 个记录中选出关键字最小的记录,并和第二个记录进行交换。
第 i 趟简单选择排序时,从第 i 个记录开始,通过 n-i 次关键字的比较,从 n-i+1 个记录中选出关键字最小的记录,并和第i个记录进行交换。
如此反复,经过 n-1 趟简单选择排序,将把 n-1 个记录排到位,剩下一个最小记录直接在最后,所以共需进行 n-1 趟简单选择排序。

3.2 实现

public class SelectSort {

 public static void sort(int[] array){

     for (int i = 0; i < array.length-1; i++) {
         int k = i;
         for (int j = i+1; j < array.length; j++) {
             if (array[j] < array[k]){
                 k = j;
             }
         }
         swap(array,k,i);
     }
 }

    private static void swap(int[] a, int i, int j){
        int emp;
        emp = a[i];
        a[i] = a[j];
        a[j] = emp;
    }
}

3.3稳定性:不稳定

3.4 双向选择排序(了解)

每一次从无序区间选出最小 + 最大的元素,存放在无序区间的最前和最后,直到全部待排序的数据元素排完 。

public static void selectSort(int[] array) {
    
    for (int i = 0; i < array.length - 1; i++) {

        // 无序区间: [0, array.length - i)
        // 有序区间: [array.length - i, array.length)
        int max = 0;
        for (int j = 1; j < array.length - i; j++) {
        
            if (array[j] > array[max]) {
            max = j;
        }
    }

    int t = array[max];
    array[max] = array[array.length - i - 1];
    array[array.length - i - 1] = t;

    }
}

4. 堆排序

4.1 原理基本原理也是选择排序,只是不在使用遍历的方式查找无序区间的最大的数,而是通过堆来选择无序区间的最大的数。

【算法思想】
①将待排序记录按照堆的定义建初堆(算法 9.9),并输出堆顶元素。
②调整剩余的记录序列,利用筛选法将前 n-i 个元素重新筛选建成为一个新堆,再输出堆顶元素。
③重复执行步骤②,进行 n-1 次筛选,新筛选成的堆会越来越小,而新堆后面的有序关键
字会越来越多,最后使待排序记录序列成为一个有序的序列,这个过程称之为堆排序。
画图过程比较繁琐,大家可以按照思路以及代码自己画着理解一下。

4.2 实现

public class HeapSort {
    
    public static void sort(int[] array){
        //建初堆:升序建大堆,降序建小堆。
        for (int i = (array.length-2)/2; i >=0 ; i--) {
            shiftDown(array,array.length,i);
        }
        //维护堆:堆顶元素与最后一个元素交换后,堆顶的“堆性质”被破环,需要维护。此时维护的堆大小应该是依次减小的。
        for (int i = 0; i < array.length-1; i++) {
            swap(array,0,array.length-i-1);
            shiftDown(array,array.length-i-1,0);
        }
    }

    private static void shiftDown(int[] array, int length, int index) {

        while (index*2+1 < length){
            int left = index*2+1;
            int right = left+1;
            int max = left;

            if (right < length && array[left] < array[right]){
                max = right;
            }

            if (array[index] >= array[max]){
                return;
            }
            swap(array,index,max);
            index = max;
        }
    }

    private static void swap(int[] a, int i, int j){
        int emp;
        emp = a[i];
        a[i] = a[j];
        a[j] = emp;
    }
}

4.3 稳定性:不稳定

5. 冒泡排序

5.1 原理:在无序区间,通过相邻数的比较,将最大的数冒泡到无序区间的最后,持续这个过程,直到数组整体有序

5.2 实现:

public class BubbleSort{

    public void sort(long[] array) {
        for (int i = 0; i < array.length - 1; i++) {
            boolean sorted = true;
            for (int j = 0; j < array.length - i - 1; j++) {
                if (array[j] > array[j + 1]) {
                    SortUtil.swap(array, j, j + 1);
                    sorted = false;
                }
            }
            if (sorted) {
                return;
            }
        }
    }
}

5.3 稳定性:稳定

6. 快速排序(重要)

6.1 原理-总览

1. 从待排序区间选择一个数,作为基准值(pivot);

2. Partition: 遍历整个待排序区间,将比基准值小的(可以包含相等的)放到基准值的左边,将比基准值大的(可以包含相等的)放到基准值的

右边;

3. 采用分治思想,对左右两个小区间按照同样的方式处理,直到小区间的长度 == 1,代表已经有序,或者小区间的长度 == 0,代表没有数据。

6.2 原理-partition:快速排序的精髓所在就是 partition 操作,实现这一操作有很多方法,总的一点就是根据 pivot 来分割数据。

6.3 稳定性:不稳定

6.4 原理-基准值的选择

1. 选择边上(左或者右)

2. 随机选择

3. 几数取中(例如三数取中):array[left], array[mid], array[right] 大小是中间的为基准值

6.5 代码实现:



public class QuickSort {
    public static void sort(int[] array) {
        
        quickSortRange(array,0,array.length-1);
    }

    // 为了代码书写方便,我们选择使用左闭右闭的区间表示形式
    // from,to 下标的元素都算在区间的元素中
    // 左闭右闭的情况下,区间内的元素个数 = to - from + 1;
    private static void quickSortRange(int[] array, int from, int to) {

        if (to - from +1 <= 1) {
            // 区间中元素个数 <= 1 个
            return;
        }

        // 挑选中区间最右边的元素 array[to],
        //int pi = partitionMethodA(array, from, to);
        //经过该步处理后数组array中的数据呈现: [from,pi)的元素是小于 pivot ;(pi,array.length-1]元素是大于 pivot ;
        //pivot == array[pi];
        // 按照分治算法的思路,使用相同的方式,处理相同性质的问题,只是问题的规模在变小
        int[] index = partitionD(array,from,to);
        int left = index[0];
        int right = index[1];
        quickSortRange(array, from, left);    // 针对小于等于 pivot 的区间做处理
        quickSortRange(array, right, to);   // 针对大于等于 pivot 的区间做处理
    }

    /**
     * 以区间最右边的元素 array[to] 最为 pivot,遍历整个区间,从 from 到 to,移动必要的元素
     * 进行分区
     * @param array
     * @param from
     * @param to
     * @return 最终 pivot 所在的下标
     */

    /*
        <= pivot: [from,left];
        > pivot : [right,to];
        未比较 :   (left,right);
     */
    private static int partitionA(int[] array, int from, int to) {
        int left = from;
        int right = to;
        int pivot = array[to];
        while (left < right){
            while (left < right && array[left] <= pivot){
                left++;
            }
            while(left < right && array[right] >= pivot){
                right--;
            }
            swap(array,left,right);
        }
        swap(array,left,to);
        return left;

    }

    /*
        <= pivot: [from,left];
        > pivot : [right,to];
        未比较 :   (left,right);

     */
    public static int partitionB(int[] array, int from, int to){
        int pivot = array[to];
        int left = from;
        int right = to;

        while(left < right){
            while(left < right && array[left] < pivot){
                left++;
            }
            array[right] = array[left];
            while(left < right && array[right] > pivot){
                right--;
            }
            array[left] = array[right];
        }
        array[left] = pivot;
        return left;
    }

    /**
     * 对 array 的 [from, to] 区间进行分区
     * 分区完成之后,区间被分割为 [<= pivot] pivot [>= pivot]
     * 分区过程中,始终保持
     * [from, s)    小于 pivot
     * [s, i)       大于等于 pivot
     * [i, to)      未比较过的元素
     * [to, to]     pivot
     * @param array
     * @param from
     * @param to
     * @return pivot 最终所在下标
     */
    public static int partitionC(int[] array,int from,int to){

        int s = from;
        int pivot = array[to];
        for (int i = from; i < to; i++) {   // 遍历 [from, to)
            // 这里加 == 号也保证不了稳定性,有交换操作
            if (array[i] < pivot) {
                // TODO: 可以进行简单的优化:如果 i == s,就不交换
                swap(array,i,s);
                s++;
            }
        }

        array[to] = array[s];
        array[s] = pivot;

        return s;
    }

    public static int[] partitionD(int[] array,int from,int to){

        int s = from;
        int i = from;
        int g = to;

        int pivot = array[to];
        while (g-i+1 > 0){
            if (array[i] == pivot){
                i++;
            }else if (array[i] < pivot){
                swap(array,s,i);
                s++;i++;
            }else {
                swap(array,g,i);
                g--;
            }
        }
        return new int[] {s-1,i};
    }

    public static int partitionE(int[]array,int left,int right){
        int d = left + 1;
        int pivot = array[left];

        for (int i = left+1; i <=right ; i++) {
            if(array[i] < pivot) {
                swap(array,i,d);
                d++;
            }
        }
        swap(array,d,left);
        return d;
    }


    private static void swap(int[] a, int i, int j){


![img](https://img-blog.csdnimg.cn/img_convert/c23f3166c3e39c142510663b8c54c433.png)
![img](https://img-blog.csdnimg.cn/img_convert/06469e484b0e2a1fd968d758cc1de79c.png)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

}
        swap(array,d,left);
        return d;
    }


    private static void swap(int[] a, int i, int j){


[外链图片转存中...(img-e5t25YCt-1715707495637)]
[外链图片转存中...(img-QxsJZRjZ-1715707495638)]

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值