常见的五种排序

news2024/11/24 19:06:02

🐶博主主页:@ᰔᩚ. 一怀明月ꦿ 

❤️‍🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C++

🔥座右铭:“不要等到什么都没有了,才下定决心去做”

🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀

目录

冒泡排序 

选择排序 

插入排序

堆排序

希尔排序

五种排序的效率比较 


冒泡排序 

从左到右,相邻元素进行比较。每次比较之后,就会找到待排数据中最大的一个或者最小的一个,这个数就会从待排数据的最右边冒出来。
以从升序为例,第一次比较后,所有数中最大的那个数就会浮到最右边;第二轮比较后,所有数中第二大的那个数就会浮到倒数第二个位置……就这样一轮一轮地比较,最后实现从小到大排序。

 这里所有排序都以升序为例

//升序
#include<stdio.h>
void Print(int arr[],int len)
{
    for(int i=0;i<len;i++)
    {
        printf("%d ",arr[i]);
    }
    printf("\n");
}
void Buble_sort(int arr[],int len)
{
    for(int i=0;i<len-1;i++)
    {
        for(int j=0;j<len-i-1;j++)
        {
            if(arr[j]>arr[j+1])
            {
                int temp=arr[j];
                arr[j]=arr[j+1];
                arr[j+1]=temp;
            }
        }
    }
    Print(arr,len);
}
int main()
{
    int arr[]={9,8,7,6,0,5,4,3,2,1};
    int len=sizeof(arr)/sizeof(*arr);
    Buble_sort(arr,len);
    return 0;
}

结果:0 1 2 3 4 5 6 7 8 9

选择排序 

 选择排序(Choose sort)是一种简单直观的排序算法。它的工作原理是:第一次从待排序的中数据元素选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。

//升序
#include<stdio.h>
void Print(int arr[],int len)
{
    for(int i=0;i<len;i++)
    {
        printf("%d ",arr[i]);
    }
    printf("\n");
}
void Choose_sort(int arr[],int len)
{
    for(int i=0;i<len;i++)
    {
        for(int j=i+1;j<len;j++)
        {
            if(arr[i]>arr[j])
            {
                int temp=arr[j];
                arr[j]=arr[i];
                arr[i]=temp;
            }
        }
    }
    Print(arr,len);
}
int main()
{
    int arr[]={9,8,7,6,0,5,4,3,2,1};
    int len=sizeof(arr)/sizeof(*arr);
    Choose_sort(arr,len);
    return 0;
}

结果:0 1 2 3 4 5 6 7 8 9

插入排序

将待排序序列分为两部分,一部分有序一部分无序,我们把第一个元素看作有序序列,从第二个元素到最后为无序序列,将无序序列中每一个元素依次插入到有序序列的合适位置–从小到大(从大到小)。 

#include<stdio.h>
void Print(int arr[],int len)
{
    for(int i=0;i<len;i++)
    {
        printf("%d ",arr[i]);
    }
    printf("\n");
}
void Insert_sort(int arr[],int len)
{
    int i,j;
    for( i=0;i<len;i++)
    {
        int temp=arr[i];
        for( j=i-1;j>=0;j--)
        {
            if(temp<arr[j])
            {
                arr[j+1]=arr[j];
            }
            else
            {
                break;
            }
        }
        arr[j+1]=temp;
    }
    Print(arr,len);
}
int main()
{
    int arr[]={9,8,7,6,0,5,4,3,2,1};
    int len=sizeof(arr)/sizeof(*arr);
    Insert_sort(arr,len);
    return 0;
}

结果:0 1 2 3 4 5 6 7 8 9

堆排序

