冒泡排序、插入排序、希尔排序、选择排序、堆排序、快速排序六大排序详解

2023-11-05

1.冒泡排序

思路:

左右相邻的两个数互相比较,大的交换到序列后边,每次遍历排出剩余的最大的数。如下图所示

代码如下:

void BubbleSort(int* a, int n)//n为数组元素个数
{
    int i = 0,j = 0;
    for (i = 0; i < n; ++i)
    {
        for (j = i; j < n-i-1; ++j)
        {
            if (a[j] > a[j + 1])
            {
                Swap(&a[j], &a[j + 1]);
            }
        }
    }
}

时间复杂度:O()

空间复杂度:O(1)

2.插入排序

思路:

  1. 认为数组中的第一个元素已经有序

  1. 之后(n-1)个元素依次与前面已经排好的元素经行比较

  1. 如果待排序元素obj小于已排序好的最后一个元素last,则交换obj和last

  1. obj和新的last比较,直到找到最后一个last小于自己

  1. 重复2-4

思路图如下:

代码如下:

void InsertSort(int* a, int n)//插入排序
{
    for (int i = 0; i < n - 1; i++)
    {
        int end = i;
        int tmp = a[end + 1];
        while (end >= 0)
        {
            if (tmp < a[end])
            {
                a[end + 1] = a[end];
                end--;
            }
            else
            {
                break;
            }
        }

        a[end + 1] = tmp;
    }
}

时间复杂度:最坏情况O()(倒序),最好情况O(n)

空间复杂度:O(1)

3.希尔排序

思路:希尔排序是插入排序的优化版本

1.将待排序数组等分为gap组,每组有n/gap个元素

2.分别对每组进行插入排序

3.缩小gap,重复1和2

4.重复3,直到gap=1

思路导图如下:

代码如下:

void Shellsort(int* a, int n)
{
    int gap = n;
    while (gap > 1)
    {
        gap = gap / 3 + 1;
        for (int i = 0; i < n-gap; i++)
        {
            int end = i;
            int tmp = a[end + gap];
            while (end >= 0)
            {
                if (tmp < a[end])
                {
                    a[end + gap] = a[end];
                    a[end] = tmp;
                    end -= gap;
                }
                else
                    break;
            }
        }
    }
}

时间复杂度:最好情况O(),最坏情况O()

空间复杂度:O(1)

4.选择排序

思路:每次遍历待排序数组时,选出最大值和最小值,最后将其与数组首尾元素互换。

思路导图如下:

代码如下:

void SelectSorrt(int* a, int n)//选择排序
{
    int begin = 0, end = n - 1;

    while (begin < end)
    {
        int mini = begin, maxi = begin;
        for (int i = begin + 1; i <= end; ++i)
        {
            if (a[i] < a[mini])
            {
                mini = i;
            }

            if (a[i] > a[maxi])
            {
                maxi = i;
            }
        }

        Swap(&a[begin], &a[mini]);
        if (maxi == begin)
            maxi = mini;

        Swap(&a[end], &a[maxi]);
        ++begin;
        --end;
    }
}

时间复杂度:O()

空间复杂度:O(1)

5.堆排序

思路:是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是

通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。

代码如下:

void Adjustdown(HeapDatatype* a, int n,  int parent)
//建大堆
{
    int child = parent * 2 + 1;
    while (child < n)
    {
        // 确认child指向大的那个孩子
        if (child + 1 < n && a[child + 1] > a[child])
        {
            child++;
        }
        // 1、孩子大于父亲,交换,继续向下调整
        // 2、孩子小于父亲,则调整结束
        if (a[child] > a[parent])
        {
            Swap(&a[child], &a[parent]);
            parent = child;
            child = parent * 2 + 1;
        }
        else
            break;
    }
}
void Heapsort(int* array, int n)
{
    assert(array);
    for (int i = (n - 1 - 1) / 2; i >= 0; i--)
    {
        Adjustdown(array, n, i);
    }

    for (int i = 0; i < n - 1; i++)
    {
        Swap(&array[0], &array[n - 1 - i]);
        Adjustdown(array, n - 1 - i, 0);
    }
}

时间复杂度:O(nlogn)

空间复杂度:O(1)

  1. 快速排序

6.1 Hoare法

思路:

1、选出一个key,一般是最左边或是最右边的。

2、定义一个begin和一个end,begin从左向右走,end从右向左走。(需要注意的是:若选择最左边的数据作为key,则需要end先走;若选择最右边的数据作为key,则需要bengin先走)。

3、在走的过程中,若end遇到小于key的数,则停下,begin开始走,直到begin遇到一个大于key的数时,将begin和right的内容交换,end再次开始走,如此进行下去,直到begin和end最终相遇,此时将相遇点的内容与key交换即可。(选取最左边的值作为key)

4.此时key的左边都是小于key的数,key的右边都是大于key的数

5.将key的左序列和右序列再次进行这种单趟排序,如此反复操作下去,直到左右序列只有一个数据,或是左右序列不存在时,便停止操作,此时此部分已有序

