【C++】十大排序算法

文章目录

  • 十大排序算法
    • 插入排序O(n^2^)
    • 冒泡排序O(n^2^)
    • 选择排序O(n^2^)
    • 希尔排序——缩小增量排序O(nlogn)
    • 快速排序O(nlogn)
    • 堆排序O(nlogn)
    • 归并排序(nlogn)
    • 计数排序O(n+k)
    • 基数排序O(n*k)
    • 桶排序O(n+k)

十大排序算法

这里是引用

排序算法的稳定性:在具有多个相同关键字的记录中,若经过排序这些记录的次序保持不变,说排序算法是稳定的。

插入排序O(n2)

  • 直接插入排序

    动画演示如图:
    在这里插入图片描述

    代码如下:

void Straight_Insertion_Sort(int a[], int length)
{
    for (int i = 1; i < length; i++)
    {
        if (a[i] < a[i - 1])
        {
            int temp = a[i];
            for (int j = i - 1; j >= 0; j--)
            {
                a[j + 1] = a[j];
                if (a[j] < temp)
                {
                    a[j + 1] = temp;
                    break;
                }
                if (j == 0 && a[j] > temp)
                {
                    a[j] = temp;
                }
            }
        }
    }
}
  • 折半插入排序

    主要分为查找和插入两个部分

    图片演示:

在这里插入图片描述

代码如下:

void Binary_Insert_Sort(int a[], int length)
{
    int low, high, mid;
    int i, j, temp;
    for (i = 1; i < length; i++)
    {
        low  = 0;
        high = i - 1;
        temp = a[i];
        while (low <= high)
        {
            mid = (low + high) / 2;
            if (temp < a[mid])
            {
                high = mid - 1;
            }
            else
            {
                low = mid + 1;
            }
        }   // while
        for (j = i - 1; j > high; j--)
        {
            a[j + 1] = a[j];
        }
        a[j + 1] = temp;
    }   // for(i)
}

冒泡排序O(n2)

思路:两两比较元素,顺序不同就交换

图解:
在这里插入图片描述

代码:

void Bubble_Sort(int a[], int length)
{
    for (int i = 0; i < length - 1; i++)
    {
        for (int j = 0; j < length - i - 1; j++)
        {
            if (a[j] > a[j + 1])
            {
                int temp = a[j];
                a[j]     = a[j + 1];
                a[j + 1] = temp;
            }
        }
    }
}

选择排序O(n2)

思路:每一次从待排序的数据元素中选择最小(最大)的一个元素作为有序的元素。如果是升序排序,则每次选择最小值就行,这样已经排好序的部分都是生序排序选择排序是不稳定的,比如说(55231这种情况,两个5的相对顺序会变)

图解:
在这里插入图片描述
代码:

void Select_Sort(int a[], int length)
{
    for (int i = 0; i < length - 1; i++)
    {
        int min_index = i;
        for (int j = i + 1; j < length; j++)
        {
            if (a[min_index] > a[j])
            {
                min_index = j;
            }
        }   // for j
        if (i != min_index)
        {
            int temp     = a[i];
            a[i]         = a[min_index];
            a[min_index] = temp;
        }
    }   // for i
}

希尔排序——缩小增量排序O(nlogn)

思路:

希尔排序又叫缩小增量排序,使得待排序列从局部有序随着增量的缩小编程全局有序。当增量为1的时候就是插入排序,增量的选择最好是531这样间隔着的。

其实这个跟选择排序一样的道理,都是不稳定的比如下图7变成9的话,就是不稳定的

图解:

在这里插入图片描述

代码:

void Shell_Sort1(int a[], int length)
{
    // 首先定义一个初始增量,一般就是数组长度除以2或者3
    int gap = length / 2;
    while (gap >= 1)
    {
        for (int i = gap; i < length; i++)
        {
            int temp = a[i];
            int j    = i;
            while (j >= gap && temp < a[j - gap])
            {
                a[j] = a[j - gap];
                j    = j - gap;
            }   // while
            a[j] = temp;
        }   // for
        gap = gap / 2;
    }   // while
}
/*****************另一种写法, 好理解****************************/
void shellsort3(int a[], int n)
{
    int i, j, gap;
    for (gap = n / 2; gap > 0; gap /= 2)
        for (i = gap; i < n; i++)
            /*j>gap之后,j前面的可以重新比较依次保证j前面间隔gap的也是有序的*/
            for (j = i - gap; j >= 0 && a[j] > a[j + gap]; j -= gap)
                Swap(a[j], a[j + gap]);
}

快速排序O(nlogn)

思路:快排的核心叫做“基准值“,小于基准值的放在左边,大于基准值的放在右边。然后依次递归。基准值的选取随机的,一般选择数组的第一个或者数组的最后一个,然后又两个指针low和high

图解:“基准值就是第一个元素”

在这里插入图片描述

1)设置两个变量I、J,排序开始的时候:I=0,J=N-1;

2)以第一个数组元素作为关键数据,赋值给 key ,即 key =A[0];

3)从J开始向前搜索,即由后开始向前搜索(J=J-1即J–),找到第一个小于 key 的值A[j],A[j]与A[i]交换;

4)从I开始向后搜索,即由前开始向后搜索(I=I+1即I++),找到第一个大于 key 的A[i],A[i]与A[j]交换;

5)重复第3、4、5步,直到 I=J; (3,4步是在程序中没找到时候j=j-1,i=i+1,直至找到为止。找到并交换的时候i, j指针位置不变。另外当i=j这过程一定正好是i+或j-完成的最后另循环结束。)

代码:

// 快速排序 需要两个函数配合
int Quick_Sort_GetKey(int a[], int low, int high)
{
    int temp = a[low];
    while (low < high)
    {
        // 首先比较队尾的元素和关键之temp,如果队尾大指针就往前移动
        while (low < high && a[high] >= temp)
        {
            high--;
        }
        // 当a[high]<temp的时候,跳出循环然后将值付给a[low],a[low]=temp
        a[low] = a[high];
        // 赋值过一次之后就立刻从队首开始比较
        while (low < high && a[low] <= temp)
        {
            low++;
        }
        a[high] = a[low];
    }                // while (low<high)
    a[low] = temp;   // 或者a[high]=temp
    return low;
}
void Quick_Sort(int a[], int low, int high)
{
    if (low < high)
    {
        int key = Quick_Sort_GetKey(a, low, high);
        Quick_Sort(a, low, key - 1);
        Quick_Sort(a, key + 1, high);
    }
}

堆排序O(nlogn)

思路:堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。堆排序分为两步:首先将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。随后第二步将其与末尾元素进行交换,此时末尾就为最大值。然后将这个堆结构映射到数组中后,就会变成升序状态了。(即升序—大根堆)

当数组元素映射成为堆时:

  1. 父结点索引:(i-1)/2
  2. +左孩子索引:2**i*+1
  3. 左孩子索引:2**i*+2

图解:

在这里插入图片描述

基本思想:

  1. 首先将待排序的数组构造成一个大根堆,此时,整个数组的最大值就是堆结构的顶端
  2. 将顶端的数与末尾的数交换,此时,末尾的数为最大值,剩余待排序数组个数为n-1
  3. 将剩余的n-1个数再构造成大根堆,再将顶端数与n-1位置的数交换,如此反复执行,便能得到有序数组

代码:

// index是第一个非叶子节点的下标(根节点)
// 递归的方式构建
void Build_Heap(int a[], int length, int index)
{
    int left    = 2 * index + 1;   // index的左子节点
    int right   = 2 * index + 2;   // index的右子节点
    int maxNode = index;           // 默认当前节点是最大值,当前节点index
    if (left < length && a[left] > a[maxNode])
    {
        maxNode = left;
    }
    if (right < length && a[right] > a[maxNode])
    {
        maxNode = right;
    }
    if (maxNode != index)
    {
        int temp   = a[maxNode];
        a[maxNode] = a[index];
        a[index]   = temp;
        Build_Heap(a, length, maxNode);
    }
}
void Heap_Sort(int a[], int length)
{
    // 构建大根堆(从最后一个非叶子节点向上)
    // 注意,最后一个非叶子节点为(length / 2) - 1
    for (int i = (length / 2) - 1; i >= 0; i--)
    {
        Build_Heap(a, length, i);
    }
    for (int i = length - 1; i >= 1; i--)
    {
        // 交换刚建好的大顶堆的堆顶和堆末尾节点的元素值,
        int temp = a[i];
        a[i]     = a[0];
        a[0]     = temp;
        // 交换过得值不变,剩下的重新排序成大顶堆
        Build_Heap(a, i, 0);
    }
}

归并排序(nlogn)

思路:分治思想,将若干个已经排好序的子序合成有序的序列。

图解:

在这里插入图片描述

代码:

// 分治思想,先逐步分解成最小(递归)再合并
// 归并
void Merge(int a[], int low, int mid, int high)
{
    int  i    = low;
    int  j    = mid + 1;
    int  k    = 0;
    int* temp = new int[high - low + 1];
    while (i <= mid && j <= high)
    {
        if (a[i] <= a[j])
        {
            temp[k++] = a[i++];
        }
        else
        {
            temp[k++] = a[j++];
        }
    }   // while (i<mid&&j<=high)
    while (i <= mid)
    {
        temp[k++] = a[i++];
    }
    while (j <= high)
    {
        temp[k++] = a[j++];
    }
    for (i = low, k = 0; i <= high; i++, k++)
    {
        a[i] = temp[k];
    }
    delete[] temp;
}
// 递归分开
void Merge_Sort(int a[], int low, int high)
{
    if (low < high)
    {
        int mid = (low + high) / 2;
        Merge_Sort(a, low, mid);
        Merge_Sort(a, mid + 1, high);
        cout << "mid=" << mid << " " << a[mid] << endl;
        cout << "low=" << low << " " << a[low] << endl;
        cout << "high=" << high << " " << a[high] << endl;
        cout << endl;
        // 递归之后再合并
        Merge(a, low, mid, high);
    }
}

代码看不懂没关系,参考链接

计数排序O(n+k)

思路:

将待排序的数据存放到额外开辟的空间中。首先找出元素的最大最小值,然后统计每个元素i出现的次数,然后放入数组i中,数组中存放的是值为i的元素出现的个数。额外数组中第i个元素是待排序数组中值为i的元素的个数。因为要求输入的数有确定范围,同时只能对整数进行排序,有场景限制。

图解:

计数排序

代码:

void Count_Sort(int a[], int length)
{
    // 得到待排序的最大值
    int max = a[0];
    int i   = 0;
    while (i < length - 1)
    {
        max = (a[i] > a[i + 1]) ? a[i] : a[i + 1];
        i++;
    }
    int* countArray = new int[max + 1] { 0 };
    int* temp       = new int[length];

    for (int i = 0; i < length; i++)
    {
        countArray[a[i]]++;
    }
    //!!!这一步的思想特别重要,在非比较排序中
    for (int i = 1; i < max + 1; i++)
    {
        countArray[i] += countArray[i - 1];
    }
    // 反向遍历
    for (int i = length - 1; i >= 0; i--)
    {
        temp[countArray[a[i]] - 1] = a[i];
        countArray[a[i]]--;
    }
    for (int i = 0; i < length; i++)
    {
        a[i] = temp[i];
    }
    delete[] countArray;
    delete[] temp;
}

基数排序O(n*k)

