程序设计与算法 | (21) STL初步

本专栏主要基于北大郭炜老师的程序设计与算法系列课程进行整理,包括课程笔记和OJ作业。该系列课程有三部分: (一) C语言程序设计;(二) 算法基础;(三) C++面向对象程序设计

(一) C语言程序设计 课程链接

1. STL概述

  • STL: (Standard Template Library) 标准模板库
  • 包含一些常用的算法如排序查找,还有常用的数据结构如可变长数组、链表 、字典等。
  • 使用方便,效率较高
  • 要使用其中的算法,需要#include

2. 排序算法 sort

用sort进行排序(用法一)

sort()基于快速排序。

  • 对基本类型的数组从小到大排序:

sort(数组名+n1,数组名+n2);
n1和n2都是int类型的表达式,可以包含变量
如果n1=0,则 + n1可以不写
将数组中下标范围为[n1,n2)的元素从小到大排序。下标为n2的元素不在排序区间内

int a[] = {15,4,3,9,7,2,6};
sort(a,a+7); //对整个数组从小到大排序  a[0]~a[6]

int a[] = {15,4,3,9,7,2,6};
sort(a,a+3); // 结果:{3,4,15,9,7,2,6}    a[0]~a[2]

int a[] = {15,4,3,9,7,2,6}; 
sort(a+2,a+5); //结果:{15,4,3,7,9,2,6}   a[2]~a[4]
用sort进行排序(用法二)
  • 对元素类型为T的基本类型数组从大到小排序:

sort(数组名+n1,数组名+n2,greater());

int a[] = {15,4,3,9,7,2,6}; 
sort(a+1,a+4,greater<int>()); // 结果:{15,9,4,3,7,2,6} a[1]~a[3] 从大到小
用sort进行排序(用法三)
  • 用自定义的排序规则,对任何类型T(包括基本类型和自定义类型)的数组排序

sort(数组名+n1,数组名+n2,排序规则结构名());

  • 排序规则结构的定义方式:
struct 结构名 {
	bool operator()( const T & a1,const T & a2) const { 
	//若a1应该在a2前面,则返回true。
	//否则返回false。
	} 
};

排序规则返回 true,意味着 a1 必须在 a2 前面;返回 false,意味着 a1 并非必须在 a2 前面.
排序规则的写法,不能造成比较 a1,a2 返回 true;比较 a2,a1 也返回 true。否则sort会 runtime error
比较 a1,a2 返回 false 比较 a2,a1 也返回 false,则没有问题。

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

//自定义排序规则
struct Rule1 //按从大到小排序 
{
	bool operator()( const int & a1,const int & a2) const { 
		return a1 > a2; //为true是 a1必须在a2前面
	} 
};

struct Rule2 //按个位数从小到大排序 
{
	bool operator()( const int & a1,const int & a2) const { 
		return a1%10 < a2%10;
	} 
};

void Print(int a[],int size) {
	for(int i = 0;i < size;++i)
		cout << a[i] << "," ; 
	cout << endl;
}

int main()
{
	int a[] = { 12,45,3,98,21,7}; 
	sort(a,a+sizeof(a)/sizeof(int)); //从小到大
	cout << "1) "; Print(a,sizeof(a)/sizeof(int)); 
	sort(a,a+sizeof(a)/sizeof(int),Rule1()); //从大到小
	cout << "2) "; Print(a,sizeof(a)/sizeof(int));
	sort(a,a+sizeof(a)/sizeof(int),Rule2()); //按个位数从小到大 
	cout << "3) "; Print(a,sizeof(a)/sizeof(int));
	return 0;
}

在这里插入图片描述

用sort对结构数组(自定义类型数组)进行排序(用法3)
#include <iostream> 
#include <cstring> 
#include <algorithm> 
using namespace std;

struct Student {
	char name[20]; 
	int id;
	double gpa
};

Student students [] = {{"Jack",112,3.4},{"Mary",102,3.8},{"Mary",117,3.9}, {"Ala",333,3.5},{"Zero",101,4.0}};

//排序规则
struct StudentRule1 { //按姓名从小到大排
	bool operator() (const Student & s1,const Student & s2) const {
		if( stricmp(s1.name,s2.name) < 0)
			return true;
		return false;
	}
};

struct StudentRule2 { //按id从小到大排
	bool operator() (const Student & s1,const Student & s2) const {
               return s1.id < s2.id;
	} 
};