int PartSort1(int* a, int begin, int end)//Hoare法

{
    int mid = GetMidIndex(a, begin, end);
    int left = begin;
    int right = end;
    int keyi = left;

    Swap(&a[left], &a[right]);
    while (left < right)
    {
        while (left<right && a[right]>a[keyi])//先走右边,找小
        {
            --right;
        }
        while (left < right && a[left] < a[keyi])
        {
            ++left;
        }
        Swap(&a[left], &a[right]);
    }
    Swap(&a[left], &a[keyi]);
    keyi = left;
    return keyi;
}
void QuickSort(int* a, int left, int right)
{
    if (left >= right)
        return;
    if ((right - left + 1) < 15)
    {
        // 小区间用直接插入替代,减少递归调用次数
        InsertSort(a + left, right - left + 1);
    }
    else
    {
        int keyi = PartSort2(a, left, right);
        QuickSort(a, left, keyi - 1);
        QuickSort(a, keyi + 1, right);
    }
}

6.2挖坑法

思路:

1.选出一个数据(一般是最左边或是最右边的)存放在key变量中,在该数据位置形成一个坑

2、还是定义一个L和一个R,L从左向右走,R从右向左走。(若在最左边挖坑,则需要R先走;若在最右边挖坑,则需要L先走)

后面的思路与hoare版本思路类似

int PartSort2(int* a, int begin, int end)//挖坑法
{

    int left = begin;
    int right = end;
    int key = a[left];
    int hole = left;
    while (left < right)
    {
        // 右边找小,填到左边坑里面
        while (left < right && a[right] >= key)
        {
            --right;
        }
        a[hole] = a[right];
        hole = right;

        // 左边找大,填到右边坑里面
        while (left < right && a[left] <= key)
        {
            ++left;
        }
        a[hole] = a[left];
        hole = left;
    }

    a[hole] = key;
    return hole;    
}
void QuickSort(int* a, int left, int right)
{
    if (left >= right)
        return;
    if ((right - left + 1) < 15)
    {
        // 小区间用直接插入替代,减少递归调用次数
        InsertSort(a + left, right - left + 1);
    }
    else
    {
        int keyi = PartSort2(a, left, right);
        QuickSort(a, left, keyi - 1);
        QuickSort(a, keyi + 1, right);
    }
}

6.3前后指针法

思路:

1、选出一个key,一般是最左边或是最右边的。

2、起始时,prev指针指向序列开头,cur指针指向prev+1。

3、若cur指向的内容小于key,则prev先向后移动一位,然后交换prev和cur指针指向的内容,然后cur指针++;若cur指向的内容大于key,则cur指针直接++。如此进行下去,直到cur到达end位置,此时将key和++prev指针指向的内容交换即可。

经过一次单趟排序,最终也能使得key左边的数据全部都小于key,key右边的数据全部都大于key。

