排序算法(归并排序、快速排序)

给你n个乱序的整数,让你将它们按照从小到大的顺序排列,这个问题看起来很简单,今天我来介绍几种非常著名的排序算法

归并排序

归并排序是经典的分治思想,要一下子完成n个数的排序不容易,可以把它从中间分割开,分别对左半部分和由半部分的数字排序,然后将两个有序的数组合并起来就得到最终的有序数组

同理,如果左右部分还是很长怎么办?继续分,直到只有一个数的时候,这个局部数组是有序的直接返回

伪代码

归并排序思想的伪代码如下:

复制代码
递归函数:

如果当前只有一个元素,返回

递归排序左半部分

递归排序右半部分

合并两边的数组

假设有一组样例 7,2,4,5,1,8

依照归并排序的思想可以将数组作以下划分

当数组递归到只有一个元素返回后,它的上一层递归就可以将两个有序数组合并,然后继续返回到上一次,以此合并两个有序数组并返回的过程如下图:

代码

java 复制代码
//归并排序
public class MergerSort {
    int[] b;
    public MergerSort(int[] b) {
        //初始化中间数组
        this.b = b;
    }
    public void sort(int[] a,int left,int right) {
        //只有一个元素不用排序
        if(left==right) {
            return;
        }
        //大于1个元素
        int mid=(left+right)/2;
        //分治策略,将数组分成两半分别排序
        sort(a,left,mid);
        sort(a,mid+1,right);

        //左右两部分都排序完毕,将它们合并
        //左半部分数组的下标
        int l_index=left;
        //右半部分数组的下标
        int r_index=mid+1;
        //中间数组b的下标
        int index=left;
        //将两个有序数组合并到一起,直到一个数组为空
        while(l_index<=mid&&r_index<=right) {
            if(a[l_index]<a[r_index]) {
                b[index]=a[l_index];
                l_index++;
            }else{
                b[index]=a[r_index];
                r_index++;
            }
            index++;
        }
        //剩下的数组是有序的直接插入到数组b的后面即可
        while(l_index<=mid){
            b[index++]=a[l_index++];
        }
        while(r_index<=right){
            b[index++]=a[r_index++];
        }

        //将有序的数组复制到原数组中
        for(int i=left;i<=right;i++){
            a[i]=b[i];
        }
    }
}

快速排序

快速排序和归并排序很像,也是利用分治的思想,快速排序每次从数组中选一个数当作中间值,把小于这个中间值的数组放到数组的左边,把大于这个数的值放到数组的右边,然后递归调用自己分别对左半部分和右半部分执行如上操作

中间值的选取

只是说了要选一个中间值,那么到底该选数组中的哪个数作为中间值呢?

常用的就是选择数组中的第一个数当作中间值,不过在极端情况下时间复杂度会退化到n方。

也可以随机选取数组中的一个数当作中间值

还有一种,就是比较左右两端和中间的数字,选介于中间的那个数当作中间值

这里我就用第一种,选择数组中的第一个数当作中间值

伪代码

java 复制代码
快速排序:

如果当前只有一个元素,返回

设置两个指针变量(i,j)分别指向数组头和尾
选择第一个数当作中间值 pivot
while(i<j){
    从后往前找到第一个小于pivot的
    从前往后找到第一个大于pivot的
    如果i<j,交换这两个数
}

将下标j对应的数和数组第一个数交换

递归对左半部分数组做同样操作
递归对右半部分数组做同样操作

代码

java 复制代码
public class QuickSort {

    public void sort(int[] a,int low,int high) {

        if(low>=high) {
            return;
        }
        int partition = partition(a, low, high);

        sort(a,low,partition-1);
        sort(a,partition+1,high);
    }

    //选第一个元素当标准,并划分左右两部分数组
    public int partition(int[] a,int low,int high) {

        int pivot = a[low];
        int i = low;
        int j = high;
        while(i<j) {
            while(i<j&&a[j]>=pivot) j--;
            while(i<j&&a[i]<=pivot) i++;
            //交换
            if(i<j){
                int temp = a[i];
                a[i] = a[j];
                a[j] = temp;
            }
        }
        //将数组中第一个元素即中间值和下标j对应的元素交换
        a[low] = a[j];
        a[j] = pivot;
        return j;
    }
}
相关推荐
KaMeidebaby4 小时前
卡梅德生物技术快报|PD1 单克隆抗体定制配套 N 糖全谱质控开发
前端·人工智能·算法·数据挖掘·数据分析
8Qi84 小时前
LeetCode 235. 二叉搜索树的最近公共祖先(LCA)
算法·leetcode·二叉树·递归·二叉搜索树·lca·迭代
bIo7lyA8v5 小时前
算法稳定性分析中的随机扰动建模的技术8
算法
sugar__salt5 小时前
从栈队列数据结构到JS原型面向对象全解
前端·javascript·数据结构
科研online5 小时前
基于多源数据和XGBoost-SHAP分析中国大陆绿地碳汇空间变异影响因素的非线性相关性与尺度差异
算法·学习方法
Cthy_hy6 小时前
拓扑排序超详解:原理 + Kahn 贪心算法
python·算法·贪心算法
三品吉他手会点灯6 小时前
C语言学习笔记 - 43.运算符与表达式 - 运算符1 - 运算符的分类和简单介绍
c语言·笔记·学习·算法
VkN2X2X4b6 小时前
算法复杂度的实验验证与误差分析的技术8
算法
其利天下技术6 小时前
风扇灯无刷电机自适应算法实战指南
算法·cocos2d·无刷电机自适应算法·bldc驱动自适应算法·其利无刷电机驱动算法
8Qi86 小时前
LeetCode 494:目标和(Target Sum)—— 题解 ✅
算法·leetcode·职场和发展·动态规划·01背包