思路: 基数也就表明桶的个数是定死的,就是10个。基数排序的思想是,从个位依次开始排序,首先按照个位的大小排序,将改变的序列按照十位开始排序,然后一次往后……

图解:

在这里插入图片描述

代码:

int Get_Max_Digits(int a[], int length)
{
    int max = a[0];
    int i   = 0;
    while (i < length - 1)
    {
        max = (a[i] > a[i + 1]) ? a[i] : a[i + 1];
        i++;
    }
    int b = 0;   // 最大值的位数
    while (max > 0)
    {
        max = max / 10;
        b++;
    }
    return b;
}
// 切记!桶子只能是十个,是定死的
void Radix_Sort(int b[], int length)
{
    int  d     = Get_Max_Digits(b, length);   // 得到最大值的位数
    int* temp  = new int[length];             // 开辟一个和原数组相同的临时数组
    // 根据最大值的位数进行排序次数循环
    int  radix = 1;
    for (int i = 0; i < d; i++)
    {
        // 每次把数据装入桶子前先清空count
        int count[10] = { 0 };   // 计数器 每次循环都清零
        for (int j = 0; j < length; j++)
        {
            // 统计尾数为0-9的个数,一次是个十百千....位
            int tail_number = (b[j] / radix) % 10;
            count[tail_number]++;   // 每个桶子里面的个数
        }
        // 桶中的每一个数的位置一次分配到temp数组中,先找到位置
        for (int j = 1; j < 10; j++)
        {
            count[j] += count[j - 1];
        }
        // 分配到temp中排序后的位置
        for (int j = length - 1; j >= 0; j--)
        {
            int tail_number              = (b[j] / radix) % 10;
            temp[count[tail_number] - 1] = b[j];
            count[tail_number]--;
        }
        // 赋值
        for (int j = 0; j < length; j++)
        {
            b[j] = temp[j];
        }
        radix *= 10;
    }   // for(int i)
    delete[] temp;
}

桶排序O(n+k)

**思路:**基数排序和计数排序都是桶思想的应用。桶排序是最基本的

​ 首先要得到整个待排序数组的最大值和最小值,然后设置桶的个数k,这样可以得到每个桶可以放的数的区间。

​ 然后遍历待排序的数组,将相关区间内的数放到对应的桶中,这样桶内在排序,就使得整个序列相对有序

图解:

在这里插入图片描述

代码:

void bucketSort(int arr[], int len)
{
    // 确定最大值和最小值
    int max = INT_MIN;
    int min = INT_MAX;
    for (int i = 0; i < len; i++)
    {
        if (arr[i] > max)
            max = arr[i];
        if (arr[i] < min)
            min = arr[i];
    }

    // 生成桶数组
    // 设置最小的值为索引0,每个桶间隔为1
    int bucketLen = max - min + 1;
    // 初始化桶
    int bucket[bucketLen];
    for (int i = 0; i < bucketLen; i++)
        bucket[i] = 0;

    // 放入桶中
    int index = 0;
    for (int i = 0; i < len; i++)
    {
        index          = arr[i] - min;
        bucket[index] += 1;
    }

    // 替换原序列
    int start = 0;
    for (int i = 0; i < bucketLen; i++)
    {
        for (int j = start; j < start + bucket[i]; j++)
        {
            arr[j] = min + i;
        }
        start += bucket[i];
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/306893.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Jmeter压缩包安装

JMeter安装及配置-Mac 本章要点 前置条件命令行安装压缩包安装 在Mac上安装对应的JMeter工具有两种方式&#xff1a;一种直接借助终端命令行brew进行安装&#xff1b;另外一种和Window电脑一样去JMeter官网下载压缩包安装。 JMeter不需要安装&#xff0c;但是JMeter作为java应用…

基于Springboot生活物资分配系统-计算机毕设 附源码 30174

Springboot生活物资分配系统 目 录 摘要 1 绪论 1.1目的与意义 1.2研究内容 1.3系统开发技术的特色 1.4springboot框架 2 1.5论文结构与章节安排 3 2 生活物资分配系统分析 4 2.1 可行性分析 4 2.2 系统流程分析 4 2.2.1数据增加流程 5 2.3.2数据修改流程 5 2.3.3数据删除…

第9章 正则表达式

学习目标 熟悉正则表达式,能够说出正则表达式的概念和作用 掌握正则表达式的创建,能够使用两种方式创建正则表达式 掌握正则表达式的使用,能够使用正则表达式进行字符串匹配 掌握正则表达式中元字符的使用,能够根据需求选择合适的元字符 掌握正则表达式中模式修饰符的使用,…

python_数据可视化_pandas_导入excel数据

目录 1.1导入库 1.2读取excel文件 1.3读取excel&#xff0c;指定sheet2工作表 1.4指定行索引 1.5指定列索引 1.6指定导入列 案例速览&#xff1a; 1.1导入库 import pandas as pd 1.2读取excel文件 pd.read_excel(文件路径) data pd.read_excel(D:/desktop/TestExcel…

Mysql判断一个表中的数据是否在另一个表存在

方式一&#xff1a; 判断A表中有多少条数据在B表中【存在】,并且显示这些数据–EXISTS语句 select A.ID, A.NAME from 表A where EXISTS(select * from 表B where A.IDB.ID) 判断A表中有多少条数据在B表中【不存在】&#xff0c;并且显示这些数据–NOT EXISTS语句 select …

嵌入式培训机构四个月实训课程笔记(完整版)-Linux系统编程第四天-Linux管道练习题(物联技术666)

更多配套资料CSDN地址:点赞+关注,功德无量。更多配套资料,欢迎私信。 物联技术666_嵌入式C语言开发,嵌入式硬件,嵌入式培训笔记-CSDN博客物联技术666擅长嵌入式C语言开发,嵌入式硬件,嵌入式培训笔记,等方面的知识,物联技术666关注机器学习,arm开发,物联网,嵌入式硬件,单片机…

针对远程40G网络的DWDM解决方案

目前&#xff0c;用户和企业积累的数据量非常巨大&#xff0c;并在不断增长。因此&#xff0c;存储和访问这些数据也变得更加苛刻&#xff0c;需要更高的数据容量和更长距离的数据传输。我们的一个客户正在考虑为现有的40G网络添加DWDM系统&#xff0c;作为一种更严肃的未来技术…

【论文阅读笔记】Stable View Synthesis 和 Enhanced Stable View Synthesis

目录 Stable View Synthesis摘要引言 Enhanced Stable View Synthesis 从Mip-NeRF360的对比实验中找到的两篇文献&#xff0c;使用了卷积神经网络进行渲染和新视角合成&#xff0c;特此记录一下 ToDo Stable View Synthesis paper&#xff1a;https://readpaper.com/pdf-ann…

SLF4J Spring Boot日志框架

JAVA日志框架 JAVA有好多优秀的日志框架&#xff0c;比如log4j、log4j2、logback、JUL&#xff08;java.util.logging&#xff09;、JCL&#xff08;JAVA Common Logging&#xff09;等等&#xff0c;logback是后起之秀&#xff0c;是Spring Boot默认日志框架。 今天文章的目…

Cost S-curve

成本S曲线 Cost S-curve 每个月成本预算&#xff0c;柱形图 每个月成本累积&#xff08;合计&#xff09;&#xff1a;成本S曲线&#xff0c;折线图&#xff0c;但是肯定都是上升的 echarts图表&#xff1a;

芯课堂 | 一种温度修调方法

一种温度修调方法 本次介绍一种温度修调方法&#xff0c;所述温度修调方法包括获取正温度系数的电流和负温度系数的电流&#xff1b;对获取到的正温度系数的电流和负温度系统的电流进行权重处理&#xff0c;得到补偿电流&#xff1b;基于预设温度特性模型&#xff0c;将补偿电流…

SD-WAN组网:实现跨境连接的智能选择

在数字化时代&#xff0c;企业面临着越来越多的挑战&#xff0c;其中之一是构建高效、安全、可靠的跨境网络连接。SD-WAN&#xff08;Software-Defined Wide Area Network&#xff09;作为一种创新的网络技术&#xff0c;通过应用软件定义的方式&#xff0c;为企业提供了一种智…

深入理解 Hadoop (四)HDFS源码剖析

HDFS 集群启动脚本 start-dfs.sh 分析 启动 HDFS 集群总共会涉及到的角色会有 namenode, datanode, zkfc, journalnode, secondaryName 共五种角色。 JournalNode 核心工作和启动流程源码剖析 // 启动 JournalNode 的核心业务方法 public void start() throws IOException …

软件测试|MySQL ORDER BY详解:排序查询的利器

简介 在数据库中&#xff0c;我们经常需要对查询结果进行排序&#xff0c;以便更好地展示数据或满足特定的业务需求。MySQL提供了ORDER BY子句&#xff0c;使我们能够轻松地对查询结果进行排序。本文将详细介绍MySQL ORDER BY的用法和示例&#xff0c;帮助大家更好地理解和应用…

汇聚数据库创新力量,打造千行万业数据基石

12月28日&#xff0c;以“汇聚数据库创新力量&#xff0c;打造千行万业数据基石”为主题的openGauss Summit 2023在北京举行。会上&#xff0c;openGauss社区理事会理事长胡正策发表《汇聚数据库创新力量&#xff0c;打造千行万业数据基石》主题演讲&#xff0c;他表示&#xf…

Ribbon学习思维导图

参考资料 1、OpenFeign与Ribbon源码分析总结与面试题 2、万字剖析OpenFeign整合Ribbon实现负载均衡的原理 3、扒一扒Nacos、OpenFeign、Ribbon、loadbalancer组件协调工作的原理 4、OpenFeign原来是这么基于Ribbon来实现负载均衡的

组织架构图如何制作?制作方法其实很简单

组织架构图如何制作&#xff1f;你是否曾经遇到过这样的场景&#xff1a;在向领导汇报工作时&#xff0c;需要展示公司的组织架构&#xff0c;却不知道如何清晰明了地呈现&#xff1f;或者在写工作报告时&#xff0c;需要描述各个部门之间的关系&#xff0c;却苦于没有合适的图…

激发无限潜力,HUAWEI WATCH GT 4 助你开启健康跑道

去运动&#xff0c;去探索&#xff01;HUAWEI WATCH GT 4 提供科学的运动规划和减脂塑形功能&#xff0c;激励你保持吃动平衡&#xff0c;达成健身目标。此外&#xff0c;全面的健康管理、便捷的 NFC 功能&#xff0c;助你开启全新智能生活&#xff0c;尽享健康精彩人生&#x…

[足式机器人]Part3 机构运动学与动力学分析与建模 Ch00-2(1) 质量刚体的在坐标系下运动

本文仅供学习使用&#xff0c;总结很多本现有讲述运动学或动力学书籍后的总结&#xff0c;从矢量的角度进行分析&#xff0c;方法比较传统&#xff0c;但更易理解&#xff0c;并且现有的看似抽象方法&#xff0c;两者本质上并无不同。 2024年底本人学位论文发表后方可摘抄 若有…

Java EE 博客系统(Servlet版)

文章目录 1. 基本情况2. 准备工作3. 博客列表页4. 博客详情页5. 实现登录6. 强制要求登录7. 显示用户信息8. 退出登录9. 发布博客10. 如果程序出现问题怎么办&#xff1f; 1. 基本情况 这里的博客系统主要是四个界面 博客列表页 显示出当前网站上都有哪些博客博客详情页 点击…