《算法笔记知识点记录》第四章——算法初步1——排序

请添加图片描述

☘前言☘

请添加图片描述

咕咕咕、鸽子精又回来了。😶‍🌫️ 没办法,之前想好好学学嵌入式,可以看到我更新了好多,结果开发板太贵了,哭晕在厕所。算了,等到回所里跟导师哭去啦。
而且最近疫情好严重,被封校了,大家也要注意安全呀。

请添加图片描述

今天继续更新,今天算是正式进入算法的入门了,上一章的其实就是简单的模拟,所以并不算入门,只是写了写算法罢了,之前一篇文章内容太多,导致把自己卷没了,这次一篇就一个知识点,分多个文章来
🧑🏻作者简介:一个从工业设计改行学嵌入式的年轻人
✨联系方式:2201891280(QQ)
📔源码地址:https://gitee.com/xingleigao/algorithm-notes
全文大约阅读时间: 120min(有点长,大家忍一下 ,一定会有蜕变的)



🍭1.基础知识点

排序是最简单的算法,其实在之前的学习我们已经接触了冒泡排序,如果没有印象的话可以看看往期文章哈《算法笔记知识点记录》第二章——快速入门2[选择结构、循环结构和数组]
这次我们再提这个算法呢,会给大家再讲一讲选择排序和插入排序,然后就是解题常用的一种方式就是库函数0.0


👻1.1选择排序

选择排序就是,每次从后面的无序序列选择一个最小的元素加入到有序序列的最后一个位置上,一直重复就可以得到最终的有序序列。可以看到得到最终的结果需要n趟选择。
请添加图片描述
于是对应的代码就很好写啦,就是n躺操作,每趟操作选出待排序部分[i,n]中的最小的元素,与a[i]交换。对应代码:

