当前位置:首页 > C++知识 > 正文内容

【高级篇】C++中的sort函数详解

亿万年的星光4年前 (2021-01-28)C++知识5843
0.简介

sort函数用于C++中,对给定区间所有元素进行排序,默认为升序,也可进行降序排序。sort函数进行排序的时间复杂度为n*log2n,比冒泡之类的排序算法效率要高,sort函数包含在头文件为#include<algorithm>的c++标准库中

1.sort的参数
sort(start,end,cmp)

start:表示排序数组起始的位置

end:表示排序数组结束的位置

cmp:用于排序的方法,可以不填,不填默认升序

2.数组中的用法
#include<bits/stdc++.h>
using namespace std;
int main()
{
   int a[5]={1,9,3,4,5};
   for(int i=0;i<5;i++)
       cout<<a[i]<<" ";
   sort(a,a+5); //数组从0开始,数组有多少个数就加多少
   cout<<endl;
   for(int i=0;i<5;i++)
       cout<<a[i]<<" ";
   return 0;
}

当我们加上cmp函数后,下面这种写法和上面的结果一样


#include<bits/stdc++.h>
using namespace std;
bool cmp(int x, int y)
{
   return x<y;    
   /*
       可以这样理解,sort第三个参数默认升序,
       这个地方是个bool函数。
       如果返回值结果为假,那么函数会互换他们的位置
       如果返回结果为真,就保持原来的位置不变 。
       如果x<y成立,那么就保持不变,否则就交换位置。
   */
}
int main()
{
   int a[5]={1,9,3,4,5};
   for(int i=0;i<5;i++)
       cout<<a[i]<<" ";
   sort(a,a+5,cmp); //数组从0开始,数组有多少个数就加多少
   cout<<endl;
   for(int i=0;i<5;i++)
       cout<<a[i]<<" ";
   return 0;
}



可以这样理解,sort中的第三个参数,会去进行两两元素的比较,
函数这个地方是个bool类型的函数。
如果返回值结果为假,那么函数会互换他们的位置
如果返回结果为真,就保持原来的位置不变函数


那么,如果把cmp中的函数改成 return x>y; 那么默认就是 从大到小排序。

3.结构体中的用法

平常做题的时候可能会遇到下面几种情况:

  • 一个结构体需要排序,里面属性太多,只根据一个属性进行排序,其余属性需要同步更改位置,单纯使用冒泡需要交换的东西太多

  • 一个结构体需求排序,但是排序依据不唯一。例如下面结构体

struct student{
   char name[50];   //学生姓名
   int sum;   //总成绩  
   int chinese; //语文成绩
   int math; //数学成绩
   int english; //英语成绩
};

要求先按照总成绩排序,如果总成绩相同,则按照数学成绩排序,如果数学成绩相同,则按照英语成绩排序,如果英语成绩相同则按照语文成绩排序。

。。。。。。

先来解决第一个问题,假如只按照总成绩排序,总成绩相同的不做任何排序处理。

#include<bits/stdc++.h>
using namespace std;
struct student{
   char name[50];   //学生姓名
   int sum;   //总成绩  
   int chinese; //语文成绩
   int math; //数学成绩
   int english; //英语成绩
};
student s[50];
bool cmp(student x, student y) //参数类型要写成结构体类型,
{
   return x.sum>y.sum;    
}
int main()
{    
   int n;// 定义数据
   cin>>n;
   for(int i=0;i<n;i++)
   {
       cin>>s[i].name>>s[i].chinese>>s[i].math>>s[i].english;
       s[i].sum=s[i].chinese+s[i].math+s[i].english;    
   }    
   sort(s,s+n,cmp);
   cout<<"按总成绩排序后的结果是:"<<endl;
   cout<<"name"<<" "<<"语文"<<" "<<"数学"<<" "<<"英语"<<" "<<"总成绩"<<endl;
   for(int i=0;i<n;i++)
   {
       cout<<s[i].name<<" "<<s[i].chinese<<" "<<s[i].math<<" "<<s[i].english<<" "<<s[i].sum<<endl;    
   }  
   
   return 0;
}
/*
8
tom1 10 20 30
tom2 10 30 30
tom3 20 30 30
tom4 10 30 10
tom5 30 40 10
tom6 10 15 10
tom7 30 20 15
tom8 20 10 15    
*/