堆排序(HeapSort)就是利用堆(一种数据结构,如果不了解堆,可以看我前面文章了解一下堆)进行排序的方法 。基本思想:将待排序的序列构造成一个大根堆。此时,整个序列的最大值就是堆顶的根结点。将它移走(其实就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次小值。如此反复执行,就能得到一个有序序列 
 

主要步骤:建堆(大根堆),调整(向下调整)


#include<stdio.h>
//两数交换
void Swap(int* e1,int* e2)
{
    int temp=*e1;
    *e1=*e2;
    *e2=temp;
}
//向上调整
void AdjustUP(int* a,int n)
{
    int child=n-1;
    int parent=(child-1)/2;
    while(child>0)
    {
        if(a[child]<a[parent])
        {
            Swap(&a[child], &a[parent]);
            child=parent;
            parent=(child-1)/2;
        }
        else
        {
            break;
        }
    }
}
//向下调整
void AdjustDown(int* a,int n,int parent)
{
    int child=parent*2+1;
    while(child<n)
    {
        if(child+1<n&&a[child]<a[child+1])
        {
            child++;
        }
        if(a[child]>a[parent])
        {
            Swap(&a[child], &a[parent]);
            parent=child;
            child=parent*2+1;
        }
        else
        {
            break;
        }
    }
}
//向上建堆排序
//时间复杂度为O(N*logN)
void HeapSort_UP(int* a,int n)
{
    //向上建堆是从第二层开始直到第h层,所以其时间复杂度为O(N*logN)
    for(int i=1;i<n;i++)
    {
        AdjustUP(a, i);
    }
    int end=n-1;
    //建堆完成后,需要进行向下调整其时间复杂度为O(N*logN)
    while(end>0)
    {
        Swap(&a[0], &a[end]);
        AdjustDown(a, end,0);
        end--;
    }
}
//向下建堆排序
//时间复杂度为N*logN
void HeapSort_Down(int* a,int n)
{
    //向下建堆是从第h-1层直到第一层,所以其时间复杂度为O(N)
    for(int i=(n-1-1)/2;i>=0;i--)
    {
        AdjustDown(a, n,i);
    }
    int end=n-1;
    //建堆完成后,需要进行向下调整其时间复杂度为O(N*logN)
    while(end>0)
    {
        Swap(&a[0], &a[end]);
        AdjustDown(a, end,0);
        end--;
    }
}
总结:向上建堆从第二层开始直到第h层,向下建堆是从第h-1层直到第一层,虽然它们经历的层数相同,但是向上建堆中第一层不用调整,向下建堆中第h层不用调整(h为最后一层),第一层的元素只有一个,第h层元素有2^(h-1)个。所以他们的时间复杂度不同,向上建堆为O(N*logN),向下建堆为O(N)
int main()
{
    int a[]={1,3,5,7,9,0,8,6,4,2};
    int n=sizeof(a)/sizeof(a[0]);
    //HeapSort_UP(a,n);
    HeapSort_Down(a, n);
    for(int i=0;i<n;i++)
    {
        printf("%d ",a[i]);
    }
    return 0;
}
//结果:0 1 2 3 4 5 6 7 8 9
结果:0 1 2 3 4 5 6 7 8 9  

希尔排序

 希尔排序是对插入排序进行优化,希尔排序先选定一个数值(整数)作为增量,把待排序所有数据分为若干组,以每个距离(这个距离就是增量)的等差数列为一组,对每一组进行排序,这一步叫作预排序,然后将增量缩小,继续分组排序,重复上述动作,直到增量缩小为1时,排序完正好有序。

​ 希尔排序原理是每一对分组进行排序后,整个数据就会更接近有序,当增量缩小为1时,就是插入排序,但是现在的数组非常接近有序,移动的数据很少,所以效率非常高,所以希尔排序又叫减小增量排序。

​ 每次排序让数组接近有序的过程叫做预排序,最后一次插入是直接插入排序

希尔排序
1.预排序--接近有序
2.插入排序

间隔gap分为一组,总计gap组
假设gap==3;
预排序:对gap组数据分别进行插入排序


gap越大,大的数可以更快到后面,小的数
#include<stdio.h>
void Print(int* a,int n)
{
    for(int i=0;i<n;i++)
    {
        printf("%d ",a[i]);
    }
    printf("\n");
}
归纳公式:合计gap组,每组n/gap个
每组:1+2+3+...+n/gap
合集gap组
总计:gap*(1+2+3+...+n/gap)

O(N^1.33)
int main()
{
    int a[]={9,8,7,6,5,4,3,2,1,0};
    int n=sizeof(a)/sizeof(*a);
    int gap=n;
    while(gap>1)//时间复杂度log3^N
    {
        gap=gap/3+1;
//        for(int j=0;j<n-gap;j++)
//        {
            for(int i=0;i<n-gap;i++)//N
            {
                int end=i;
                int temp=a[end+gap];
                while(end>=0)//log3^N
                {
                    if(a[end]>temp)
                    {
                        a[end+gap]=a[end];
                        end-=gap;
                    }
                    else
                    {
                        break;
                    }
                }
                a[end+gap]=temp;
            }
//        }
    }
    Print(a, n);
    return 0;
}
结果:0 1 2 3 4 5 6 7 8 9

五种排序的效率比较 

其实这里是六种排序,我在这里加入了 C 语言库里的快速排序qsort,为了更好比较各个排序的效率。这里采用六种排序同时排序具有 相同10000 个数据的数组。

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
//打印函数
void Print(int* a,int n)
{
    for(int i=0;i<n;i++)
    {
        printf("%d ",a[i]);
    }
    printf("\n");
}
//交换函数
void Swap(int* e1,int* e2)
{
    int temp=*e1;
    *e1=*e2;
    *e2=temp;
}
//向下调整
//大根堆
void AdjustDown(int* a,int n,int parent)
{
    int child=parent*2+1;
    while(child<n)
    {
        if(child+1<n&&a[child]>a[child+1])
        {
            child++;
        }
        if(a[child]<a[parent])
        {
            Swap(&a[child], &a[parent]);
            parent=child;
            child=parent*2+1;
        }
        else
        {
            break;
        }
    }
}
//建大堆排序
void AdjustDownSort(int*a,int n)
{
    for(int i=(n-1-1)/2;i>=0;i--)
    {
        AdjustDown(a, n, i);
    }
    int end=n-1;
    while(end>0)
    {
        Swap(&a[0], &a[end]);
        AdjustDown(a, end, 0);
        end--;
    }
}
//冒泡排序
void BubbleSort(int* a,int n)
{
    for(int i=0;i<n-1;i++)
    {
        for(int j=0;j<n-i-1;j++)
        {
            if(a[j]>a[j+1])
                Swap(&a[j], &a[j+1]);
        }
    }
}
//选择排序
void SelectSort(int* a,int n)
{
    for(int i=0;i<n;i++)
    {
        for(int j=i+1;j<n;j++)
        {
            if(a[i]>a[j])
                Swap(&a[i], &a[j]);
        }
    }
}
//插入排序
void InsertSort(int* a,int n)
{
    for(int i=0;i<n;i++)
    {
        int end=i;
        int temp=a[i+1];
        while(end>=0)
        {
            if(a[end]>temp)
            {
                a[end+1]=a[end];
                end--;
            }
            else
            {
                break;
            }
        }
        a[end+1]=temp;
    }
}
//希尔排序
void SellSort(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 temp=a[end+gap];
            while(end>=0)
            {
                if(a[end]>temp)
                {
                    a[end+gap]=a[end];
                    end-=gap;
                }
                else
                {
                    break;
                }
            }
            a[end+gap]=temp;
        }
    }
}
int cmp_int(const void* e1, const void* e2)
{
 return *(int*)e1 - *(int*)e2;
}