struct StudentRule3 {//按gpa从高到低排
	bool operator() (const Student & s1,const Student & s2) const {
		return s1.gpa > s2.gpa;
	}
};

void PrintStudents(Student s[],int size){
	for(int i = 0;i < size;++i)
		cout << "(" << s[i].name << ","
               << s[i].id <<"," << s[i].gpa << ") " ;
    cout<<endl;
}

int main()
{
	int n = sizeof(students) / sizeof(Student);
	sort(students,students+n,StudentRule1()); //按姓名从小到大排 
	PrintStudents(students,n); 
	sort(students,students+n,StudentRule2()); //按id从小到大排 
	PrintStudents(students,n); 
	sort(students,students+n,StudentRule3()); //按gpa从高到低排 
	PrintStudents(students,n);
	return 0;
}

3. 二分查找算法

  • STL提供在排好序的数组上进行二分查找的算法

binary_search
lower_bound
upper_bound

用binary_search进行二分查找(用法一)
  • 在从小到大排好序的基本类型数组上进行二分查找

binary_search(数组名+n1,数组名+n2,值);
n1和n2都是int类型的表达式,可以包含变量
如果n1=0,则 + n1可以不写

查找区间为下标范围为[n1,n2)的元素,下标为n2的元素不在查找区间内
在该区间内查找"等于"值的元素,返回值为true(找到)或false(没找到)

"等于"的含义: a 等于 b <=> a < b和b < a都不成立

用binary_search进行二分查找(用法二)
  • 在用自定义排序规则排好序的、元素为任意的T类型的数组中进行二分查找

binary_search(数组名+n1,数组名+n2,值,排序规则结构名());
n1和n2都是int类型的表达式,可以包含变量
如果n1=0,则 + n1可以不写

查找区间为下标范围为[n1,n2)的元素,下标为n2的元素不在查找区间内
在该区间内查找"等于"值的元素,返回值为true(找到)或false(没找到)

查找时的排序规则,必须和排序时的规则一致! (否则就算有结果,也没有意义)

"等于"的含义: a 等于 b <=> "a必须在b前面"和"b必须在a前面"都不成立

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

//排序规则
struct Rule //按个位数从小到大排 {
	bool operator()( const int & a1,const int & a2) const { 
		return a1%10 < a2%10;
	}
};

void Print(int a[],int size) {
	for(int i = 0;i < size;++i)
		cout << a[i] << "," ; 
	cout << endl;
}

int main()
{
	int a[] = { 12,45,3,98,21,7};
	sort(a,a+6); //排序时的规则 默认从小到大排序
	Print(a,6);
	cout <<"result:"<< binary_search(a,a+6,12) << endl; //查找的排序规则默认是从小到大排序
	cout <<"result:"<< binary_search(a,a+6,77) << endl;
	sort(a,a+6,Rule()); //按个位数从小到大排
	Print(a,6);
	cout <<"result:"<< binary_search(a,a+6,7) << endl; //查找的排序规则默认是从小到大排序,而此时排序的规则时 按个位数从小到大排。 不一致,结果无意义。
	cout <<"result:"<< binary_search(a,a+6,8,Rule()) << endl; //返回true可以找到,也就是98 因为按个位数从小到大排序时,98必须排在8前面不成立 8必须排在98前面也不成立 
}

"等于"的含义: a 等于 b <=> "a必须在b前面"和"b必须在 a前面"都不成立

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

struct Student {
	char name[20]; 
	int id;
	double gpa;
};

Student students [] = { {"Jack",112,3.4},{"Mary",102,3.8},{"Mary",117,3.9}, {"Ala",333,3.5},{"Zero",101,4.0}};

//排序规则
//排序规则
struct StudentRule1 { //按姓名从小到大排
	bool operator() (const Student & s1,const Student & s2) const {
		if( stricmp(s1.name,s2.name) < 0)
			return true;
		return false;
	}
};

struct StudentRule2 { //按id从小到大排
	bool operator() (const Student & s1,const Student & s2) const {
               return s1.id < s2.id;
	} 
};

struct StudentRule3 {//按gpa从高到低排
	bool operator() (const Student & s1,const Student & s2) const {
		return s1.gpa > s2.gpa;
	}
};

