the Set class
还有一个最有用的集合类,就是set(集合)类了,出口的方法如下图,这个类我们用来模拟数学上的集合,也就是说这个类里的元素是无序且其值只出现一次。set类在许多算法应用中是极其有用的。所以我们应该从一些实例中去体验和感受它们是怎么工作以及为什么在程序中如此有用。
先介绍一下set的常见的方法:
在这里我们再也不是用我们熟悉的pop跟push(push_back)函数来放入或者是取出元素了,我们用insert跟erase函数来进行一些的添加跟删除。
我们了解一下我们的常用方法吧:
方法 | 用法 |
---|---|
插入删除 | |
insert(value) | 向集合中插入一个元素 |
erase() | 擦除元素中的一个或者一段元素 |
clear() | 清除集合中的元素 |
查找 | |
find() | 查找value的值,返回下标位置,否则,返回最后一个元素后面一个位置(即迭代器的end) |
容量 | |
empty() | 判断集合是否为空 |
size() | 返回集合中的元素个数 |
max_size() | 返回集合的最大容量 |
迭代器 | |
begin() | 返回开头的迭代器 |
end() | 返回结尾的迭代器 |
rbegin() | 反向遍历的首个位置迭代器 |
rend() | 反向遍历的最后位置的迭代器 |
关于迭代器的介绍,看这个:C++抽象编程——STL(4)——vector类
Implementing the library
我们先来试试这些集合可以干什么吧,我们之前提过一个功能很强大的字符处理头文件,(详情见: C++抽象编程——字符串(3)——< cctype >库在字符串中的应用)想知道它是怎么实现的吗?具体的细节我们就不必要理解了,那么我们要做的是了解它是怎么样的一个思路吧。
我们可以举个例子,比如我们有个判断是不是数字的方法:
isdigit(ch)
实现起来很简单:
bool isdigit(ch) {
return ch >= '0' && ch <= '9';
}
但是用户往往输入的是一串的数字,所以我们可以建立一个集合,里面的元素为{0,1,2,3,4,5,6,7,8,9},我们可以检测ch在不在这个集合里面。那么我们沿着这个思路写出大概的代码:
#include <iostream>
#include <set>
#include <cctype>
using namespace std;
/*将字符串变为集合*/
set<char> setFromString(string str);
/*函数声明*/
bool isFind(char ch, set<char> DIGIT_SET);
bool isFind(char ch, set<char> LOWER_SET);
bool isFind(char ch, set<char> UPPER_SET);
bool isFind(char ch, set<char> PUNCT_SET);
bool isFind(char ch, set<char> SPACE_SET);
bool isFind(char ch, set<char> XDIGIT_SET);
/*定义集合*/
set<char> DIGIT_SET = setFromString("0123456789");
set<char> LOWER_SET = setFromString("abcdefghijklmnopqrstuvwxyz");
set<char> UPPER_SET = setFromString("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
set<char> PUNCT_SET = setFromString("!\"#$%&'()*+,-./:;<=>?@[\\]^_‘{|}");
set<char> SPACE_SET = setFromString(" \t\v\f\n\r");
set<char> XDIGIT_SET = setFromString("0123456789ABCDEFabcdef");
/*定义函数*/
bool isdigit(char ch) { return isFind(ch, DIGIT_SET); }
bool islower(char ch) { return isFind(ch, LOWER_SET); }
bool ispunct(char ch) { return isFind(ch, PUNCT_SET); }
bool isspace(char ch) { return isFind(ch, SPACE_SET); }
bool isupper(char ch) { return isFind(ch, UPPER_SET); }
bool isxdigit(char ch) { return isFind(ch, XDIGIT_SET); }
set<char> setFromString(string str) {
set<char> set;
for (int i = 0; i < str.length(); i++) {
set.insert(str[i]);
}
return set;
}
/*判断集合中是否存在该元素*/
bool isFind(char ch, set<char> DIGIT_SET) {
set<char>::iterator it;
it = DIGIT_SET.find(ch);
if(it != DIGIT_SET.end()) return true;
else return false;
}
......
在这里我们注意,这个文件我没有写main函数,所以是不能运行的。你可以自己添加main函数去试试这些功能。这里的最后我用省略号省略了一系列的isFind函数,因为后面的函数只是最后的参数的名字改一下就可以了。最后我觉得set< char > setFromString(string str) 这个方法很好,我们可以参考这个改一下类型,比如vector类,我们就可以简化输入。
再认真看看最后的isFind函数,这里有一行代码:
set<char>::iterator it;
it = DIGIT_SET.find(ch);
iterator是一个迭代器,::为域运算符,所以就是说迭代器it是set< char >类型的迭代器,因为我们前面的DIGIT_SET.find()函数返回的是迭代器,不是一个数值。
set集合的输入与输出
我们还可以再举例一个输入输出的简单例子:
第一,先参考vector,试试输出
先看看错误提示,no match for “operator[]”…,翻译过来就是没有匹配的[ ]运算符,那么常规方法不行,我们就试试它提供的迭代器来完成:
#include <iostream>
#include <set>
using namespace std;
int main(){
set<int> s;
set<int>::iterator it;
for(int i = 0; i <= 9; i++){
s.insert(i);
}
for(it = s.begin(); it != s.end(); it++)
cout << (*it) << " ";
/* it = s.find(5); /*查找键值为5的元素*
if(it != s.end()){ /*当it不为尾部的迭代器的时候,就找到了
cout << *it <<endl;
}else{
cout<<"不存在这个元素";
}*/
return 0;
}
输出的结果如图:
这里我有一个地方注释掉了,这里面就是find方法的运用,我就不上图了,有兴趣就取消注释来运行看看吧。接下来就介绍set的用途吧