int main()
{
    srand((unsigned int)time(NULL));
    const int N=10000;
    int* a1=(int*)malloc(sizeof(int)*N);
    int* a2=(int*)malloc(sizeof(int)*N);
    int* a3=(int*)malloc(sizeof(int)*N);
    int* a4=(int*)malloc(sizeof(int)*N);
    int* a5=(int*)malloc(sizeof(int)*N);
    int* a6=(int*)malloc(sizeof(int)*N);
    
    for(int i=0;i<N;i++)
    {
        a1[i]=rand()%100;
        a2[i]=a1[i];
        a3[i]=a1[i];
        a4[i]=a1[i];
        a5[i]=a1[i];
        a6[i]=a1[i];
    }
    int begin1=(int)clock();
    BubbleSort(a1, N);
    int end1=(int)clock();
    printf("冒泡排序所需的时间:%dms\n",end1-begin1);
    
    int begin2=(int)clock();
    SelectSort(a2, N);
    int end2=(int)clock();
    printf("选择排序所需的时间:%dms\n",end2-begin2);
    
    int begin3=(int)clock();
    AdjustDownSort(a3, N);
    int end3=(int)clock();
    printf("堆排序所需的时间:%dms\n",end3-begin3);
    
    int begin4=(int)clock();
    InsertSort(a4, N);
    int end4=(int)clock();
    printf("插入排序所需的时间:%dms\n",end4-begin4);
    
    int begin5=(int)clock();
    SellSort(a5, N);
    int end5=(int)clock();
    printf("希尔排序所需的时间:%dms\n",end5-begin5);
    
    int begin6=(int)clock();
    qsort(a6, N, 4, cmp_int);
    int end6=(int)clock();
    printf("快排排序所需的时间:%dms\n",end6-begin6);
    return 0;
}

