排序算法总结与C++实现(冒泡、简单选择、直接插入、堆、归并、快速)

C++十种排序方法(快速排序、冒泡排序等等) C++十种排序方法(快速排序、冒泡排序等等) 一、冒泡排序 1、概念及思路:冒泡排序顾名思义就是大的数沉下去,小的数浮上来,就跟气泡在水底浮上来一样;基本的思路很简单,就是相邻的两个数相比较,如果前面那个数比后面那个数大,则换位置,否则不需要换。以此循环下去(这里指的是从小到大排序,当然也可以从大到小) 2、代码演示: #include<iostream> using namespace std; int main() { int i; int arr[10] = { 1,5,2,3,6 阅读详情

如有错误,请及时指出!谢谢!

几种排序算法时间复杂度和空间复杂度:

这里写图片描述

1.冒泡排序
如果是从小到大排序,从最后一个元素开始,依次与前一个元素比较,比前一个元素小则交换。这样小的元素就浮到上面了。第二轮再从最后一个元素开始。
C++实现如下:(优化版,引入了flag)

void bubbleSort(vector<int> &A) 
{  
    bool flag=1;
    for (int j = 0; j < A.size() && flag; j++) 
    {
        flag=0;  
        for (int i = A.size() - 1; i > j; i--)
        {
            //如果一直没有数据交换,则说明已经排好了,flag=0,在下一个for不执行直接结束
            //这样就不用再进行后面的for循环了
            if (A[i] < A[i - 1])
            {
                swap(A[i], A[i - 1]);
                flag=1;
            }
        }  
}  

时间复杂度:最好O(n),最坏O(n^2),平均O(n^2)
冒泡排序状态变化举个栗子:
待排:37462
第一轮:37426、37246、32746、23746
第二轮:23746、23476
第三轮:23467,排好了……

2.简单选择排序
第一轮:j=0,先设第一个元素下标为min,将第一个元素(下标为0)与第二个(下标为1)比较,将min设置为较小元素的下标;再讲min与第三个比较,将将min设置为较小元素的下标。一轮比较之后,获得第一个小元素的下标min,将j=0位置元素与min位置元素交换。
第二轮:从第二个元素开始,获得第二小的元素
……
C++实现如下:

void selectionSort(vector<int> &A) 
{  
    for (int j = 0;j < A.size();j++) 
    {  
        int min = j;  
        for (int i = j + 1;i < A.size();i++) 
        {  
            if (A[i] < A[min])  
                min = i;  
        }  
        if(j!=min) swap(A[j],A[min]);  
    }  
}  

时间复杂度:O(n^2)
简单选择排序状态变化举个栗子:
序号:01234
待排:37462
第一轮:初始化最小元素的下标min=0,经过比较min=4,即第4个元素2,交换第0个元素和第4个元素:27463
第二轮:初始化最小元素的下标min=1,经过比较min=4,即第4个元素3,交换第1个元素和第4个元素:23467
第三轮:初始化最小元素的下标min=2,经过比较min=2,不改变……实际上已经排好了……

3.直接插入排序
C++实现如下:

void insertionSort(vector<int> &A) 
{  
    for (int j = 1;j < A.size();j++) 
    {  
        int key = A[j];  
        int i=j-1;  
        while(i>=0&&key < A[i])
        {  
            A[i + 1] = A[i];  //向后移一位
            i--;  
        }  
        A[i + 1] = key;  
    }  
} 

最好O(n),最坏O(n^2),平均O(n^2)
将小的元素不断往前移动,把比它大的元素不断往后移动。
直接插入排序状态变化举个栗子:
序号:01234
待排:53462
第一轮:j=1,key=A[1]=3,i=0 , key=3<A[0]=5 , A[1]=5,i=-1 ,跳出while,A[0]=3→35462
第二轮:j=2 , key=A[2]=4 , i=1 , key=4<A[1]=5, A[2]=5,i=0,跳出while,A[1]=4→34562
………………

4.堆排序
一些基本概念和定义:
大顶堆:完全二叉树,每个结点的值都大于其左右孩子的值;即A[i]≥A[2i],A[i]≥A[2i+1]
小顶堆:完全二叉树,每个结点的值都小于其左右孩子的值;即A[i]≤A[2i],A[i]≤A[2i+1]
完全二叉树,如果用一个数组存储(下标从0开始)。若下标为i,则双亲下标是【((i-1)/2)向下取整】;同理,下标为i的结点,它的左右孩子下标为2i+1和2i+2。

步骤:
(1)构造大顶堆
(2)堆顶移走(其实是与末尾元素交换)
(3)重复(1)

堆排序主函数:

基本步骤:
(1)从最后一个非叶子节点开始,对每个非叶子结点进行堆排序
(2)将堆顶与最后一个元素交换
(3)除去最后一个元素,重新构建大顶堆
void HeapSort(vector<int>& A)
 {  
    int heap_size = A.size() - 1;  
    for (int i = (heap_size-1) / 2;i >= 0;i--)  
    //因为所有叶子结点已经是合法的大顶堆了,所以对所有非叶子结点构造大顶堆
    {  
        maxHeapify(A, heap_size,i);         //从下标为i到heap_size元素构造大顶堆
    }  
    while (heap_size >= 1)
     {  
        swap(A[heap_size], A[0]);    //交换堆顶与末尾元素
        heap_size--;  
        maxHeapify(A, heap_size, 0);  
    }  
}  

下面是构造大顶堆函数maxHeapify()的实现(递归和非递归):

//递归
//从下标为i到heap_size元素构造大顶堆
void maxHeapify(vector<int>& A, int heap_size, int i) 
{  
    int largest = i * 2 + 1;  
    if (largest > heap_size) return;  
    if (largest<heap_size&&A[largest + 1]>A[largest]) 
    {  
        largest++;  //选出较大的孩子用于下一步与父节点交换值
    }  
    if (A[i]<A[largest]) 
    {   //如果自己的孩子比自己大则交换两者的值    
        swap(A[i], A[largest]); 
        maxHeapify(A, heap_size, largest);  
    }  
}  
//非递归
void maxHeapify(vector<int>& A, int heap_size, int i) 
{  
    int largest;  
    while (i * 2 < heap_size)
     {  
        largest = i * 2 + 1;  
        if (largest<heap_size&&A[largest + 1]>A[largest]) 
        {  
            largest++;  
        }  
        if (A[i]<A[largest]) 
        {    //如果自己的孩子比自己大则交换两者的值    
            swap(A[i], A[largest]);  
        }  
        else break; //如果不比自己大则不交换    
        i = largest;  
    }  
}  

由于每次重新恢复堆的时间复杂度为O(logN),共N - 1次重新恢复堆操作,再加上前面建立堆时N / 2次向下调整,每次调整时间复杂度也为O(logN)。

5.两路归并排序
两两组合,排序;归并,排序……

//递归的方法
void MergeSort(vector<int>& A)
{
    MSort(A,0,A.size()-1);
}
void MSort(vector<int>& A,int low,int high)
{
    if(low<high)
    {
        int mid=(low+high)/2;
        MSort(A,low,mid);
        Msort(A,mid+1,high);
        Merge(A,low,mid,high);   //排好序顺便合并
    }
}
void Merge(vector<int>&A, int p, int q, int r)  
{  
    vector<int> L(A.begin() + p, A.begin() + q+1);   //A[p......q]  
    vector<int> R(A.begin() + q+1, A.begin() + r+1); //A[q+1......r]  
    L.push_back(INT_MAX);  
    R.push_back(INT_MAX);  
    for (int i = 0, j = 0, k = p; k <= r; k++)  
    {  
        if (L[i] <= R[j]) 
            A[k] = L[i++];  
        else A[k] = R[j++];    //从小到大排序
    }  
}  
// 非递归
// merge_sort: 非递归实现 --迭代  
// 非递归思想: 将数组中的相邻元素两两配对。用merge函数将他们排序,  
// 构成n/2组长度为2的排序好的子数组段,然后再将他们排序成长度为4的子数组段,  
// 如此继续下去,直至整个数组排好序。    
// merge_sort(): 非递归实现-自底向上  
// 将原数组划分为left[min...max] 和 right[min...max]两部分  
void merge_sort(vector<int> &list)  
{  
    int length = list.size();  
    vector<int> temp(length, 0);  
    int i, left_min, left_max, right_min, right_max, next;  
    for (i = 1; i < length; i *= 2) // i为步长,1,2,4,8……,两两合并
    {  
        for (left_min = 0; left_min < length - i; left_min = right_max)  
        {  
            right_min = left_max = left_min + i;  
            right_max = left_max + i;  
            if (right_max > length)  
                right_max = length;  
            next = 0;  
            while (left_min < left_max && right_min < right_max)  
                temp[next++] = list[left_min] > list[right_min] ? list[right_min++] : list[left_min++];  

            while (left_min < left_max)  
                list[--right_min] = list[--left_max];  

            while (next > 0)  
                list[--right_min] = temp[--next];  
        }  
    }  
}  

6.快速排序
通过一趟排序将待排记录分割成独立的两部分,一部分关键字均比另一部分关键字小;再分别对这两部分进行相同的操作。

void QuickSort(vector<int>& A)
{
    QSort(A,0,A.size()-1);
}
//递归
void QSort(vector<int>& A, int p, int r)  
{  
    if (p<r)  
    {  
        int q = partition(A,p,r);  
        QSort(A, p, q-1);  
        QSort(A, q+1, r);  
    }  
}  

其中partition的实现如下:

int partition(vector<int>& A, int low, int high) 
{  
    int key = A[low];
    while(low<high)
    {
        while(low<high && A[high]>=key)
        {
            high--;
        }
        swap(A[low],A[high]);
        while(low<high && A[low]<=key)
        {
            low++;
        }
        swap(A[low],A[high]);
    }  
    return low;
}  
//非递归的方法
//数据规模很大时,递归的算法很容易导致栈溢出,改为非递归,模拟栈操作
//最大长度为n,每次压栈时先压长度较大的,此时栈深度为logn。  
template<typename Comparable>  
void quicksort2(vector<Comparable> &vec,int low,int high){  
    stack<int> st;  
    if(low<high){  
        int mid=partition(vec,low,high);  
        if(low<mid-1){  
            st.push(low);  
            st.push(mid-1);  
        }  
        if(mid+1<high){  
            st.push(mid+1);  
            st.push(high);  
        }  
        //其实就是用栈保存每一个待排序子串的首尾元素下标,下一次while循环时取出这个范围
        //对这段子序列进行partition操作  
        while(!st.empty()){  
            int q=st.top();  
            st.pop();  
            int p=st.top();  
            st.pop();  
            mid=partition(vec,p,q);  
            if(p<mid-1){  
                st.push(p);  
                st.push(mid-1);  
            }  
            if(mid+1<q){  
                st.push(mid+1);  
                st.push(q);  
            }         
        }  
    }  
}  

快速排序状态变化如下:
序号:012345678
待排:519374862
第一轮:取key=5,219374865,215374869,214375869,214357869,以5为中心分成两半:2143和7869分别再进行快排。

直接插入排序、冒泡排序、快排、简单选择排序、堆排序、归并排序 C++代码实现 插入类排序 直接插入排序 每趟将一个待排序的关键字按照其值的大小插入到已经排好的部分有序序列的适当位置上,直到所有待排关键字都被插入到有序序列中为止。 void insertssort(vector<int>& R){ for(int i = 1 ;i <R.size();i++){ int j = i-1; int temp = R[i]; while (j<i &&j>=0 &&am 阅读详情

相关推荐

三种排序算法(直接插入、冒泡、快速)的C++实现

三种排序算法(直接插入、冒泡、快速)的C++实现。有讲解

排序:选择排序、交换排序和归并排序

选择排序 选择排序的基本思想是:每次从待排序的文件中选择出排序码最小的记录将该记录放于已排序文件的最后一个位置,直到已排序文件记录个数等于初始待排序文件的记录个数为止。 直接选择排序(不稳定排序) 树型选择排序 堆排序(不稳定排序) 直接选择排序 直接选择排序是一种简单的方法,首先从所有n个待排序记录中选择排序码最小的记录举该记录,将该记录与第1个记录交换,再从剩下的n-1个记录中选出排序码最小的记录和第 2个记录交换。重复这样的操作直到剩下两个记录时,再从中选出排序码最小的记录和第n-1个记录交换.

Sylvia_Wu51的博客 2940

直接插入排序/快速排序/选择排序/冒泡排序(详细实现算法和性能比较)

数据结构---直接插入排序/快速排序/选择排序/冒泡排序(详细实现算法和性能比较)

数据结构-各种排序算法(插入、交换、选择、归并)

数据结构的各个排序算法的代码实现和时间复杂度(插入、交换、选择、归并)

qq_59614938的博客 769

直接排序法,折半插入法,希尔排序法,快速排序法(c语言实现)

直接排序法,折半插入法,希尔排序法,快速排序法(c语言实现),适合初学数据结构的同学。全部程序都在VC++6.0调试通过。

排序算法.doc 详细讲解了插入排序、交换排序、选择排序、归并排序等排序算法的原理以及实现代码

从排序的基本概念讲起,详细讲解了插入排序、交换排序、选择排序、归并排序等排序算法的原理以及实现代码

【一起学数据结构与算法】几种常见的排序(插入排序、选择排序、交换排序、归并排序)

排序是计算机内经常进行的一种操作,其目的是将一组“无序”的记录序列调整为“有序”的记录序列。分内部排序和外部排序,若整个排序过程不需要访问外存便能完成,则称此类排序问题为内部排序。反之,若参加排序的记录数量很大,整个序列的排序过程不可能在内存中完成,则称此类排序问题为外部排序。内部排序的过程是一个逐步扩大记录的有序序列长度的过程。–(来源百度)将杂乱无章的数据元素,通过一定的方法按关键字顺序排列的过程叫做排序。

摸鱼胖嘟嘟的博客 3795

直接插入、折半插入、冒泡、快速、简单选择等排序方法 用c语言实现

直接插入、折半插入、冒泡、快速、简单选择等排序方法 用c语言实现 代码运行正常 不会有任何的问题

直接插入排序算法——C/C++

直接插入排序 1、插入排序(Insertion-Sort)的基本思想: 每次将一个待排序的数据按照大小插入到前面已经排好序的适当位置,直到全部数据插入完成为止。 2、插入排序的步骤: 2.1、建立一个哨兵(即临时变量),把要插入的数据赋给它。 2.2、插入数据从后面开始比较,如果大于前面的就记录下标,并将数据后移,直到插入数据碰到比它小的。 2.3、将临时变量赋值给当前记录下标。 2.4、for循...

有人_295的博客 6万+

Gem5模拟器,详解官网教程Event-driven programming(五)

Gem5模拟器,详解官网教程Event-driven programming、时间调度、如何自定义SimObject

qq_46675545的博客 2038

图像评价之计算PSNR、SSIM、MSE、LPIPS和NIQE评价指标

如果代码对你的研究有所帮助,请为该仓库点上小星星。

书山有路,学海无涯! 2643

几种排序算法的C++实现

一、复杂度比较 类别 排序方法 时间复杂度 空间复杂度 稳定性 平均情况 最好情况 最坏情况 插入 排序 直接插入 稳定 shell排序 不稳定 选择 排序 简单选择 不稳...

Brett 388

鸿蒙进阶——HDI及IDL硬件接口IPC框架小结

HDI(Hardware Device Interface):OpenHarmony硬件设备接口,定义系统中跨进程通信的接口,实现服务间的跨进程通信

最美不过,心中有梦,身旁有你! 3903

C/C++最全排序算法汇总,原理+代码

排序是计算机内经常进行的一种操作,其目的是将一组“无序”的记录序列调整为“有序”的记录序列。分内部排序和外部排序。若整个排序过程不需要访问外存便能完成,则称此类排序问题为内部排序。反之,若参加排序的记录数量很大,整个序列的排序过程不可能在内存中完成,则称此类排序问题为外部排序。内部排序的过程是一个逐步扩大记录的有序序列长度的过程。将杂乱无章的数据元素,通过一定的方法按关键字顺序排列的过程叫做排序。假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,

m0_68557563的博客 1323

告别龟速与断连:Arduino IDE下ESP32及ESP32-CAM一站式环境部署指南

本文提供Arduino IDE下ESP32及ESP32-CAM一站式环境部署指南,解决下载速度慢、断连等常见问题。通过国内镜像源加速、详细步骤讲解和ESP32-CAM专属配置技巧,帮助开发者快速完成环境搭建,避免常见陷阱,提升开发效率。

weixin_30576827的博客 771

阅文集团大数据面试题及参考答案

在 Flink 中,watermark 是一种用于处理乱序事件时间的机制。实现接口:通常需要实现 AssignerWithPeriodicWatermarks 或 AssignerWithPunctuatedWatermarks 接口。前者会周期性地生成 watermark,后者则是基于某些特定事件来生成 watermark ,比如接收到某个特定值的消息时。定义位置:可以在数据源处或者在流处理的中间操作中定义 watermark。在数据源定义时,能更精准地根据数据的产生特性设置 watermark;

大模型大数据攻城狮的专栏 1088

【C++】排序算法

本文介绍了常见的排序算法分类及其实现方法。排序算法主要分为插入类(直接插入、折半插入、希尔排序)、交换类(冒泡、快速排序)、选择类(简单选择、堆排序)、归并类和分配类(基数排序)。详细分析了插入排序中的直接插入和折半插入算法,包括算法原理、时间复杂度分析、稳定性特点及代码实现。直接插入排序通过逐个比较实现有序序列扩展,时间复杂度为O(n²);折半插入排序利用二分查找优化比较过程,但移动次数不变。文章还提供了相关算法的图示说明、性能比较和代码示例,为学习排序算法提供了系统的参考资料。

-笔记- 138

bash: huggingface-cli: command not found... 解决方案

本文主要介绍了bash: huggingface-cli: command not found… 解决方案,希望能对使用大模型的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 5万+

C++ | 9大排序学习总结

本文是作者为准备C++版《数据结构》课程而整理的排序算法总结,共涵盖九大经典排序算法。文章分为插入类(直接插入、折半插入、希尔排序)、交换类(冒泡、快速排序)、选择类(简单选择、堆排序)、归并类和基数类五大类别。本文可作为数据结构学习的实用参考资料。

2502_92658961的博客 175

​非线性分析-增加位移量可能出现下面错误。虽然求解无法在所有时间点完成,但在某些点上仍能够求解部分结果。请参阅“帮助系统”中的故障排除,以了解更多信息详情。由于受约束,规划求解引擎无法收敛

基于收敛状态拆分载荷步‌:在已收敛的载荷步基础上,将未收敛的关键区域拆分为更细的子步,比如在载荷突变点前设置5~10个子步,逐步加载。替换冲突约束为弱约束‌:若存在约束冲突,将刚性约束替换为弱弹簧约束(刚度设为1e-6~1e-4),既限制刚体位移,又不影响结构的变形自由度,命令流:SPRING, NODE, K, 1e-6。部分区域约束完整,但存在未被约束的刚体自由度,或约束类型与大变形/接触逻辑冲突,比如某部件的位移约束在初始阶段有效,但大变形后约束位置脱离实际受力点,导致求解器在该阶段无法收敛。

qq_15963745的博客 144

Agentic RL: 大模型后训练 SFT、PPO和GRPO

本文介绍了从LLM训练到Agentic RL的发展过程。传统LLM训练包括预训练和后训练两个阶段,其中后训练通过监督微调、奖励建模和强化学习等技术优化模型表现。针对智能体在复杂任务中的不足,提出了Agentic RL新范式,将LLM嵌入强化学习框架,通过多步交互、工具使用和环境反馈来优化长期目标。相比传统单轮对话优化(PBRFT),Agentic RL具有状态包含历史上下文、行动类型多样、动态状态转移等特点,更适合解决需要多步推理和规划的任务。这种新方法为开发更强大的智能体系统提供了可能。

Cachel Wood的博客 698

十大排序算法笔记(含完整代码实现)

1.排序的思路2.代码3.就地性 :只在数组(待排序的位置)内部排序,不涉及到多余的空间稳定性:针对重复数据而言4 5 2* 3 2----->2* 2 3 4 5 重复数据的相对位置没有发生变化--->稳定的内部排序 时间算法度给定n个数据,要求把这n个数据重新排列成升序输入n在输入这n个数据升序输出这n个数据乱序区 --→有序区-----

Nanamisa__的博客 242

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

一、十大排序算法

常见的排序算法

Ray Home 263

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

各内部排序算法时间复杂度比较

#include <stdio.h> #include <stdlib.h> #include <conio.h> #include <time.h> void get_data(int r[],int n) {int i; srand( (unsigned)time( NULL ) ); for(i=1;i<=n;i++)r[i]=rand()%100; } void reverse_data(int r[],int n) {int i; f...

weixin_56508665的博客 291

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

十种排序算法总结(冒泡、插入、选择、希尔、归并、堆、快速,计数,桶,基数)

首先声明一下,本文只对七种排序算法做简单总结,并参照一些资料给出自己的代码实现,并没有对某种算法理论讲解,更详细的 了解可以参考以下资料(本人参考): 1、《data structure and algorithm analysis in c 》 2、《大话数据结构》 3、http://blog.youkuaiyun.com/morewindows/article/details/7961256

Meditation 7万+

C++排序算法总结(冒泡、插入、选择、希尔、归并、快速、堆)

C++排序算法总结(冒泡、插入、选择、希尔、归并、快速、堆)排序算法是面试中经常遇到以及面试官常考的算法基本功,掌握排序算法对于找工作而言很重要的一个标准。 [转载注明出处] (http://my.youkuaiyun.com/my/mycsdn)排序算法总结: 冒泡排序 插入排序 选择排序 希尔排序 归并排序 快速排序 堆排序 目录C排序算法总结冒泡插入选择希尔归并快速堆目录 冒泡排序 插入排序 选择排序

yuebai008的博客 3725
上一篇: 随机梯度下降法(Stochastic Gradient Descent)和批量梯度下降法(Batch Gradient Descent )总结
下一篇: Fisher线性判别分析(Linear Discriminant Analysis,LDA)
code_caq
博客等级 码龄11年 112粉丝 58原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值