《啊哈算法》第一章--排序(解析+代码)

本文介绍了几种基础的排序算法,包括冒泡排序的时间复杂度为O(n^2),适合小数据量;快速排序平均时间复杂度为O(N*logN),是最常用的排序算法之一;桶排序在数据均匀分布时能达到O(N+C)的时间复杂度,但空间复杂度高;计数排序是桶排序的简化版,但空间浪费严重。这些算法各有优缺点,适用于不同的场景。

目录

一,计数排序

二,冒泡排序(Bubble Sort)

三,快速排序(Quick Sort)

四,桶排序(Bucket Sort)

五,小哼买书


从无到有掌握最基础的算法

多学点算法,做题时就能拓宽思路;一种简单的算法思路,能将看起来很复杂的问题,变得简单

关于冒泡排序,快速排序和桶排序

冒泡

最慢的,只在数据量很小时能用,时间复杂度为O(n^2)

快排(推荐)

万金油(最常用),包含分治的思想,复杂度为O(N*logN),类似sort()

桶排序

时间复杂度最低(最快),为O(N + C),N为循环次数,C为N*(logN - logM),M为桶数量

也含有分治的思想

它利用函数中映射的关系(即桶与数据一对多的关系),减少了大量比较,所以时间复杂度很低,正因为如此,导致空间复杂度很高,时间越快占用空间越多(桶的数量越多),当样本跨度较大不适用,比如对1000001,1,200099999,88进行排序,不会考虑桶排序

它只适用于数据均匀分布,元素值较为集中的序列

一,计数排序

它是桶排序的简化版本

比桶排序还浪费空间,比如需要排序的范围 0 ~ 2e9(2*10^9),就需要2*10^9个桶,也就是申请2*10^9个变量,即使只对3个数排序,仍需要这么大的空间,就很浪费

 eg: 5个同学分别考了5分,3分,5分,2分,8分,将分数从大到小排序并输出

#include<iostream>
using namespace std;
int a[9]; //全局数组自动初始化为0
int main()
{
    int t;
    for(int i = 0; i < 5; ++i) { //输入5次
        cin>>t; //分数
        a[t]++; //这个分数出现的次数
    }
    for(int i = 8; i >= 0; --i) //i为分数
        for(int j = 0; j < a[i]; ++j) //j为次数
            cout<<i<<" ";
    return 0;
}
5 3 5 2 8
8 5 5 3 2

二,冒泡排序(Bubble Sort)

每次比较相邻两个元素,如果顺序不对,就交换

比如下图就是一趟冒泡排序

 对n个数进行冒泡,需要将 n - 1 个数归位,也就是进行 n - 1 趟操作

eg: 有5个同学和自己的分数,Amy 5分, Mike 10分, Bob 6分, Girl 4分, Jhon 5分,按照分数从高到低输出他们的名字(涉及结构体

#include<iostream>
using namespace std;
struct stu
{
    char name[20];
    int score;
};
int main()
{
    struct stu a[10], t; //t要声明为结构体的变量
    int n = 5;
    for(int i = 0; i < n; ++i)
        cin>>a[i].name>>a[i].score;
    for(int i = 0; i < n - 1; ++i) //n - 1趟
        for(int j = 0; j < n - i - 1; ++j) { //每趟比上一趟少比较一次
            if(a[j].score < a[j + 1].score) {
                t = a[j];
                a[j] = a[j + 1];
                a[j + 1] = t; //交换结构体两个变量
            }
        }
    for(int i = 0; i < n; ++i)
        cout<<a[i].name<<" ";
    return 0;
}
Amy 5 Mike 10 Bob 6 Girl 4 Jhon 5
Mike Bob Amy Jhon Girl

三,快速排序(Quick Sort)

先上图

 

 

 

 假设左端第一个数字6为基数(便于后续参照),根据传入的左右边界声明 i, j两个游标

j游标先行,(假设从小到大排序)直到 j游标 指向的数字小于基数6,停止

i游标后走,直到 i游标 指向的数字大于基数6

i, j 指向的数字交换

重复上面的过程直到 i, j相遇(指向同一个数,这个数必然比基数6小)

然后相遇的数字再与左端基数6交换

此时中间的左边都比中间小,中间的右边都比中间大

后续分别对6的左边和右边递归就好

#include<iostream>
using namespace std;
int a[66666], n; //定义全局变量,可在子函数使用
void quick_sort(int left, int right)
{
    if(left > right)
        return; //终止条件,说明当前数组长度为1或物理不存在
    int i, j, base;
    i = left, j = right, base = a[left];
    while(i < j) {
        while(i < j && a[j] >= base)
            j--; //j游标先行
        while(i < j && a[i] <= base)
            i++;
        if(i < j) {
            a[i] = a[i]^a[j];
            a[j] = a[i]^a[j];
            a[i] = a[i]^a[j]; //异或交换两个数
        }
    }
    a[left] = a[j];
    a[j] = base; //基数与指向的数交换
    quick_sort(left, j - 1); //对左边递归
    quick_sort(j + 1, right); //对右边递归
}
int main()
{
    cin>>n; //n个数
    for(int i = 0; i < n; ++i)
        cin>>a[i];
    quick_sort(0, n - 1);
    for(int i = 0; i < n; ++i)
        cout<<a[i]<<" ";
    return 0;
}
7
-50 666 99 12 -2 36 2
-50 -2 2 12 36 99 666

详细点的可以看这个

 (5条消息) C++快速排序之整型数组_码龄11天的博客-优快云博客_c++整数排序

四,桶排序(Bucket Sort)

与快排的区别:

快排将集合分为两个桶,对两个桶按快排排序,它是在集合本身上的排序,即原地排序

桶排序将集合分为多个桶,在额外空间上对桶进行排序,避免了构成桶过程中元素的比较和交换

算法过程:

1,Max和Min

遍历数组,得到最大值Max和最小值Min

2,桶的个数

(Max - Min) / 间隔 + 1 = 桶的个数,

比如Max == 666, Min == -28,每个桶间隔假设100,则桶的个数为 694 / 100 + 1 = 7

3,放入桶

遍历数组,将元素加入对应区间的桶中

4,对桶排序(方法自选)

5,将桶内元素放回原序列

意思就是这么个意思,不想敲了,书里没有

五,小哼买书

就是对输入的数组进行排序和去重,很简单我就不写了

可以考虑先排序,如果和上一个不相等,就输出

相等则代表重复,不输出

评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千帐灯无此声

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值