可以看出是按照总计成绩进行排序的。可以看出,我们在cmp函数中只要写一个结构体中的参数就可以了。


那么第二个问题来了。我们可以继续改cmp中的写法

#include<bits/stdc++.h>
using namespace std;
struct student{
   char name[50];   //学生姓名
   int sum;   //总成绩  
   int chinese; //语文成绩
   int math; //数学成绩
   int english; //英语成绩
};
student s[50];
bool cmp(student x, student y) //参数类型要写成结构体类型,
{
  //先按照总成绩由大到小排(如果两个数的总成绩不相等,则根据大小关系判断是否交换位置)
   if(x.sum!=y.sum)    
       return x.sum>y.sum;
  //如果总成绩相同,再按照数学成绩进行排序  
   if(x.math!=y.math)
       return x.math>y.math;
  //如果数学成绩相同,再按照英语成绩进行排序        
   if(x.english!=y.english)
       return x.english>y.english;
   else //最后只剩语文了
       return x.chinese>y.chinese;
}
int main()
{    
   int n;// 定义数据
   cin>>n;
   for(int i=0;i<n;i++)
   {
       cin>>s[i].name>>s[i].chinese>>s[i].math>>s[i].english;
       s[i].sum=s[i].chinese+s[i].math+s[i].english;    
   }    
   sort(s,s+n,cmp);
   cout<<"按总成绩排序后的结果是:"<<endl;
   cout<<"name"<<" "<<"语文"<<" "<<"数学"<<" "<<"英语"<<" "<<"总成绩"<<endl;
   for(int i=0;i<n;i++)
   {
       cout<<s[i].name<<" "<<s[i].chinese<<" "<<s[i].math<<" "<<s[i].english<<" "<<s[i].sum<<endl;    
   }  
   
   return 0;
}
/*
8
tom1 10 20 50
tom2 10 30 40
tom3 10 40 30
tom4 20 20 40
tom5 30 20 30
tom6 40 20 20
tom7 30 20 30
tom8 20 20 30    
*/

可以看出,首先按照总成绩排序,如果总成绩相同,则按照数学成绩排序,如果数学成绩相同,则按照英语成绩排序。题目的样例不够完善,没有体现出如果在上面的条件下,如果英语成绩也相同的情况。

4.字典序问题

一些题目中,可能会要求按照字典序排序,一般多见于字符串的类型。

比如

例题1—单词排序:

【题目描述】输入一行单词序列,相邻单词之间由1个或者多个空格间隔,请按照字典序输出这些单词。

【输入】一行单词序列,最少1个单词,最多100个单词,每个单词长度不超过50,单词之间用至少1个空格间隔。数据不含除字母、空格外的其他字符。

【输出】按字典序输出这些单词。

【样例输入】

She  wants  to go to Peking University to study  Chinese

【样例输出】 

Chinese
Peking
She
University
go
study
to
wants

首先,这个题目简单一点的做法就是,直接for循环,按照ASCII码比较。但是,我们学了sort,用起来就比较简单了。

做法1:sort+结构体+字符数组

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct student{
	char name[50]; 
}s[100]; 
bool cmp(student x, student y){
	return x.name > y.name;
}
int main(){
	int n;
	cin>>n; //确定长度
	for(int i=0;i<n;i++){
		cin>>s[i].name;
	}
	//sort(s,s+n); //因为是结构体,所以不加第三个参数,这里会报错 
	sort(s,s+n,cmp); 
	cout<<"-----结果-----"<<endl;
	for(int i=0;i<n;i++){
		cout<<s[i].name<<endl;
	}
}
/*
输入: 
4
aa
bs
cf
ck 
输出: 
ck
cf
bs
aa
*/

可以看出,我们如果结构体中只是用字符数组排序的话,只能按照输入的正序或者倒序排,但是没有按照字典序排。(但是如果是类似按照总成绩进行排序,那么名字会同步变化)