结果:

泡排序所需的时间:389679ms

选择排序所需的时间:165760ms

堆排序所需的时间:3005ms

插入排序所需的时间:75965ms

希尔排序所需的时间:1628ms

快排排序所需的时间:585ms

可见快排、希尔排序和堆排序是一个量级,其中快排的效率非常高,不可思议的是希尔排序的效率高过了时间效率为O(N*logN)的堆排序,虽然希尔排序的中循环比较多,但是时间效率并不高,因为希尔排序的时间效率存在难以解决的数学难题,所以很难精确其时间效率,希尔排序的时间效率大概是 O(N^1.3)。插入排序、选择排序和冒泡排序,这三种排序的时间效率都为O(N^2),其中插入排序的效率明显高于其他两个,冒泡排序的效率非常低,没有实际的用途,常用于教学。

  🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

批量提取某音视频文案(二)

牙叔教程 简单易懂 之前写过一篇 批量提取某音视频文案 , 在之前的教程中, 我用的是微软的语音转文字功能, 今天我们换个方法, 使用 逗哥配音 的 文案提取 功能 准备工作 下载视频和音频 我在github找到的是这个仓库 https://github.com/Johnserf-Seed/TikTokDownload 注意一…

VLANIF虚接口案例实践

1&#xff09;拓扑 2&#xff09;需求&#xff1a; -所有PC能够ping通自己的网关 -实现vlan间互通&#xff0c;实现所有的PC互通 3&#xff09;配置步骤&#xff1a; 第一步&#xff1a;给pc配置IP地址 第二步&#xff1a;交换机创建vlan,做access和trunk -所有的交换机都配…

传统图形学对nerf的对比与应用落地

作者今年参加了China3DV的盛会&#xff0c;大会的发表、线下讨论、学者、工业界等等的交流着实对于Nerf有了更深的思考&#xff0c;以下是作者的抛砖引玉&#xff0c;如有不当之处敬请指出~ 传统图形学与nerf的简介&#xff1a; 传统图形学&#xff1a;显示表达几何表达方式&…

【CloudCompare教程】010:点云的裁剪功能(分段、裁剪、筛选)

本文讲解CloudCompare点云的裁剪功能(分段、裁剪、筛选)。 文章目录 一、点云的分段二、点云的裁剪三、点云的筛选一、点云的分段 加载案例点云数据,如下图所示: 选中图层点云,点击工具栏中的【分割】工具。 点击【激活线状选择】工具: 在需要裁剪的点云上绘制现状裁剪范…

使用免费的SSL证书将nginx配置的普通网站修改为HTTPS网站

一、需求说明 已经在Centos8系统中使用nginx搭建了网站;但是该网站没有实现HTTPS协议不安全;现需要将网站升级为HTTPS站点。 Linux环境对Nginx开源版源码下载、编译、安装、开机自启https://blog.csdn.net/xiaochenXIHUA/article/details/130265983?spm=1001.2014.3001.5501

chatgpt赋能python:Python交易接口简介

Python交易接口简介 Python作为一种高级编程语言&#xff0c;被广泛用于各种不同的领域&#xff0c;其中包括金融市场交易。Python交易接口提供了一种优雅而简单的方式&#xff0c;使得交易者能够方便地执行自己的交易策略。 什么是Python交易接口&#xff1f; Python交易接…

Effective第三版 中英 | 第2章 创建和销毁对象 | 考虑静态工厂方法而不是构造函数

文章目录 Effective第三版第2章 创建和销毁对象前言考虑静态工厂方法而不是构造函数 Effective第三版 第2章 创建和销毁对象 前言 大家好&#xff0c;这里是 Rocky 编程日记 &#xff0c;喜欢后端架构及中间件源码&#xff0c;目前正在阅读 effective-java 书籍。同时也把自己…

基于SSM的人才招聘网站

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

模拟实现库函数:strcpy

目录 通过cplusplus网站了解函数功能&#xff1a; 断言assert的使用&#xff1a; 关于const&#xff1a; 本篇你最应该了解的内容&#xff1a; 通过cplusplus网站了解函数功能&#xff1a; 要模拟实现库函数&#xff0c;首先我们需要了解这个函数的参数&#xff0c;函数的…

主机加固介绍

