前面我们已经学习了sort()排序,本节我么将继续学习STL库提供的其他排序算法函数模板——stable_sort()。“stable”意为稳定,那么我们这个stable_sort()和之前学习过的排序算法sort()有什么区别呢,”稳定“之处在哪?原来,如果出现相同元素彼此紧邻,比如{1,2,3,3,3,4,5,3},我们其实只需要把最后一个‘3’前移即可,但是sort()奉行极致效率,不会浪费额外效能去判断元素是否相等,所以不保证同等元素是否保持原本位置;而stable_sort()则完善了这一瑕疵,它奉行”稳定排序“思想,在保证排序的情况下尽量让同等元素位置保持不变。

有的读者觉得这种排序似乎”多此一举“,但其实stable_sort()排序意义重大!比如Dotcpp编程举办了一个算法竞赛,主办方为了激发选手活力,决定设计独特的“一血”机制(完成第一题才能做其他题),排名首先会按照解决问题量进行排序,在等量情况下会通过对比解决第一道题的时间先后进行二次排序。当我们刷新排名时,我们就不能通过sort()进行排序了,因为sort()会打乱“一血”排名机制,此时我们只能通过stable_sort()进行排名。

stable_sort()的用法与sort()无异,切记使用前需要包含头文件<algorithm>。

同sort()一样,使用stable_sort()函数进行排序也有以下三点要求:

1. 由于stable_sort()对容器进行排序时,需要对元素进行随机访问,所以要求排序容器为随机访问迭代器,也就是array容器、vector容器、deque容器,C风格数组(将指针作迭代器使用)。

2. 如果元素为自定义数据,由于stable_sort()默认是升序排序,所以要求自定义数据重载“<”比较运算符。

3. 如果元素为自定义数据,由于stable_sort()需要对元素进行高效移动,所以需要自定义数据提供移动构造函数和移动赋值运算符。

stable_sort()排序有两个重载函数,下面我们通过代码向读者简要展示其参数和功能:

/*此处beg意为起始位置,end意为结束位置,两者可为数组指针或迭代器,排序区间为[beg,end)*/ 
   stable_sort(beg,end);//默认是升序排序
   stable_sort(beg,end,cmp());//额外增加仿函数cmp进行自定义比较

我们通过stable_sort()分别对普通数组和vector容器进行基础数据排序和自定义数据排序。