如果是结构体+字符串呢

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct student{
	string name; 
}s[100]; 
bool cmp(student x, student y){
	return x.name < y.name;
}
int main(){
	int n;
	cin>>n; //确定长度
	for(int i=0;i<n;i++){
		cin>>s[i].name;
	}
	//sort(s,s+n); //因为是结构体,所以不加第三个参数,这里会报错 
	sort(s,s+n,cmp); 
	cout<<"-----结果-----"<<endl;
	for(int i=0;i<n;i++){
		cout<<s[i].name<<endl;
	}
}

/*
输入: 
4
aa
bs
cf
ck 
输出: 
aa
bs
cf
ck
*/

可以看出这种是没有问题的。

也就是说,如果是成绩排序+字典序排序的话, 那么类似于名字这样的,要用字符串而不是字符数组。

做法2:sort+字符串数组

除了结构体之外,我们还可以用字符串数组来

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
string s[100]; 
int main(){
	int n;
	cin>>n; //确定长度
	for(int i=0;i<n;i++){
		cin>>s[i];
	}
	sort(s,s+n); 
	cout<<"-----结果-----"<<endl;
	for(int i=0;i<n;i++){
		cout<<s[i]<<endl;
	}
}

/*
输入: 
4
Ajl
dsa
Bdr
rgk
输出: 
Ajl
Bdr
dsa
rgk
*/

可以看出,字符串数组可以不用加sort的第三个参数,默认按照字典序输出。当然,我们也可以加上第三个参数。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
string s[100]; 
bool cmp(string x, string y){
	return x>y;
}

int main(){
	int n;
	cin>>n; //确定长度
	for(int i=0;i<n;i++){
		cin>>s[i];
	}
	sort(s,s+n,cmp); 
	cout<<"-----结果-----"<<endl;
	for(int i=0;i<n;i++){
		cout<<s[i]<<endl;
	}
}

/*
输入: 
4
Ajl
dsa
Bdr
rgk
输出: 
rgk
dsa
Bdr
Ajl
*/
5.总结

不论是单纯的数组还是结构体,sort函数的第三个参数是用来决定两个元素是否要进行交换位置的。


扫描二维码推送至手机访问。

版权声明:本文由青少年编程知识记录发布,如需转载请注明出处。

分享给朋友:

相关文章

【题解】均分纸牌

【题目描述】有n堆纸牌,编号分别为 1,2,…, n。每堆上有若干张,但纸牌总数必为n的倍数。可以在任一堆上取若干张纸牌,然后移动。移牌规则为:在编号为1的堆上取的纸牌,只能移到编号为 2 的堆上;在...

C++中的宏

一、预处理和编译器    首先,预编译器就是在编译器之前运行,换句话说,预编译器根据程序员的指示,决定实际要编译的内容。预编译器编译指令都以 # 开头。例如:1...

【数据结构】队列—基本概念

【数据结构】队列—基本概念

一、基本定义队列是一种先进先出的线性结构,简称FIFO结构。特点就是“先进先出”二、队列的相关概念队头与队尾:允许元素插入的一端称为队尾,允许元素删除的一端称为队头入队:队列的插入操作出队:队列的删除...

【算法】分治算法

前言所谓分治算法就是指分而治之,即将较大规模的问题分解成几个较小规模的问题,通过对较小问题的求解达到对整个问题的求解。当我们将问题分解成两个较小问题求解时的分治方法称为二分法。比如,我们玩过最简单的猜...

C++小项目——实时钟表

C++小项目——实时钟表

0.前言在很多游戏中,我们要使用时间,这个时间一个是系统当前的时间,一个是服务器给你的时间。这篇文章我们尝试做一个模拟时钟。效果图如下1.任务分解1.首先我们尝试使用easyx来画一个。基本框架如下:...

【数据结构】栈的基本操作

0.前言上一篇中简单介绍了栈的定义,这一篇中介绍栈的基本用法,包含压栈,出栈,判断栈空,判断栈中元素个数等。下面进行详细介绍1.基本用法本文介绍的栈的主要操作,使用栈之前加入<stack>...