1. STL初步

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值