文章目录:
1.1 STL概述
1)STL:标准模板库
2)STL包含一些常用的算法如排序查找,还有常用的数据结构如可变长数组、链表、字典等
3)使用方便效率高
4)要使用其中的算法需要#include<algorithm>
1.2 排序算法sort
1)用法1:
(1)对基本类型数组从小到大排序:
sort(数组名+n1, 数组名+n2);
(2)n1和n2都是int类型的表达式,可以包含变量
(3)如果n1等于0可以不写
(4)将数组下标区间为[n1,n2)的元素从小到大排序,下标为n2的元素不在排序范围内
int a[7] = {11,22,3,5,15,5,4};
sort(a, a+7); //对整个数组排序
sort(a, a+3); //对0-2排序
sort(a+2,a+5); //对2-4排序
2)用法2:
(1)对元素类型为T的基本数据类型从大到小排序:
sort(数组名+n1, 数组名+n2,greater<T>());
int a[7] = {11,22,3,5,15,5,4};
sort(a+1,a+4,greater<int>()); //对1-3从大到小排序
3)用法3:
(1)用自定义的排序规则,对任何数据类型T的数组排序:
sort(数组名+n1, 数组名+n2,排序规则结构());
(2)排序规则结构的定义方式:
struct 结构名{
bool operator()( const T & a1, const T & a2){
//若a1在a2前面则返回true,否则返回false
}
};
(3)举例如下:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
struct Rule1{ //从大到小排
bool operator()(const int & a1, const int & a2){
return a1 > a2;
}
};
struct Rule2{ //按照各位从小到大排
bool operator()(const int & a1, const int & a2){
return a1%10 < a2%10;
}
};
void Print(int a[], int length){
for (int i = 0; i < length; i++){
cout << a[i] <<" ";
}
cout << endl;
}
int main(){
int a[] = {3,5,1,34,25,35};
sort(a, a + sizeof(a) / sizeof(int)); //从小到大排序
Print(a, sizeof(a) / sizeof(int));
sort(a, a + sizeof(a) / sizeof(int), Rule1() ); //从大到小排序
Print(a, sizeof(a) / sizeof(int));
sort(a, a + sizeof(a) / sizeof(int), Rule2() ); //个位数从小到大排
Print(a, sizeof(a) / sizeof(int));
return 0;
}
#include <iostream>
#include <cstring>
#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 & a1, const Student & a2){
if ( strcmp(a1.name,a2.name) < 0)
return true;
return false;
}
};
struct StudentRule2{ //按照id从小到大排
bool operator()(const Student & a1, const Student & a2){
return a1.id < a2.id;
}
};
struct StudentRule3{ //按照gpa从大到小排
bool operator()(const Student & a1, const Student & a2){
return a1.gpa > a2.gpa;
}
};
void Print(Student a[], int length){
for (int i = 0; i < length; i++){
cout << "( " << a[i].name << "," << a[i].id << "," << a[i].gpa << " )";
}
cout << endl;
}
int main(){
int length = sizeof(students)/sizeof(Student);
sort(students,students + length, StudentRule1()); //按姓名从小到大排序
Print(students, length);
sort(students,students + length, StudentRule2()); //按id从小到大排序
Print(students, length);
sort(students,students + length, StudentRule3()); //按gpa从大到小排序
Print(students, length);
}
输出:
( Ala,333,3.5 ) ( Jack,112,3.4 ) ( Mary,102,3.8 ) ( Mary,117,3.9 ) ( Zero,101,4 )
( Zero,101,4 ) ( Mary,102,3.8 ) ( Jack,112,3.4 ) ( Mary,117,3.9 ) ( Ala,333,3.5 )
( Zero,101,4 ) ( Mary,117,3.9 ) ( Mary,102,3.8 ) ( Ala,333,3.5 ) ( Jack,112,3.4 )
1.3 二分查找算法
1)STL提供在排好顺序的数组上进行二分查找的算法
binary_search
lower_search
upper_search
1.3.1 binary_search算法
1)用法1:在从小到大排序好的基本数据类型数组中进行二分查找
binary_search(数组名+n1, 数组名+n2,值);
2)在下标区间为[n1,n2),不包含n2的区间查找等于值得元素,找到返回true,找不到返回false
3)等于的含义:a < b和a > b都不成立
4)用法2:再用自定义排序规则排序好的,元素类型为任意T类型的数组进行二分查找
binary_search(数组名+n1, 数组名+n2,值,排序规则结构名());
5)在下标区间为[n1,n2),不包含n2的区间查找等于值得元素,找到返回true,找不到返回false
6)等于的含义:a < b和a > b都不成立
7)查找时的排序规则必须和排序时的规则一致!!!
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
struct Rule{ //按照各位从小到大排
bool operator()(const int & a1, const int & a2){
return a1%10 < a2%10;
}
};
void Print(int a[], int length){
for (int i = 0; i < length; i++){
cout << a[i] <<" ";
}
cout << endl;
}
int main(){
int a[] = {3,5,1,34,25,35};
sort(a, a + sizeof(a) / sizeof(int)); //从小到大排序
Print(a, sizeof(a) / sizeof(int));
cout << "result:" <<binary_search(a, a + 6 , 34) << endl;
cout << "result:" <<binary_search(a, a + 6 , 54) << endl;
sort(a, a + sizeof(a) / sizeof(int), Rule() ); //个位数从小到大排
Print(a, sizeof(a) / sizeof(int));
cout << "result:" <<binary_search(a, a + 6 , 34, Rule()) << endl;
cout << "result:" <<binary_search(a, a + 6 , 4, Rule()) << endl;
return 0;
}
#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 & a1, const Student & a2){
if ( strcmp(a1.name,a2.name) < 0)
return true;
return false;
}
};
struct StudentRule2{ //按照id从小到大排
bool operator()(const Student & a1, const Student & a2){
return a1.id < a2.id;
}
};
struct StudentRule3{ //按照gpa从大到小排
bool operator()(const Student & a1, const Student & a2){
return a1.gpa > a2.gpa;
}
};
void Print(Student a[], int length){
for (int i = 0; i < length; i++){
cout << "( " << a[i].name << "," << a[i].id << "," << a[i].gpa << " )";
}
cout << endl;
}
int main(){
Student s;
strcpy(s.name, "Jack");
s.id = 117;
s.gpa = 3.6;
int length = sizeof(students)/sizeof(Student);
sort(students,students + length, StudentRule1()); //按姓名从小到大排序
Print(students, length);
cout << "result:" << binary_search(students, students + length, s ,StudentRule1()) << endl;
sort(students,students + length, StudentRule2()); //按id从小到大排序
Print(students, length);
cout << "result:" << binary_search(students, students + length, s ,StudentRule2()) << endl;;
sort(students,students + length, StudentRule3()); //按gpa从大到小排序
Print(students, length);
cout << "result:" << binary_search(students, students + length, s ,StudentRule3()) << endl;
}
输出:
( Ala,333,3.5 )( Jack,112,3.4 )( Mary,102,3.8 )( Mary,117,3.9 )( Zero,101,4 )
result:1
( Zero,101,4 )( Mary,102,3.8 )( Jack,112,3.4 )( Mary,117,3.9 )( Ala,333,3.5 )
result:1
( Zero,101,4 )( Mary,117,3.9 )( Mary,102,3.8 )( Ala,333,3.5 )( Jack,112,3.4 )
result:0
1.3.2 lower_search算法 (大于等于)
1)用法1:对基本数据类型T的从小到大排序好的数组进行查找
T * lower_bound(数组名+n1, 数组名+n2,值);
2)返回一个指针T * p,*p是查找区间下标最小的,大于等于值得元素,如果找不到,p指向下标为n2的元素
3)在元素类型为任意T类型,按照自定义的排序规则排好序的数组中查找
T * lower_bound(数组名+n1, 数组名+n2,值, 排序规则结构名());
4)返回一个指针T * p,*p是查找区间下标最小的,可以排在值后面的元素,如果找不到,p指向下标为n2的元素
1.3.3 upper_bound算法(大于)
1)用法1:对基本数据类型T的从小到大排序好的数组进行查找
T * upper_bound(数组名+n1, 数组名+n2,值);
2)返回一个指针T * p,*p是查找区间下标最小的,大于等于值得元素,如果找不到,p指向下标为n2的元素
3)在元素类型为任意T类型,按照自定义的排序规则排好序的数组中查找
T * upper_bound(数组名+n1, 数组名+n2,值, 排序规则结构名());
4)返回一个指针T * p,*p是查找区间下标最小的,必须排在值后面的元素,如果找不到,p指向下标为n2的元素
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
struct Rule{ //按照各位从小到大排
bool operator()(const int & a1, const int & a2){
return a1%10 < a2%10;
}
};
void Print(int a[], int length){
for (int i = 0; i < length; i++){
cout << a[i] <<" ";
}
cout << endl;
}
int main(){
int a[] = {3,5,1,34,25,35};
a[6] = 10000;
sort(a, a + sizeof(a) / sizeof(int)); //从小到大排序
Print(a, sizeof(a) / sizeof(int));
cout << "result:" <<*lower_bound(a, a + 6 , 34) << endl;
cout << "result:" <<*upper_bound(a, a + 6 , 4) << endl;
sort(a, a + sizeof(a) / sizeof(int), Rule() ); //个位数从小到大排
Print(a, sizeof(a) / sizeof(int));
cout << "result:" <<*lower_bound(a, a + 6 , 34, Rule()) << endl;
cout << "result:" <<*upper_bound(a, a + 6 , 4, Rule()) << endl;
return 0;
}
输出:
1 3 5 25 34 35
result:34
result:5
1 3 34 5 25 35
result:34
result:5
1.4 STL中的平衡二叉树
1)有时需要在大量增加、删除数据的同时,还要进行大量的查找
2)希望增加数据、删除数据、查找数据都能在logn复杂度完成
3)排序+二分查找显然不行,因为插入数据就要重新排序
4)可以使用平衡二叉树数据结构,体现在STL中就是:multiset、set、multimap、map
1.4.1 multiset容器
1)用法:multiset< T > st;
2)定义了一个multimap变量st,st里面可以存放T类型的数据,并且能够自动排序,开始时st为空,可以有元素重复
3)排序规则:表达式 a < b 为true,则a排在b前面
4)可用st.insert插入数据,使用st.find查找数据,st.erase删除元素,复杂度都是logn
5)使用示例:
#include <iostream>
#include <cstring>
#include <set> //使用multiset和set需要此头文件
using namespace std;
int main(){
int a[] = {3,5,1,34,25,35};
multiset<int> st;
for (int i = 0; i < 6; i++){
st.insert(a[i]); //插入的是a[i]的复制品
}
multiset<int>::iterator i; //迭代器,类似于指针
for (i = st.begin(); i != st.end(); i++){
cout << *i << " "; //输出1 3 5 25 34 35
}
cout << endl;
i = st.find(4);
if ( i == st.end()){
cout << "not found!" << endl;
}
st.insert(4);
for (i = st.begin(); i != st.end(); i++){
cout << *i << " "; //输出1 3 4 5 25 34 35
}
cout << endl;
i = st.find(4);
if ( i == st.end()){
cout << "not found!" << endl;
}
else{ //找到就返回找到的元素的迭代器
cout << "found:" << *i <<endl;
}
i= st.lower_bound(4); //大于等于
cout << "found(大于等于):" << *i <<endl;
i = st.upper_bound(4); //大于
cout << "found(大于):" <<*i << endl;
st.erase(i); //删除迭代器i指向的 即5
for (i = st.begin(); i != st.end(); i++){
cout << *i << " "; //输出1 3 4 25 34 35
}
return 0;
}
6)multiset上的迭代器:multiset< T > st;
(1)st.begin()返回类型为multiset< T >::iterator,是指向st中的第一个元素的迭代器
(2)st.end()返回值类型为multiset< T >::iterator,是指向st中的最后一个元素的迭代器
(3)对迭代器++,就能指向容器中的下一个元素,–就指向前一个元素
7)自定义排序规则的multiset用法:
#include <iostream>
#include <cstring>
#include <set> //使用multiset和set需要此头文件
using namespace std;
struct Rule{ //按照各位从小到大排
bool operator()(const int & a1, const int & a2){
return a1%10 < a2%10;
}
};
int main(){
int a[] = {3,5,1,34,25,35};
multiset<int, greater<int>> st1; //从大到小排
for (int i = 0; i < 6; i++){
st1.insert(a[i]); //插入的是a[i]的复制品
}
multiset<int>::iterator i; //迭代器,类似于指针
for (i = st1.begin(); i != st1.end(); i++){
cout << *i << " "; //输出1 3 5 25 34 35
}
cout << endl;
multiset<int,Rule> st2;
for ( int i = 0; i <6 ; i++){
st2.insert(a[i]);
}
multiset<int,Rule> ::iterator p;
for ( p = st2.begin(); p != st2.end(); p++){
cout << *p << " ";
}
cout << endl;
p = st2.find(14445);
cout << *p <<endl; //输出5 因为排序规则为按照个位数排
return 0;
}
#include <iostream>
#include <cstring>
#include <algorithm>
#include <set>
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 Rule{ //按照id从小到大排
bool operator()(const Student & a1, const Student & a2){
return a1.id < a2.id;
}
};
void Print(Student a[], int length){
for (int i = 0; i < length; i++){
cout << "( " << a[i].name << "," << a[i].id << "," << a[i].gpa << " )";
}
cout << endl;
}
int main(){
multiset<Student,Rule> st;
for ( int i = 0; i < 5; i++){
st.insert(students[i]);
}
multiset<Student,Rule>::iterator p;
for (p = st.begin(); p != st.end(); p++){
cout << p->name << " " << p->id << " " << p->gpa << endl;
}
Student s = {"Mary" , 117, 4.5};
p = st.find(s); //按照什么排序就按照什么查找
cout << p->name << " " << p->id << " " << p->gpa << endl;
return 0;
}
输出:
Zero 101 4
Mary 102 3.8
Jack 112 3.4
Mary 117 3.9
Ala 333 3.5
Mary 117 3.9
1.4.2 set容器
1)和multiset的区别在于不能有重复元素
2)set插入可能不成功(插入重复元素不成功)
3)set的用法:
#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
int main(){
int a[] = {1,4,4,2,3,7,6,5};
set<int> st;
for ( int i = 0; i < 8 ;i++){
st.insert(a[i]);
}
cout << st.size() <<endl; //输出7
set<int>::iterator i;
for ( i = st.begin(); i != st.end(); i++){
cout << *i << " ";
}
cout << endl;
pair<set<int>::iterator, bool> res = st.insert(7); //插入7失败,因为7已经存在 且返回值为pair
if ( !res.second){
cout << *res.first << " already exists." << endl;
}
else{
cout << *res.first << " inserted." << endl;
}
return 0;
}
输出:
7
1 2 3 4 5 6 7
7 already exists.
1.4.3 multimap和map容器
1)multimap里的元素都是以pair的形式存在的:multimap<T1, T2> mp;
2)mp里的元素都是如下类型:
struct {
T1 first; //关键字
T2 second; //值
};
3)multimap中的元素都是按照first排序,并且可以按照first进行查找
4)缺省的排序规则为“a.first < b.first”为true,则a排在b前面
4)插入方式:mp.insert(make_pair(first,second)); 其余的和set相同
5)map和multimap的区别在于:
(1)不能有关键字重复
(2)可以使用[ ]访问元素,返回值为first和关键字相同的元素的second
(3)插入元素可能失败
(4)插入元素方式还可以使用:mp[first] = second;
6)map例题:单词数量统计
输入大量单词,每个单词一行,不超过20个字符,没有空格,按照出现次数从多到少输出单词。出现次数相同的,字典序靠前的在前面
#include <iostream>
#include <algorithm>
#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){
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)
++mp[s];
for (auto i = mp.begin(); i != mp.end(); i++){
Word tmp;
tmp.wd = i->first;
tmp.times = i->second;
st.insert(tmp);
}
for (auto i = st.begin(); i != st.end(); i++){
cout << i->wd << " " << i->times << endl;
}
return 0;
}
输入:
刘东洋
刘海洋
刘东洋
托尼
输出:
刘东洋 2
托尼 1
刘海洋 1