最近公司做服务器安全&#xff0c;开始在市场了解产品&#xff0c;对这一块算是短暂的研究了一段时间&#xff0c;有一点心得给大家分享一下。 主机加固 最近主机加固的概念被炒得火热&#xff0c;主机加固的功能也正在被致力于服务器安全的相关人士所关注。 那么究竟什么是主…

【CVPR2022】CSWin Transformer详解

【CVPR2022】CSWin Transformer详解 0. 引言1. 网络结构2. 创新点2.1 Cross-Shaped Window Self-Attention2.2 Locally-Enhanced Positional Encoding(LePE) 3. 实验总结 0. 引言 Transformer设计中一个具有挑战性的问题是&#xff0c;全局自注意力的计算成本非常高&#xff0…

chatgpt赋能python:Python代码怎么敲:了解Python编程语言

Python代码怎么敲&#xff1a;了解Python编程语言 Python是一种高级编程语言&#xff0c;具有易读易用和高效性等优点。这使得Python成为了程序员的最佳选择&#xff0c;并成为了广泛应用于机器学习、Web开发、数据分析等领域。 Python代码敲法&#xff1a;小技巧 Python代码…

chatgpt赋能python:Python主要语句介绍

Python主要语句介绍 Python是一种广泛使用的高级编程语言&#xff0c;其语法简介、易于学习&#xff0c;并有丰富的库和工具支持。在Python中&#xff0c;主要的语句可以帮助开发人员快速编写代码&#xff0c;实现各种各样的任务。在本文中&#xff0c;我们将介绍Python中的主…

性能优化之高Log file sync等待实战案例分享

故障情况 AWR报告如下&#xff1a; 之后他们把大部分业务停掉后&#xff0c;Log file sync等待事件还是非常高。 通过对比昨天跟今天相同时间的AWR&#xff0c;在业务量小非常多的情况&#xff0c;等待时间还是高非常大。 诊断过程 log file sync等待事件首先判断当前系统IO…

“微商城”项目(1环境搭建)

开发工具分享&#xff1a; 百度网盘&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1lSsCjf-_zx1ymu6uZeG26Q?pwdhuan 提取码&#xff1a;huan 一、环境搭建说明 本项目服务端环境要求为 Windows Apache PHP MySQL。 下面介绍如何搭建环境&#xff0c;部署服…

CW32系列模数转换器(ADC)

模数转换器&#xff08;ADC&#xff09;的主要功能是将模拟量转换为数字量&#xff0c;方便MCU进行处理。下面以CW32L083为例介绍CW系列的模数转换器的特点和功能&#xff0c;并提供演示实例。 一、概述 CW32L083 内部集成一个 12 位精度、最高 1M SPS 转换速度的逐次逼近型模…

位操作符的应用

目录 位操作符的概念&#xff1a; 一、&&#xff08;按位与&#xff09;&#xff1a;两个整数的补码对应的二进制位有0则为0&#xff0c;两个同时为1才为1&#xff0c;得到的数仍为补码。 二、|&#xff08;按位或&#xff09;&#xff1a;两个整数的补码对应的二进制位…

Effective第三版 中英 | 第2章 创建和销毁对象 | 当面临多个参数的构造器时考虑使用构建器

文章目录 Effective第三版前言第2章 创建和销毁对象当面临多个参数的构造器时考虑使用构建器 Effective第三版 前言 大家好&#xff0c;这里是 Rocky 编程日记 &#xff0c;喜欢后端架构及中间件源码&#xff0c;目前正在阅读 effective-java 书籍。同时也把自己学习该书时的笔…

【KKT】∇f(x)+λ∇g(x)=0中λ的讨论

Karush-Kuhn-Tucker (KKT)条件 〇、问题背景 在阅读 Karush-Kuhn-Tucker (KKT)条件 时&#xff0c;不太能理解 ∇ f \nabla f ∇f 的方向&#xff0c;以及 ∇ g \nabla g ∇g 的方向&#xff1a; 为什么 ∇ f \nabla f ∇f 是指向可行域内部&#xff0c; ∇ g \nabla g ∇g…

Java多线程方面知识

目录 1.程序、进程、线程 2.进程与线程的内存解析 3.并发与并行 4.Java程序的线程 5.多线程的创建&#xff1a;方式一&#xff1a;继承于Thread类 6.start方法的作用 7.使用start()时要注意的问题 8.Thread类中的一些方法 9.线程的优先级 10.多线程的创建&#xff1a…