void SelectSort(){
	for(int i = 1;i <= n; ++i){	//共需要n躺过程
		int k = i;
		for(int j = 1; j <= n;++j)	//获取最小的元素
			if(a[j] < a[k]	k = j;
		swap(a[i],a[k]);	//交换元素
	}
}

需要的注意的点有几个:

  • 当i和k交换的时候如果一样的话可以不交换,但是这点复杂度时间影响不大
  • 冒泡排序的最好时间复杂度是O(n),但是选择排序复杂度都是O(n^2),因为冒泡排序中间判断了是否已经有序了
  • 示例代码给的数组起始时1终点时n,自己写的时候要灵活改动。

🕷️1.2插入排序

简单插入排序是每次将一个元素插入到前面的已经有序的序列中,显然如果只有一个元素的话肯定有序,所以是从第二个元素插入,一共需要n-1趟操作。
请添加图片描述
图片还是比较清晰的表达了这个过程,但是插入的时候我们注意到需要移动元素,我们可以将查找位置和移动位置两个过程结合起来。代码如下:

void InsertSort(){
	for(int i = 2;i <= n; ++i){
		int tmp = a[i],j = i;
		while(j > 1&& tmp < a[j-1]){
			a[j] = a[j-1];//后移一个
			j--;
		}
		a[j] = temp;//插入完成
	}
}

💐1.3库函数的使用

在C++中有一个非常实用的库函数就是sort,我们考试也只是考虑实现,所以我们建议直接使用库函数。而且sort规避了快排算法极端情况复杂度退化到O(n2)的情况,有兴趣的同学可以看看stl源码。


如何使用

#include <algorithm>
using namespace std;
sort(首元素地址(必须),尾元素地址的下一个地址(必须),比较函数(可省略));

其中前两行是规定动作,大家使用cpp进行编程的时候建议都加上using namespace std;防止出错。
然后前两个参数必须的,第三个可省略,默认的比较函数是从大到小进行排列。例如

int main(){
	int a[5] = {1,3,5,-1,2};
	sort(a, a + 5);
	for(int i = 0;i < 5;++i)	printf("%d ",a[i]);
}

得到的结果就是-1 1 2 3 5,需要注意的是这个结果可以对double浮点数也可以生效,这个牵扯到stl的知识,大家知道可以用就完事了。


cmp函数
默认的sort函数只能完成从小到大的结果,为了实现自定义的排序方式,我们就需要cmp函数来实现自定义功能,其实从名字上也能看出来就是用来比较的函数。

	bool cmp(int a, intb){return a > b;}//前面大于后面就是从大到小
	sort(a, a + 5, cmp);

这样就可以得到结果啦。
当然也可以写结构体作比较就可以实现很多复杂的排序啦。

✨例题

1025 PAT Ranking (25 分)

🍕题目描述

全英文。。。就问你慌不慌,2333。其实挺好懂的啦,多看看就不慌了。题目大意:一共有n个考场,每个考场都有一些学生,输入是考生的准考证号和分数,需要按分数从大到小的顺序返回所有考生的准考证号,排名、考场号和考场内排名。其中如果分数相同的话就按id的顺序进行排序。

🎶解题思路

肯定要建立结构体的,然后读入一个考场的所有数据后就可以对考场中所有人进行排序,并将对应的排名信息写入结构体,最后对所有数据进行排名,并输出对应的排名信息。

🎐小技巧

进行排名计算的时候,肯定会有并列的情况,判断方式其实就是如果当前的分数和上一个的分数一样,那么就将对应的名次信息和上一个的名次写的一样,否则就等于统计变量的值。其中将第一名赋为1。

🍘代码

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

struct student{
    char id[17];//id号
    int score;	//分数
    int local;	//考场号
    int local_rank;	//考场排名
}stu[30001];

bool cmp(student a, student b){	//比较函数
    if(a.score != b.score)  return a.score > b.score;
    else return strcmp(a.id, b.id) < 0; 
}

int main(){
    int N, K, num = 0;
    //数据接收 并对考场内用户进行排名
    scanf("%d",&N);
    for(int i = 0; i < N; ++i){
        //获取考场内考生数据
        scanf("%d",&K);
        for( int j = 0; j < K; ++j){
            scanf("%s %d",stu[num].id,&stu[num].score);
            stu[num].local = i + 1;
            num++;
        }
        //对考场内考生进行排名
        sort(stu + num - K,stu + num, cmp);
        stu[num - K].local_rank = 1;
        for(int j = num - K + 1; j < num; ++j)
            if(stu[j].score == stu[j - 1].score)
                stu[j].local_rank = stu[j - 1].local_rank;
            else
                stu[j].local_rank = j + 1 - num +K;
    }
    printf("%d\n",num);
    sort(stu,stu + num, cmp);
    int r = 1;
    for(int i = 0; i < num; ++i){
        if(i > 0 && stu[i].score != stu[i-1].score)
            r = i + 1;
        printf("%s ",stu[i].id);
        printf("%d %d %d\n", r, stu[i].local, stu[i].local_rank);
    }

    return 0;
}

🐳课后习题

我写完会放题解,大家写完了可以在评论区打卡哟!题解我放评论区吧,这样不用修改文章。

题目相同链接难度
《算法笔记》4.1小节——算法初步->排序⭐⭐
A1062 Talent and Virtue (25 分)B1015 德才论 (25 分)⭐⭐
A1012 The Best Rank (25 分)⭐⭐
A1025 PAT Ranking (25 分)⭐⭐
A 1028 List Sorting (25 分)⭐⭐
A 1055 The World’s Richest (25 分)⭐⭐
A 1083 List Grades (25 分)⭐⭐⭐
A 1080 Graduate Admission (30 分)⭐⭐⭐⭐
1095 Cars on Campus (30 分)⭐⭐⭐⭐

题解:评论区见,置顶没有就是我没写完0.0,大佬们刷完打个卡
大家加油冲!!!!

请添加图片描述

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

XingleiGao

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

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

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

打赏作者

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

抵扣说明:

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

余额充值