int main()
{
	Student s;
	strcpy(s.name,"Mary");
	s.id= 117;
	s.gpa = 0;
	int n = sizeof(students) / sizeof(Student);
	sort(students,students+n,StudentRule1()); //按姓名从小到大排
	cout << binary_search( students , students+n,s,StudentRule1()) << endl; //true可以找到 只按名字来找 
	strcpy(s.name,"Bob");
	cout << binary_search( students , students+n,s,StudentRule1()) << endl; //false
	sort(students,students+n,StudentRule2()); //按id从小到大排
	cout << binary_search( students , students+n,s, StudentRule2()) << endl; //true可以找到 只按id来找 
}
用lower_bound二分查找下界(用法一)
  • 对元素类型为T的从小到大排好序的基本类型的数组中进行查找

T * lower_bound(数组名+n1,数组名+n2,值);

返回一个指针 T * p;
*p 是查找区间里下标最小的,大于等于"值" 的元素。如果找不到,p指向下标为n2的元素

用lower_bound二分查找下界(用法二)
  • 在元素为任意的T类型、按照自定义排序规则排好序的数组中进行查找

T * lower_bound(数组名+n1,数组名+n2,值,排序规则结构名());

返回一个指针 T * p;
*p 是查找区间里下标最小的,按自定义排序规则,可以排在"值"后面的元素。如果找 不到,p指向下标为n2的元素。

用upper_bound二分查找上界(用法一)
  • 在元素类型为T的从小到大排好序的基本类型的数组中进行查找

T * upper_bound(数组名+n1,数组名+n2,值);

返回一个指针 T * p;
*p 是查找区间里下标最小的,大于"值"的元素。如果找不到,p指向下标为n2的元素

用upper_bound二分查找上界(用法二)
  • 在元素为任意的T类型、按照自定义排序规则排好序的数组中进行查找

T * upper_bound(数组名+n1,数组名+n2,值,排序规则结构名());

返回一个指针 T * p;
*p 是查找区间里下标最小的,按自定义排序规则,必须排在"值"后面的元素。如果找 不到,p指向下标为n2的元素

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

//排序规则
struct Rule //按个位数从小到大排 {
	bool operator()( const int & a1,const int & a2) const { 
		return a1%10 < a2%10;
	}
};

void Print(int a[],int size) {
	for(int i = 0;i < size;++i)
		cout << a[i] << "," ; 
	cout << endl;
}

#define NUM 7
int main()
{
	int a[NUM] = { 12,5,3,5,98,21,7};
	sort(a,a+NUM); //默认从小到大
	Print(a,NUM); // => 3,5,5,7,12,21,98,
	int * p = lower_bound(a,a+NUM,5); //返回指向 下标最小的 >=5的元素
	cout << *p << "," << p-a << endl; //=> 5,1
	p = upper_bound(a,a+NUM,5); //返回指向 下标最小的 >5的元素
	cout << *p << endl; //=>7
	cout << * upper_bound(a,a+NUM,13) << endl; //=>21 //下标最小的 >13的元素
	sort(a,a+NUM,Rule()); //按个位数从小到大排
	Print(a,NUM); //=>21,12,3,5,5,7,98,
	cout << * lower_bound(a,a+NUM,16,Rule()) << endl; // 7 下标最小的 按照个位数排序 可以排在16后面的元素 
	cout << lower_bound(a,a+NUM,25,Rule()) - a<< endl; // 3
	cout << upper_bound(a,a+NUM,18,Rule()) - a << endl; //  7 没有找到  a+NUM-a
	if( upper_bound(a,a+NUM,18,Rule()) == a+NUM) //超过查找范围
		cout << "not found" << endl; //=> not found
	cout << * upper_bound(a,a+NUM,5,Rule()) << endl; // =>7 下标最小的 按照个位数排序 必须排在5后面的元素 
	cout << * upper_bound(a,a+NUM,4,Rule()) << endl; // =>5 下标最小的 按照个位数排序 必须排在4后面的元素 
	return 0;
}

4. STL中的平衡二叉树

  • 有时需要在大量增加、删除数据的同时, 还要进行大量数据的查找
  • 希望增加数据、删除数据、查找数据都能在 log(n)复杂度完成
  • 排序+二分查找显然不可以,因加入新数据就要重新排序
  • 可以使用“平衡二叉树”数据结构存放数据,体现在STL中,就是以 下四种“排序容器” :

multiset set multimap map