int PartSort3(int* a, int begin, int end)
{
    int keyi = begin;
    int prev = begin, cur = begin + 1;
    while (cur <= end)
    {
        // 找到比key小的值时,跟++prev位置交换,小的往前翻,大的往后翻
        if(a[cur] < a[keyi] && ++prev != cur)
            Swap(&a[prev], &a[cur]);
        ++cur;
    }
    Swap(&a[prev], &a[keyi]);
    keyi = prev;
    return keyi;
}
void QuickSort(int* a, int left, int right)
{
    if (left >= right)
        return;
    if ((right - left + 1) < 15)
    {
        // 小区间用直接插入替代,减少递归调用次数
        InsertSort(a + left, right - left + 1);
    }
    else
    {
        int keyi = PartSort3(a, left, right);
        QuickSort(a, left, keyi - 1);
        QuickSort(a, keyi + 1, right);
    }
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

冒泡排序、插入排序、希尔排序、选择排序、堆排序、快速排序六大排序详解 的相关文章

随机推荐

  • java开发常用代码

    基础类型转换 https www cnblogs com expiator p 12602446 html BigDecimal计算 涉及金额之类的运算 不要用 Double Float 这些类型 用 BigDecimal 才能精确计算 详
  • Tensorflow: Model parallelism 模型并行计算

    在tensorflow官方tutorial上给出了多GPU的用法 但那是基于data parallelism的计算 主要思想是将数据划分成不同部分 用同一个模型进行计算 但是我在写代码中发现 会出现单个模型过大无法再单个GPU上运行 这时候
  • JAVA的三大特征之多态

    多态 什么是多态 多态就是同一个行为的不同表现形式 换句话说就是同一个方法因为对象的不同所产生不同的结果 多态存在的条件 继承 重写 父类引用指向子类对象 例 public static void main String args a是人的
  • iOS面试小贴士

    最全的iOS面试题及答案 iOS面试小贴士 回答好下面的足够了 多线程 特别是NSOperation 和 GCD 的内部原理 运行时机制的原理和运用场景 SDWebImage的原理 实现机制 如何解决TableView卡的问题 block和
  • jQuery的Ajax操作小结——$.ajax和$.getJSON等用法小结

    一 ajax用法与举例 jQuery ajax url settings 返回值 XMLHttpRequest 通过 HTTP 请求加载远程数据 这个是jQuery 的底层 AJAX 实现 简单易用的高层实现见 get post 等 最简单
  • 你们公司的【前端项目】是如何做测试的?字节10年测试经验的我这样做的...

    前端项目也叫web端项目 通俗讲就是网页上的功能 是我们能够在屏幕上看到并产生交互的体验 前端项目如何做测试 要讲清楚这个问题 先需要你对测试流程现有一个全局的了解 先上一张测试流程图 测试流程图 接下来下面我们从需求阶段 开发阶段 测试阶
  • vivo的Android升级包,【原厂固件】vivo y66ia系统升级rom刷机包_卡刷包_PD1621B_A_1.9.6...

    今天小编跟大家分享下vivo Y66iA手机固件rom的刷机教程 此版本固件主要是优化了系统安全性 及系统运行的稳定性以及与一些第三方App的兼容性 版本区分方法如下 请在打开手机设置 关于手机 版本里看看是PD1621B A字样 然后下载
  • (解决方案) node: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.28‘ not found (node required by node)

    您可能会遇到安装在 ubuntu 操作系统上的 NodeJS 问题 当您运行 node v或pm2 list 命令时出现错误 node lib x86 64 linux gnu libc so 6 version GLIBC 2 28 no
  • 编写shell脚本实现tomcat定时重启的方法

    我的环境是 centos 7 1 在某个目录新建一个 sh 脚本文件 一般cron安装在var spool cron这里 于是我就将脚本创建在这 vim var spool cron tomcatStart sh 2 在 tomcatSta
  • 数据结构复习总结

    第一章 绪论 这里介绍了数据结构的基本概念和术语 以及算法和算法时间复杂度的分析方法 主要内容如下 1 数据结构是一门研究非数值计算程序设计中操作对象 以及这些对象之间的关系和操作的学科 2 数据结构包括两个方面的内容 数据的逻辑结构和存储
  • 挖矿kdevtmpfsi病毒处理

    通过top命令可以看到kdevtmpfsi导致CPU 700 多 导致该病毒只要是通过redis漏洞进来的 1 该病毒还有守护进程 如果光kill掉该病毒 过段时间又起来的 守护进程 kinsing 2 该病毒还有定时任务 如果光杀死kde
  • android中实现登录功能实现原理,用一个最简单的登录例子来了解Android的MVC和MVP架构的原理和实现...

    在目前的Android开发中 MVP与MVC架构还有MVVM都非常流行 三者在不同的场景下都有各自的优势和劣势 一般而言会根据具体的业务场景来选择不同的模式 所以并不是说开发一个App一定完全遵循那种模式 完全可以根据业务场景不同混合多种模
  • 书写中断服务函数的时候注意的问题:

    书写中断服务函数的时候注意的问题 1 中断服务函数名尽量用复制 不要自己写 因为只要你写错一个字母 这个函数就变成普通函数了 2 如果中断服务函数是公共入口 进入到中断服务函数后先要查询是哪种中断 3 先清中断标志 然后再做中断处理 不要把
  • python项目之弹球小游戏 2

    Hello 大家好 我们又见面了 本来我是想再拖几天再发布的 可我的良心不允许我这么做 毕竟在 python项目之弹球小游戏 1 中我们只是写了窗口的程序 还没有加入我们的主题元素呢 所以今天 我们就来加入 小球 这个关键因素 小球的图片素
  • Android 获取apk中的所有类

    直接把下面代码放到工具类调用即可 import android content Context import android os Build import android util Log import com duole games s
  • vue移动端适配(px转vw)postcss-px-to-viewport配置

    安装postcss px to viewport npm install postcss px to viewport 根目录新建postcss config js文件 postcss config js文件 module exports
  • FPGA自学之路4(按键消抖)

    先看框图 按键消抖意思就是前面和后面会有一系列信号抖动 中间才是我们要的信号 这里预设中间需要的信号 gt 20ms 用计数器计数 key in低电平就开始计数 高电平就清零 等计数器能计数到M 1 20ms 时输出一个高电平 这个按键消抖
  • Windows在线安装Qt5.15.2教程、Qt组件模块选择

    1 Qt5 15 2安装包 https download qt io 从archive qt里选 2 Qt5 15 2在线安装教程 https blog csdn net Qi 1337 article details 121249717
  • 关于:Error:java:java.lang.ExceptionInInitializerError 问题的解决

    本地运行项目的时候报上面错误 原因是jdk版本过高导致 解决方法步骤如下 idea 1 点击 File Project Structrue 2 把这两个圈起来的选项改成如下 3 保存 再次运行问题解决
  • 冒泡排序、插入排序、希尔排序、选择排序、堆排序、快速排序六大排序详解

    1 冒泡排序 思路 左右相邻的两个数互相比较 大的交换到序列后边 每次遍历排出剩余的最大的数 如下图所示 代码如下 void BubbleSort int a int n n为数组元素个数 int i 0 j 0 for i 0 i lt