DataWhale学习笔记 LeetCode算法day05-08

本文详细介绍了排序算法中的冒泡排序、选择排序、插入排序、归并排序、希尔排序、快速排序、堆排序、计数排序、桶排序和基数排序,分析了它们的时间复杂度、空间复杂度以及稳定性,并提供了代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、排序

01 冒泡排序

顾名思义,这种排序像水下的一串泡泡要冒出水面,但只能让大泡泡先冒出,小泡泡才能冒出。通过两两比对(下面的泡泡跟它正上方的比较),依次将两泡泡中较大的那个放在上面。

n个数据,需要排n-1趟,每一趟要前后比较n-1-i次。

则一次排序过后,最大的冒出水面;第二次再从最下面的开始比较,这次第二大的泡泡冒出水面;重复此步骤,直到水下只有两个泡泡,比较它们,这次两个泡泡按大小顺序冒出水面,排序就完成了。

大家学习过程中可以参考b站演示视频,直观清晰。

代码实现:

#include<stdio.h>
#define N 5
int main()
{
    int i,j,tmp;
    int arr[N]={5,2,3,4,1};
    for(i=0;i<N-1;i++)
    {
        for(j=0;j<N-1-i;j++)
        {
            if(arr[j]>arr[j+1])
               {
                    tmp=arr[j];
                    arr[j]=arr[j+1];
                    arr[j+1]=tmp;
                }
        }
    }

    for(i=0;i<N;i++)
    {printf("%3d",arr[i]);}
      printf("\n");
    return 0;

}

分析:明显看到冒泡是需要双层循环的,这意味着时间复杂度最高可达O(n*n),因此只适合数据量较小的情况;不过冒泡也是有优点的,它是一种原地排序,没有占用其他空间,空间复杂度是很小的;同时,每一次都是相邻两者比较、调换,其稳定性较高。

02 选择排序

选择排序即每一次都从无序数列中选出最小(大)的,排在有序部分,直至全部排完。

需要排n-1趟,每趟从i+1比到最后一个元素。

代码实现:

#include<stdio.h>
#define N 5
int main()
{
    int i,j,tmp,min=0;
    int arr[N]={5,4,1,2,3};
    for(i=0;i<N-1;i++)
    {
        min=i;
        for(j=i+1;j<N;j++)
        {
            if(arr[min]>arr[j])
            {
                min=j;
            }
            if(min!=i)
            {
                tmp=arr[min];
                arr[min]=arr[i];
                arr[i]=tmp;
            }
        }
    }
    for(i=0;i<N;i++)
    {
        printf("%3d",arr[i]);
    }
    printf("\n");
    return 0;
}

可以看到这里也是双层循环,故时间复杂度最大O(n*n),同样是原地排序,空间复杂度小,由于每次调换不是与相邻元素换,其稳定性也不是太好。

03 插入排序

即每次从无序序列中取一个数,在有序序列中从左向右地进行比较,直到找到该元素应处的位置,把它放在该位置;重复此操作,直至无序序列为0。

这其中也是需要依次拿出数,拿出的数依次去比较,也就是双层循环,时间复杂度最大为O(n*n);没有占用其他空间,空间复杂度O(1)。且插入排序也较稳定(这里还不理解)。

【考虑篇幅,之后的排序不再写代码】

04 归并排序

有点像二分法,不断对数组平分两组,直至每一组都只有一个元素,再把相邻两组比大小组合为一组,e.g.一个元素一组并成两个元素一组,此时相邻两组共有4个元素,比较这4个元素,合并为有序的一个新组,以此类推,直到重新合并为含所有元素的一大组。

时间复杂度O(n*log n),空间复杂度O(n),较稳定排序。

05 希尔排序

希尔排序也是分组,但它是组内分先后的排序,好像上小学班级里分小组,每个组都有1号,2号,3号那种。比如8个人,平分两组(9个人就3组,只不过第三组只1人);每组1号跟1号比,2号跟2号比(田忌赛马之前的老赛制那感觉),把小的放在第一组,大的放在第二组;比完这4个组员,重新分组,这次就是2人一组,还是每组1号跟1号比,2号跟2号比;最后直到每组一个人,再做比较,最终完成。

时间复杂度:O(n*log方 n)-O(n*n)之间,空间复杂度O(n),不稳定排序。

06 快速排序

这种算法像是俩人碰头问题。选定一个基数做对照,左一个指针右一个指针,分别指着最左最右的元素开始与基数比对,把比基数小的放左边,大的放右边。这俩指针要交替着来,一人走一步,如果某一步左指针指着的数就应该在左边,没换到右边去,那左指针就再走一步。

排好一次,在原基数的左右分别重复此步骤,直至全部有序。

时间复杂度O(n*n),空间复杂度O(n),不稳定排序。

07 堆排序

首先要知道大顶堆,即二叉树上任意节点数>其子节点数,要实现它,只要节点与子节点三个数据找最大即可。

于是堆排序的方法就很清晰了,只要构建大顶堆,每次都把最顶上的元素拿出来,天然的就是从大到小的一组数了!!非常奇妙。

时间复杂度O(n*log n),空间复杂度O(1),不稳定排序。

08 计数排序

举实例说明:一串数:3,5,6,3,1,0,8。定义一数组arr[9]={0},遍历该串数,出现3,即给arr[3]加1,出现5即给arr[5]加1......本串数出现两次3,即最后arr[3]=2。

最后将arr[i]的i顺序排出,arr[i]计数几次就排几次相应的i,即完成初始数组的排序。

(这波其实是优劣明显了,数值跨度大的话就来不了了,空间太大太浪费)

时间复杂度O(n+k),空间复杂度O(k),稳定排序。

09 桶排序

一组数:1,3,9,......,100,67,30,划分区间如[0,20),[20,40),......[80-100],先把数分到各个桶里,各桶里进行排序,再从桶里顺序拿出来排成一串。(在桶里咋排就看情况选了)

时间复杂度O(n),空间复杂度O(n+m),不稳定排序。

10 基数排序

类似计数排序,是其进阶版。按个十百千位数字依次计数,记完一次排一次,直到最高位记完排完,此时全部有序。

时间复杂度O(n*k),空间复杂度O(n+k),稳定排序。

一口气总结了这些排序,真是要我老命,做题就另开一个吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值