如果固定死数据量,没有删除和新插入的数据,那么可以用排序+二分查找,如果有新加入的数据,这种方法必须重新排序,效率很低。而以上四种容器,插入新数据后,可以自动排序,插入数据、删除数据、查找数据都能在 log(n)复杂度完成。

5. multiset

multiset st;

  • 定义了一个multiset变量st,st里面可以存放T类型的数据,并且能自动排序。开始st为空
  • 排序规则:表达式 “a < b” 为true,则 a 排在 b 前面
  • 可用 st.insert添加元素,st.find查找元素,st.erase删除元素,复杂度 都是 log(n)
#include <iostream>
#include <cstring>
#include <set> //使用multiset和set需要此头文件 using namespace std;

int main()
{
	multiset<int> st; //默认从小到大排
	int a[10]={1,14,12,13,7,13,21,19,8,8 };
	for(int i = 0;i < 10; ++i)
		st.insert(a[i]); //插入的是a[i]的复制品
	multiset<int>::iterator i; //迭代器,近似于指针
	for(i = st.begin(); i != st.end(); ++i)
    	cout << * i << ","; //1,7,8,8,12,13,13,14,19,21,
    cout << endl;
    i = st.find(22); //查找22,返回值是迭代器
    if( i == st.end()) //找不到则返回值为 end()
    	cout << "not found" << endl;
    st.insert(22); //插入 22   插入新元素会自动排序 logn
    i = st.find(22);
    if( i == st.end())
    	cout << "not found" << endl;
     else
        cout << "found:" << *i <<endl; //找到则返回指向找到的元素的迭代器
     
    i = st.lower_bound(13); //返回最靠后的迭代器 it,使得[begin(),it)中的元素 都在 13 前面 ,复杂度 log(n)
    cout << * i << endl; //13   >=13 下标最小的
    i = st.upper_bound(8); //返回最靠前的迭代器 it,使得[it,end())中的元素都在 8 后面,复杂度 log(n)
    cout << * i << endl; //12 >8 下标最小的
    st.erase(i); //删除迭代器 i 指向的元素,即12
    for(i = st.begin(); i != st.end(); ++i)
    	cout << * i << ",";
    return 0;
}

multiset 上的迭代器

multiset::iterator p;

  • p是迭代器,相当于指针,可用于指向multiset中的元素。访问multiset中的元素要通 过迭代器。
  • 与指针的不同: multiset上的迭代器可 ++ ,–, 用 != 和 == 比较,不可比大小,不可加减整数,不 可相减

multiset st;

  • st.begin() 返回值类型为 multiset::iterator, 是指向st中的头一个元素的迭代器
  • st.end() 返回值类型为 multiset::iterator, 是指向st中的最后一个元素后面的迭代器
  • 对迭代器 ++ ,其就指向容器中下一个元素,-- 则令其指向上一个元素
自定义排序规则的multiset用法
#include <iostream> 
#include <cstring> 
#include <set>
using namespace std;

struct Rule1 {
	bool operator()( const int & a,const int & b) const {
		return (a%10) < (b%10); }//返回值为true则说明a必须排在b前面
};

int main()
{
	multiset<int,greater<int> > st; //排序规则为从大到小
	int a[10]={1,14,12,13,7,13,21,19,8,8 };
	for(int i = 0;i < 10; ++i)
    	st.insert(a[i]);
    multiset<int,greater<int> >::iterator i;
    for(i = st.begin(); i != st.end(); ++i)
		cout << * i << ","; 
	cout << endl; //21,19,14,13,13,12,8,8,7,1,
	multiset<int,Rule1 > st2; //排序规则为自定义排序规则 
	//st2的元素排序规则为:个位数小的排前面
	for(int i = 0;i < 10; ++i)
		st2.insert(a[i]);
	multiset<int,Rule1>::iterator p;
	for(p = st2.begin(); p != st2.end(); ++p)
		cout << * p << ",";
	cout << endl;
	p = st2.find(133); 
	cout << * p << endl; //13 按照个位数排序 13必须排在133前面不成立 133必须排在13前面也不成立
}

find(x): 在排序容器中找一个元素y,使得 “x必须排在y前面”和 “y必须排在x前面” 都不成立

 #include <iostream>
 #include <cstring>
 #include <algorithm>
 #include <set>

 using namespace std;
 struct Student {
       char name[20];
       int id;
       int score;
};

