“排序容器”:set 和 multiset、map和multimap
简单说就是可以将数据直接丢进容器里,容器会对数据按照一定的规则自动排序。
首先来说说set 和 multiset:set和multiset会根据特定的排序准则,自动将元素进行排序。不同的是后者允许元素重复而前者不允许。
排序规则:表达式 “a < b” 为true,则 a 排在 b 前面
可用 st.insert
添加元素,st.find
查找元素,st.erase
删除元素
multiset 上的迭代器
multiset<T>::iterator p;
multiset<T> st;
multiset关联的知识:
迭代器(类似指针)
p是迭代器,相当于指针,可用于指向multiset中的元素。访multiset中的元素要通过迭代器。
与指针的不同:
multiset上的迭代器可 ++ ,–, 用 != 和 == 比较,不可比大小,不可加减整数,不可相减。
st.begin()和st.end()
st.begin() 返回值类型为 multiset::iterator, 是指向st中的头一个元素的迭代器
st.end() 返回值类型为 multiset::iterator, 是指向st中的最后一个元素后面的迭代器
对迭代器 ++ ,其就指向容器中下一个元素,-- 则令其指向上一个元素
#include <iostream>
#include <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 << ",";
cout << endl;
迭代器的操作
i = st.find(22); //查找22,返回值是迭代器
if( i == st.end()) //找不到则返回值为 end()
cout << "not found" << endl;
st.insert(22); //插入 22
i = st.find(22);
if( i == st.end())
cout << "not found" << endl;
else
cout << "found:" << *i <<endl;
//找到则返回指向找到的元素的迭代器
接下来通过一个简单的代码,展示一下find的原理:
struct Rule1 {
bool operator()( const int & a,const int & b) const {
return (a%10) < (b%10);
}//返回值为true则说明a必须排在b前面
};
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;
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;
return 0;
}
此处"133==13"? 并不是这样,因为排序规则rule1是按照个位数的大小排序,一位133和13的个位数相同,因此编译器认为两数相等。
i = st.lower_bound(13);
//返回最靠后的迭代器 it,使得[begin(),it)中的元素都在 13 前面
cout << * i << endl;
i = st.upper_bound(8);
//返回最靠前的迭代器 it,使得[it,end())中的元素都在 8 后面
cout << * i << endl;
st.erase(i); //删除迭代器 i 指向的元素,即12
for(i = st.begin(); i != st.end(); ++i)
cout << * i << ",";
return 0;
}
binary_search、lower_bound与 upper_bound
在用自定义排序规则排好序的、元素为任意的T类型的数组中进行二分查找
binary_search(数组名+n1,数组名+n2,值);
binary_search(数组名+n1,数组名+n2,值,排序规则结构名());
n1和n2都是int类型的表达式,可以包含变量如果n1=0,则 + n1可以不写
查找区间为下标范围为[n1,n2)的元素,下标为n2的元素不在查找区间内
在该区间内查找"等于"值的元素,返回值为true(找到)或false(没找到)
查找时的排序规则,必须和排序时的规则一致!
关于binary_search()是怎样找到相同值的:
"等于"的含义: a 等于 b <=> "a必须在b前面"和"b必须在a前面"都不成立此处的"等于"和multiset中的find()原理类似,找的是临界,而不是确切的相等。
(1)在对元素类型为T的从小到大排好序的基本类型的数组中进行查找
T * lower_bound(数组名+n1,数组名+n2,值);
返回一个指针 T * p
*p 是查找区间里下标最小的,大于等于"值" 的元素。如果找不到,p指向下标为n2的元素(即最后一个无效元素后的位置)
(2)在元素为任意的T类型、按照自定义排序规则排好序的数组中进行查找
T * lower_bound(数组名+n1,数组名+n2,值,排序规则结构名());
返回一个指针 T * p
*p 是查找区间里下标最小的,按自定义排序规则,可以排在"值"后面的元素。如果找不到,p指向下标为n2的元素(即最后一个有效元素后的位置,即空)
(1)在元素类型为T的从小到大排好序的基本类型的数组中进行查找
T * upper_bound(数组名+n1,数组名+n2,值);
返回一个指针 T * p;
*p 是查找区间里下标最小的,大于"值"的元素。如果找不到,p指向下标为n2的元素(同上)
(2)在元素为任意的T类型、按照自定义排序规则排好序的数组中进行查找
T * upper_bound(数组名+n1,数组名+n2,值,排序规则结构名());
返回一个指针 T * p;
*p 是查找区间里下标最小的,按自定义排序规则,必须排在"值"后面的元素。如果找不到,p指向下标为n2的元素
set相关的知识
set和multiset的区别在于容器里不能有重复元素a和b重复 ,“a必须排在b前面” 和“b必须排在a前面”都不成立。
set插入元素可能不成功。(不能插入相同的元素)
#include <iostream>
#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);
if( ! result.second ) //条件成立说明插入不成功
cout << * result.first <<" already exists."<< endl;
else
cout << * result.first << " inserted." << endl;
return 0;
}
对于pair模板在这里,我有以下理解
插入2若插入成功返回true,否则返回false
然后通过迭代器指向插入的位置
此处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; 54