#include<iostream>
#include<vector>
#include<string>
#include<algorithm>//包含算法头文件! 
/* 对普通数组和vector容器进行基础数据排序和自定义数据排序 */
using namespace std;
/*自定义数据*/ 
struct dotcpp_user
{
bool operator<(const dotcpp_user&u)const
{
return grade<u.grade;
}
string name;//姓名 
int age;//年龄 
int grade;//做题个数 
bool is_online;//是否在线 
};
/*基础数据类型仿函数*/ 
struct cmp_basic
{
bool operator()(const int &a,const int &b)const
{
return a>b;
}
};
/*自定义数据类型仿函数*/ 
struct cmp_diy
{
bool operator()(const dotcpp_user &u1,const dotcpp_user &u2)const
{
return u1.grade>u2.grade;
}
};
/*--基本数据类型&&默认升序排序--*/ 
void test1()
{
cout << "---------------------------------------------\n" ;
cout<< "处理基本数据类型,且遵循默认排序规则:\n";
   cout << "无序状态:{4,5,3,1,2}\n" ; 
   int a[]={4,5,3,1,2};
   vector<int> v{4,5,3,1,2};
   stable_sort(&a[0],&a[4]+1);//数组 
   stable_sort(v.begin(),v.end());//vector容器 
   cout << "a数组:"; 
   for(int i=0;i<5;++i)cout << a[i]  << " ";
   cout << '\n'; 
   cout << "vector容器:"; 
   for(auto i=v.begin();i!=v.end();++i)cout << *i  << " ";
   cout << '\n';
   cout << "---------------------------------------------\n" ;
} 
/*--基本数据类型&&自定义降序排序--*/ 
void test2()
{
cout << "---------------------------------------------\n" ;
cout<< "处理基本数据类型,且自定义降序排序:\n";
   cout << "无序状态:{4,5,3,1,2}\n" ; 
   int a[]={4,5,3,1,2};
   vector<int> v{4,5,3,1,2};
   stable_sort(&a[0],&a[4]+1,cmp_basic());//数组 
   stable_sort(v.begin(),v.end(),cmp_basic());//vector容器 
   cout << "a数组:"; 
   for(int i=0;i<5;++i)cout << a[i]  << " ";
   cout << '\n'; 
   cout << "vector容器:"; 
   for(auto i=v.begin();i!=v.end();++i)cout << *i  << " ";
   cout << '\n';
   cout << "---------------------------------------------\n" ;
} 
/*--自定义数据类型&&默认升序排序--*/ 
void test3()
{
cout << "---------------------------------------------\n" ;
cout<< "处理自定义数据类型,且遵循默认排序规则:\n";
   cout << "无序状态:{4,5,3,1,2}\n" ; 
   /*创建复杂对象*/
dotcpp_user u1{"user01",18,100,true};
dotcpp_user u2{"user02",18,200,true};
dotcpp_user u3{"user03",18,300,true};
dotcpp_user u4{"user04",18,400,true};
dotcpp_user u5{"user05",18,500,true};
   dotcpp_user a[]={u4,u5,u3,u1,u2};
   vector<dotcpp_user> v{u4,u5,u3,u1,u2};
   stable_sort(&a[0],&a[4]+1);//数组 
   stable_sort(v.begin(),v.end());//vector容器 
   cout << "a数组:"; 
   for(int i=0;i<5;++i)cout << a[i].name  << " ";
   cout << '\n'; 
   cout << "vector容器:"; 
   for(auto i=v.begin();i!=v.end();++i)cout << i->name << " ";
   cout << '\n';
   cout << "---------------------------------------------\n" ;
} 
/*--自定义数据类型&&自定义降序排序--*/ 
void test4()
{
cout << "---------------------------------------------\n" ;
cout<< "处理自定义数据类型,且自定义降序排序:\n";
   cout << "无序状态:{4,5,3,1,2}\n" ; 
   /*创建复杂对象*/
dotcpp_user u1{"user01",18,100,true};
dotcpp_user u2{"user02",18,200,true};
dotcpp_user u3{"user03",18,300,true};
dotcpp_user u4{"user04",18,400,true};
dotcpp_user u5{"user05",18,500,true};
   dotcpp_user a[]={u4,u5,u3,u1,u2};
   vector<dotcpp_user> v{u4,u5,u3,u1,u2};
   stable_sort(&a[0],&a[4]+1,cmp_diy());//数组 
   stable_sort(v.begin(),v.end(),cmp_diy());//vector容器 
   cout << "a数组:"; 
   for(int i=0;i<5;++i)cout << a[i].name  << " ";
   cout << '\n'; 
   cout << "vector容器:"; 
   for(auto i=v.begin();i!=v.end();++i)cout << i->name << " ";
   cout << '\n';
   cout << "---------------------------------------------\n" ;
} 
int main(){
system("title dotcpp.com");
    test1();
    test2();
    test3();
    test4();
    return 0;
}

编译结果如下:

stable_sort()

观察输出结果,我们成功使用stable_sort()模板函数对支持随机访问迭代器的容器和C风格的普通数组进行排序!

总结:使用模板函数stable_sort()前切记包含头文件<algorithm>,同时要知道stable_sort()能够作用于哪些容器。使用stable_sort()模板函数能够方便我们解决容器排序问题,同时在保证排序的情况下尽量让同等元素位置保持不变,对于编程竞赛这种类似的”一血“机制来说意义重大!

点赞(0)

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

Dotcpp在线编译      (登录可减少运行等待时间)