Student students [] = { {"Jack",112,78},{"Mary",102,85},
{"Ala",333,92},{"Zero",101,70},{"Cindy",102,78}};

struct Rule { //如果分数不一样 按分数从大到小排序 若分数一样,则按名字的字典序排序
	bool operator() (const Student & s1,const Student & s2) const { 
	if( s1.score != s2.score) 
		return s1.score > s2.score; 
	else 
		return (strcmp(s1.name,s2.name) < 0);
	} 
};

int main()
{
	multiset<Student,Rule> st; //自定义类型 自定义规则
	for(int i = 0;i < 5;++i)
		st.insert(students[i]); //插入的是students[i]的复制品
	multiset<Student,Rule>::iterator p;
	for(p = st.begin(); p != st.end(); ++p)
		cout << p->score <<" "<<p->name<<" "<< p->id <<endl;
	Student s = { "Mary",1000,85};
	p = st.find(s);  //查找时的排序规则 和 排序时一致。
	if( p!= st.end()) //找到了  
		cout << p->score <<" "<< p->name<<" " << p->id <<endl;//85 Mary 102 Rule和id无关    s = { "Mary",1000,85}和结构数组中的 { "Mary",102,85}按照规则 二者谁前谁后无所谓。 
	return 0;
}

6. set

set的用法
  • set和multiset的区别在于容器里不能有重复元素
    a和b重复 等价于 “a必须排在b前面” 和“b必须排在a前面”都不成立

  • set插入元素可能不成功

#include <iostream>
#include <cstring>
#include <set>
using namespace std;

int main()
{
	set<int> st;  //默认排序规则 从小到大
	int a[10] ={ 1,2,3,8,7,7,5,6,8,12 };
	for(int i = 0;i < 10; ++i)
		st.insert(a[i]);
	cout << st.size() << endl; //输出:8 去除了重复元素
	set<int>::iterator i;
	for(i = st.begin(); i != st.end(); ++i)
		cout << * i << ","; //输出:1,2,3,5,6,7,8,12,
	cout<<endl;
	pair<set<int>::iterator, bool> result = st.insert(2); //set的insert函数返回的是pair类型 pair类型的第一个元素是set迭代器类型 第二个元素是bool类型 表示插入是否成功
	if(! result.second ) //条件成立说明插入不成功
		cout << * result.first <<" already exists." << endl;
	else
		cout << * result.first << " inserted." << endl;
	return 0;	
}

在这里插入图片描述

pair模板的用法

pair<T1,T2>类型等价于:

struct {
	T1 first;
	T2 second;
}

例如:pair<int, double> a;
等价于:

struct {
	int first;
    double second;
} a;

a.first = 1; 
a.second = 93.93;

7. multimap

multimap的用法

multimap容器里的元素,都是pair形式的

multimap<T1,T2> mp;

则mp里的元素都是如下类型:

struct {
	T1 first; //关键字
	T2 second; //值
};

multimap中的元素按照first排序,并可以按first进行查找
缺省的排序规则是 “a.first < b.first” 为true,则a排在b前面

multimap的应用

一个学生成绩录入和查询系统,接受以下两种输入:
Add name id score
Query score

name是个不超过16字符的字符串,中间没有空格(可以用cin直接读),代表学生姓名。id 是个整数,代表学号。score是个整数,表示分数。学号不会重复,分数 和姓名都可能重复。

两种输入交替出现。第一种输入表示要添加一个学生的信息,碰到这 种输入,就记下学生的姓名、id和分数。第二种输入表示要查询,碰到这 种输入,就输出已有记录中分数比score低的最高分获得者的姓名、学号 和分数。如果有多个学生都满足条件,就输出学号最大的那个学生的信息。如果找不到满足条件的学生,则输出“Nobody”

在这里插入图片描述

 
#include <iostream>
#include <map> //使用multimap和map需要包含此头文件 
#include <cstring>
using namespace std;

struct StudentInfo {
	int id;
    char name[20];
};

struct Student { //按分数进行排序 和 查询 
	int score; 
    StudentInfo info;
};

typedef multimap<int,StudentInfo> MAP_STD;
// 此后 MAP_STD 等价于 multimap<int,StudentInfo> 更简便
//  typedef int * PINT;
//则此后PINT等价于int*。即PINTp;等价于 int*p;

