STL--set注意事项

混杂着记录的,可能会比较乱,但是都是一些有用的点

1.insert

pair<iterator, bool> insert(const value_type& x);
iterator insert(iterator position, const value_type& x);

单参数的insert: The first version return a pair, with its member pair::first set to an iterator pointing to either the newly inserted element or to the element that already had its same value in the set. The pair::second element in the pair is set to true if a new element was inserted or false if an element with the same value existed.

双参数的insert: The second version returns an iterator pointing to either the newly inserted element or to the element that already had its same value in the set.

双参数insert允许对x将要插入的位置的线索说明。如果线索给的精确,那么插入会很快。如果不精确的话就需要用常规的插入算法来完成,此时与单参数的insert相同。

	set<int> iSet1, iSet2;

	for (int i = 0; i < 100000; ++i)
		iSet1.insert(i);

	for (int i = 0; i < 100000; ++i)
		iSet2.insert(iSet2.end(), i);

单参数的耗时1856毫秒,双参数的耗时920毫秒,正确使用insert可以减少插入的时间。


2.set的第二个模板参数

默认情况下,排序操作使用less<Object>函数对象实现,而该函数对象是通过对Object调用operator<来实现的

比如判断相等:!(isLessThan(lhs, rhs) || isLessThan(rhs, lhs)) 

例如可以生成一个存储string对象的set,通过使用CaseInsensitiveCompare函数对象来忽略字符的大小写

class CaseInsensitiveCompare {
public:
	bool operator()(const string& lhs, const string& rhs) {
		return stricmp(lhs.c_str(), rhs.c_str()) < 0;
	}
};

int main()
{
	set<string, CaseInsensitiveCompare> s;
	
	s.insert("hello");
	s.insert("HellO");
	
	cout << s.size(); // 1

	return 0;
}
3.排序准则

⑴以template参数定义之

例如 std::set<int, std::greater<int> > coll;

这种情况下排序准则就是型别的一部分,因此型别系统确保“只有排序准则相同的容器才能被合并”。实际的排序准则是容器所产生的函数对象(functor,仿函数)。

class Person {
public:
	string firstname()const;
	string lastname()const;
};
class PersonSortCriterion {
public:
	bool operator()(const Person& p1, const Person& p2)const {
		/**
		 * p1的姓小于p2的姓
		 * 当姓相等时候p1的名字小于p2的名字
		 */
		return p1.lastname() < p2.lastname() ||
			((!(p2.lastname() < p1.lastname())) && p1.firstname() < p2.firstname());
	}
};

int main()
{
	typedef set<Person, PersonSortCriterion> PersonSet;

	PersonSet coll;

	PersonSet::iterator pos;
	for (pos = coll.begin(); pos != coll.end(); ++pos) {
		// ...
	}

	return 0;
}
这个就是仿函数,用类的operator()取代一般函数,一般函数无法做到成为一个类别。所以可以用仿函数来当set的template参数。

在coll的构造函数内会自动生成class PersonSortCriterion的一个实体,所有的元素都将以此为排序准则进行排序。

你无法将这个set拿来和“拥有不同排序准则”的其他set合并或互相赋值。

⑵以构造函数参数定义之。

这种情况下,同一个型别可以运用不同的排序准则,而排序准则的初始值或状态也可以不同。

如果执行期才获得排序准则,而且需要用到不同的排序准则(但数据型别必须相同),这个方法可以派上用场。

// type for sorting criterion
template <class T>
class RuntimeCmp {
public:
	enum cmp_mode{ normal, reverse };
private:
	cmp_mode mode;
public:
	// constructor for sorting criterion
	// - default criterion uses value normal
	RuntimeCmp(cmp_mode m = normal) :mode(m) {}
	// comparison of elements
	bool operator()(const T& t1, const T& t2)const {
		return mode == normal ? t1 < t2 : t2 < t1;
	}
	// comparison of sorting criteria
	bool operator==(const RuntimeCmp& rc) {
		return mode == rc.mode;
	}
};

typedef set<int, RuntimeCmp<int> > IntSet;
void fill(IntSet& set);

int main()
{
	// create, fill, and print set with normal element order
	// - uses default sorting criterion
	IntSet coll1;
	fill(coll1);
	PRINT_ELEMENT(coll1, "coll1: ");	// 1 2 4 5 6 7
	
	// create sorting criterion with reverse element order
	RuntimeCmp<int> reverse_order(RuntimeCmp<int>::reverse);
	
	// create, fill, and print set with reverse element order
	IntSet coll2(reverse_order);
	fill(coll2);
	PRINT_ELEMENT(coll2, "coll2: ");	// 7 6 5 4 2 1
	
	// assign elements AND sorting criterion
	coll1 = coll2;
	PRINT_ELEMENT(coll1, "coll1: ");	// 7 6 5 4 2 1
	coll1.insert(3);
	PRINT_ELEMENT(coll1, "coll1: ");	// 7 6 5 4 3 2 1
	
	// just to make sure...
	if (coll1.value_comp() == coll2.value_comp()) {	// true
		cout << "coll1 and coll2 have same sorting criterion" << endl;
	}
	else {
		cout << "coll1 and coll2 have different sorting criterion" << endl;
	}
	
	return 0;
}

void fill(IntSet& set) {
	// fill insert elements in random order
	set.insert(4);
	set.insert(7);
	set.insert(5);
	set.insert(1);
	set.insert(6);
	set.insert(2);
	set.insert(5);
}
这个例子说明了 如果准则不同,准则本身也会被赋值(assigned)或交换(swapped)。

4.迭代器性质

和其他所有关联式容器类似,这里的迭代器是双向迭代器(bidirectional iterator)。

所以对于只能用于随机存取迭代器(random access iterator)的STL算法(例如排序或随机乱序random_shuffling),set和multiset就用不了了。

更重要的是,对迭代器操作而言,所有元素都被视为常数。set<int> iter = iSet.begin(); *iter = 1; // Error:不可修改的左值

这可以确保你不会人为改变元素值,从而打乱既定顺序。然而也使得你无法对sets或multisets元素调用任何变动性算法(modifying algorithms)

例如你不能对它调用remove(),因为remove()算法实际上是一个参数值覆盖被移除的元素,如果要移除set和multisets的元素,你只能使用它们所提供的成员函数。


c
co
Com
Comp
Compa
Compar
compari
comparis
comparis
compariso
comparison
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值