int main()
{
	MAP_STD mp;
    Student st;
    char cmd[20];
	
	while( cin >> cmd ) {
		if( cmd[0] == 'A') { //添加学生信息
			cin >> st.info.name >> st.info.id >> st.score ;
		mp.insert(make_pair(st.score,st.info )); //成对插入
		} //make_pair生成一个 pair<int,StudentInfo>变量 //其first 等于 st.score, second 等于 st.info
		else if(  cmd[0] == 'Q' ){ //根据分数进行查询
			int score;
			cin >> score;
			MAP_STD::iterator p = mp.lower_bound (score); //迭代器指向 下标最小的 >=score的那个元素 
			if(p! = mp.begin()){ //我们要找的是比score小的最高分  
				--p; //往前移动一个元素
				score = p->first; //比要查询分数低的最高分
				MAP_STD::iterator maxp = p;
				int maxId = p->second.id; 
				for(; p != mp.begin() && p->first == score; --p) { //分数相同的话 找学号最大的
					if( p->second.id > maxId ) {
						maxp = p;
						maxId = p->second.id ;
					}
				}
					
				//如果上面循环是因为 p == mp.begin() 而终止,如果此时p指向的元素的score仍然相同,那么还要进行处理
				if(p->first == score){
					if( p->second.id > maxId ) {
                    	maxp = p;
                        maxId = p->second.id ;
					}
				}
				cout << maxp->second.name << " " << maxp->second.id << " "
                                << maxp->first << endl;
              }
              else
              	//lower_bound的结果就是 begin,说明没人分数比查询分数低
              	cout << "Nobody" << endl;
              }
        }
        return 0;			
}

8. map

map的用法

和multimap区别在于:

  • 不能有关键字重复的元素
  • 可以使用 [] ,下标为关键字,返回值为first和关键字相同的元素的second
  • 插入元素可能失败
#include <iostream> 
#include <map> 
#include <string>  //字符串对象
using namespace std;

struct Student {
	string name;
    int score;
};

Student students[5] = { {"Jack",89},{"Tom",74},{"Cindy",87},{"Alysa",87},{"Micheal",98}};

typedef map<string,int> MP;

int main()
{
	MP mp;
	for(int i = 0;i < 5; ++i)
		mp.insert(make_pair(students[i].name,students[i].score));
	cout << mp["Jack"] << endl; // 输出 89
	mp["Jack"] = 60; //修改名为"Jack"的元素的second
	for(MP::iterator i = mp.begin(); i != mp.end(); ++i)
		cout << "(" << i->first << "," << i->second << ") ";
	//输出:(Alysa,87) (Cindy,87) (Jack,60) (Micheal,98) (Tom,74)
	cout << endl;
	Student st;
	st.name = "Jack";
	st.score = 99;
	pair<MP::iterator, bool> p = mp.insert(make_pair(st.name,st.score));
	if( p.second ) //插入成功
    	cout << "(" << p.first->first << ","<< p.first->second << ") inserted" <<endl;
    else
    	cout << "insertion failed" << endl; //输出此信息
    mp["Harry"] = 78; //插入一元素,其first为"Harry",然后将其second改为78
    MP::iterator q = mp.find("Harry");
    cout << "(" << q->first << "," << q->second <<")" <<endl;
    //输出 (Harry,78)
    return 0;
}
map例题:单词词频统计程序

输入大量单词,每个单词,一行,不超过20字符,没有 空格。 按出现次数从多到少输出这些单词及其出现次数 。出现次数相同的,字典序靠前的在前面.

在这里插入图片描述

#include <iostream>
#include <set>
#include <map>
#include <string>
using namespace std;

struct Word {
     int times;
     string wd;
};

struct Rule {
	bool operator () ( const Word & w1,const Word & w2) const {
		if( w1.times != w2.times)
			return w1.times > w2.times;
		else
			 return w1.wd < w2.wd;
	}
}

int main()
{
	string s;
	set<Word,Rule> st; 
	map<string,int> mp;
	while( cin >> s )  //读入一个单词 插入map中,并统计出现次数 map的关键字是单词 值为出现的次数
		++ mp[s] ;
	for( map<string,int>::iterator i = mp.begin();i != mp.end(); ++i) {
		Word tmp;
		tmp.wd = i->first; tmp.times = i->second; 
		st.insert(tmp);
	}
	for(set<Word,Rule>::iterator i = st.begin();i != st.end(); ++i)
		cout << i->wd << " " << i->times << endl;
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值