C++标准模板库编程实战 第五章 set容器

目录

5.1 set容器

5.2 使用set容器

5.2.4 set 迭代器

5.2.5 在set中保存指针

5.3 使用multimap

5.3.1 保存派生类指针

5.4 unordered_set

5.6 集合运算

5.6.1 set_union() 算法

5.6.2 set_intersection() 算法

5.6.3 set_difference() 算法

5.6.4 set_symmetric_difference() 对称差集算法

5.6.5 includes() 算法

课后练习


5.1 set容器

定义set容器的模板如下:

set<T>,保存对象唯一,有序

multiset<T>,可以保存重复对象。

unordered_set<T>,对象唯一,位置由哈希值决定。

unordered_multiset<T>,可以保存重复对象。

5.2 使用set<T>容器

set容器内部元素的组织方式和map<T>相同。都是平衡二叉树。

1.set没有at() ioerator[]()

2.insert() emplace() emplace_hint()

3.clear() erase()

4.find() equal_range() lower_bound() upper_bound()

5.2.4 set 迭代器

5.所有set<T>成员函数返回的迭代器都是const,如果想要修改set容器中的元素,必须先删除它,再插入新的版本。

当必须修改元素且需要将他们组合到一个或多个set容器中时,可以使用指针。通常使用shared_ptr或weak_ptr。

5.2.5 在set中保存指针

大多数时候我们不在意元素在set中的顺序,只在意在不在。

推荐使用memory头文件中的owner_less<T>函数对象类型的实例来比较容器中的智能指针。

比较基于两个智能指针所拥有对象的地址。

shared_ptr<T>类模板中owner_before<T>实例的函数模板原型:

•	 template<typename X> bool owner_before(const std::shared_ptr<X>& other) const;
•	 template<typename X> bool owner_before(const std::weak_ptr<X>& other) const;

 weak_ptr类似。注意函数模板类型参数和类模板类型参数不同,所以可以比较指向不同类型对象的指针。

1.在容器中保存weak_ptr对象时,在使用它时需要确保它以来的shared_ptr仍然存在。可以通过expired()来检查和他关联的shared_ptr是否存在。

5.3 使用multimap

默认用less<T>来比较元素,也可以使用不同的比较函数,但是在元素等价,必须返回false:

std::multiset<string, std::greater<string>> words{ {"dog", "cat", "mouse"}, 
 std::greater<string>()};

在一个有比较运算符comp的multimap容器中,如果表达式!(a comp b)&& !(b comp a) 为true,那么a和b相等。

1.insert总是可以成功。

2.emplace() emplace_hint()

3.find()返回与参数匹配的第一个元素的迭代器,如果都不匹配,返回结束迭代器。

4.equal_range()

5.lower_bound() upper_bound()

6.count()

5.3.1 保存派生类指针

如果不在乎元素的排序顺序,可以使用owner<T>实例。

5.4 unordered_set

和unordered_map<T>容器。

可以将格子的索引传入begin() end()或 cbegin() cend(),返回格子所包含元素段的开始和结束迭代器。

成员函数bucket_count()返回格子的个数。

以下代码展示如何列出容器中每个格子的元素。

for(size_t bucket_index {}; bucket_index < names.bucket_count(); ++bucket_index)
{
 std::cout << "Bucket " << bucket_index << ":\n";
 for(auto iter = names.begin(bucket_index); iter != names.end(bucket_index); ++iter)
 {
 std::cout << " " << iter->first << " " << iter->second;
 }
 std::cout << std::endl;
}

5.6 集合运算

5.6.1 set_union() 算法

第一个版本5个参数:前两个参数指出左操作数的集合范围,三四参数指出右操作数的集合范围。最后一个指向结果集合的存放位置。

要求使用set_union 之前 set1set2需要升序。

std::vector<int> set1 {1, 2, 3, 4, 5, 6};
std::vector<int> set2 {4, 5, 6, 7, 8, 9};
std::vector<int> result;
std::set_union(std::begin(set1), std::end(set1), // Range for set that is left operand
 std::begin(set2), std::end(set2), // Range for set that is right operand
 std::back_inserter(result)); // Destination for the result: 1 2 3 4 5 6 7 8 9

第二个版本6个参数:最后一个参数是用来比较集合元素的函数对象。

std::set<int, std::greater<int>> set1 {1, 2, 3, 4, 5, 6}; // Contains 6 5 4 3 2 1
std::set<int, std::greater<int>> set2 {4, 5, 6, 7, 8, 9}; // Contains 9 8 7 6 5 4
std::set<int, std::greater<int>> result; // Elements in descending sequence
std::set_union(std::begin(set1), std::end(set1),std::begin(set2), std::end(set2),
std::inserter(result, std::begin(result)), // Result destination: 9 8 7 6 5 4 3 2 1
 std::greater<int>()); // Function object for comparing elements

set_union()返回一个指向被复制元素段末尾的后一个位置的迭代器。

5.6.2 set_intersection() 算法

两个版本的set_intersection和set_union参数相同。

结果容器默认用less<T>对元素进行排序。

set_intersection返回一个指向目的容器中插入的最后一个元素的下一个位置。

std::set<string> words1 {"one", "two", "three", "four", "five", "six"};
std::set<string> words2 {"four", "five", "six", "seven", "eight", "nine"};
std::set<string> result;
std::set_intersection(std::begin(words1), std::end(words1),
 std::begin(words2), std::end(words2),
 std::inserter(result, std::begin(result))); 
 // Result: "five" "four" "six"
5.6.3 set_difference() 算法

返回一个指向目的容器中插入的最后一个元素的下一个位置。

std::set<string, std::greater<string>> words1 {"one", "two", "three", "four", "five", "six"};
std::set<string, std::greater<string>> words2 {"four", "five", "six", "seven", "eight", "nine"};
std::set<string, std::greater<string>> result;
std::set_difference(std::begin(words1), std::end(words1),
 std::begin(words2), std::end(words2),
 std::inserter(result, std::begin(result)), // Result: "two" "three" "one"
 std::greater<string>()); // Function object to compare element
5.6.4 set_symmetric_difference() 对称差集算法
std::set<string> words1 {"one", "two", "three", "four", "five", "six"};
std::set<string> words2 {"four", "five", "six", "seven", "eight", "nine"};
std::set_symmetric_difference(std::begin(words1), std::end(words1),
 std::begin(words2), std::end(words2),
 std::ostream_iterator<string> {std::cout, " "});
5.6.5 includes() 算法

比较两个元素的集合,如果第二个集合中全部元素来自于第一个集合,返回true。如果第二个集合为空,也返回true。

std::set<string> words1{ "one", "two", "three", "four", "five", "six" };
	std::set<string> words2{ "four", "two", "seven" };
	std::multiset<string> words3;
	std::cout << std::boolalpha
		<< std::includes(std::begin(words1), std::end(words1),
			std::begin(words2), std::end(words2))
		<< std::endl; // Output: false
	std::cout << std::boolalpha
		<< std::includes(std::begin(words1), std::end(words1),
			std::begin(words2), std::begin(words2))
		<< std::endl; // Output: true
	std::set_union(std::begin(words1), std::end(words1), std::begin(words2), std::end(words2),
		std::inserter(words3, std::begin(words3)));
	std::cout << std::boolalpha
		<< std::includes(std::begin(words3), std::end(words3),
			std::begin(words2), std::end(words2))
		<< std::endl; // Output: true
	copy(begin(words3), end(words3), ostream_iterator<string>(cout, " "));

并集操作只包含每个重复元素的一个副本。如果words1 words2是multiset容器,那结果肯会包含一些重复元素。

std::multiset<string> words1{ "one", "two","nine","nine","one", "three", "four", "five", "six" };
	std::multiset<string> words2{ "four", "two", "seven","seven","nine","nine"};
	std::multiset<string> words3;
	std::cout << std::boolalpha
		<< std::includes(std::begin(words1), std::end(words1),
			std::begin(words2), std::end(words2))
		<< std::endl; // Output: false
	std::cout << std::boolalpha
		<< std::includes(std::begin(words1), std::end(words1),
			std::begin(words2), std::begin(words2))
		<< std::endl; // Output: true
	std::set_union(std::begin(words1), std::end(words1), std::begin(words2), std::end(words2),
		std::inserter(words3, std::begin(words3)));
	std::cout << std::boolalpha
		<< std::includes(std::begin(words3), std::end(words3),
			std::begin(words2), std::end(words2))
		<< std::endl; // Output: true
	copy(begin(words3), end(words3), ostream_iterator<string>(cout, " "));

如果在两个集合中都重复,结果也会重复。

课后练习

pe5_1:

#include<iostream>
#include<vector>
#include<set>
#include<random>
#include<string>
enum class Color { red1, red2, black1, black2 };
static const std::string scolor[4]={ "red1", "red2", "black1", "black2" };
//const string scolor[4] = { "red1", "red2", "black1", "black2" };
using namespace std;

template<typename T>
T generate_rand(const T& min,const T& max);
class Card {
private:
	Color color;
	int number;
public:
	//Card() :color(Color::red1), number(0) {};
    Card(Color cc, int nn) :color(cc), number(nn) {};
	Color get_color() { return color; };
	int get_number() { return number; };
    bool operator<(const Card& cc) const {
        return color < cc.color || (color == cc.color && number < cc.number);
    }
    friend std::ostream& operator<<(ostream &os, const Card& cc) {
        //static const string scolor[4] = { "red1", "red2", "black1", "black2" };
        os << scolor[int(cc.color)] <<" "<<cc.number << endl;
        return os;
    }
};
int main() {
	vector<Card> cc;
    set<Card> AA[4];
    /*set<Card> north;
    set<Card> south;
    set<Card> east;
    set<Card> west;
    AA[0] = north;
    AA[1] = south;
    AA[2] = east;
    AA[3] = west;*/
    /*for (int i = 0; i < 52; i++) {
        cc.push_back(Card{ generate_rand(Color::red1,Color::black2), generate_rand(1,13) });
    }*/
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 13; j++) {
            cc.emplace_back(static_cast<Color>(i), j);
        }
    }
    random_shuffle(begin(cc), end(cc));
    auto iter = begin(cc);
    for (int i = 0; i < 4; i++) {
        copy(iter, iter + 13, inserter( AA[i],begin( AA[i]) ) );
        advance(iter, 13);
    }
    for (int i = 0; i < 4; i++) {
        cout << "玩家" << i << " : " << endl;
        for (auto value : AA[i]) {
            std::cout << value << endl;
        }
    }
	return 0;
}
template<typename T>
T generate_rand(const T& min, const T& max) {
    // 创建一个随机数引擎
    std::random_device rd;
    std::mt19937 gen(rd());

    // 定义随机数的范围
    /*int min = 1;
    int max = 52;*/

    // 创建一个分布对象,指定随机数的范围
    std::uniform_int_distribution<> dis(min, max);

    // 生成随机数
    /*int random_num = dis(gen);*/
    return dis(gen);
}

pe5_2:

#include<iostream>
#include<set>
#include<unordered_set>
using namespace std;
int main() {

	unordered_multiset<string> words;
	string word;

	while (true)
	{
		if ((cin >> word).eof()) {
			cin.clear();
			break;
		}
		words.emplace(word);
	}
	int ccount = 0;
	for (auto value : words) {
		cout << value << " count: " << words.count(value)<<" ";
		if ((ccount+1) % 6 == 0) {
			cout << endl;
			ccount == 0;
		}
		ccount++;
	}

	return 0;
}

pe5_3:

#include<iostream>
#include<set>
#include<unordered_set>
#include<random>
using namespace std;

template<typename T>
T generate_rand(const T& min, const T& max);

template<typename T>
T sum(const T& min, const T& max);
int main() {

	multiset<short> words;
	short number1 = 1, number2 =6;

	for (int i = 0; i < 1000; i++) {
		words.emplace(sum(generate_rand(number1, number2), generate_rand(number1, number2)));
	}
	
	for (int i = 2; i < 13;i++) {
		cout << i << " count: " << words.count(i) << endl;
	}

	return 0;
}
template<typename T>
T generate_rand(const T& min, const T& max) {
    // 创建一个随机数引擎
    std::random_device rd;
    std::mt19937 gen(rd());

    // 定义随机数的范围
    /*int min = 1;
    int max = 52;*/

    // 创建一个分布对象,指定随机数的范围
    std::uniform_int_distribution<> dis(min, max);

    // 生成随机数
    /*int random_num = dis(gen);*/
    return dis(gen);
}
template<typename T>
T sum(const T& min, const T& max) {
	return min + max;
}

pe5_4:

#include<iostream>
#include<set>
#include<unordered_set>
#include<random>
#include<vector>
#include<map>
#include<tuple>
using namespace std;
const vector<string> books{ "C++","C","Java","Python","PHP","GOLONG","R","shell","C#","Ruby" };
template<typename T>
T generate_rand(const T& min, const T& max);

set<string> generate_set(const int& min, const int& max);

int main() {
	
	multimap<string, set<string>> people_books;
	cout << "Enter people's name: " << endl;
	string name;

	while (true) {
		if ((cin >> name).eof()) {
			cin.clear();
			break;
		}
		people_books.emplace(name, generate_set(0, 9));
	}
	cout << "Show All;" << endl;
	for (auto value : people_books) {
		cout << value.first << " has " << "books: ";
		for (auto vvv : value.second) {
			cout << vvv << " ";
		}
		cout << endl;
	}
	multimap<int, tuple<string,string,set<string>>> number_books;
	set<string> same_books;
	for (auto iter = begin(people_books); iter != end(people_books); iter++) {
		for (auto iter2 = next(iter); iter2 != end(people_books); iter2++) {
			set_intersection(begin(iter->second), end(iter->second),
				begin(iter2->second), end(iter2->second),
				inserter(same_books, begin(same_books)));

			number_books.emplace(size(same_books), tuple<string, string, set<string>>(iter->first, iter2->first, same_books));
		}
	}
	/*for (auto value : people_books) {
		for (auto value2 : people_books) {
			set_intersection(begin(value.second), end(value.second),
				begin(value2.second), end(value2.second),
				inserter(same_books,begin(same_books)));

			number_books.emplace(size(same_books), tuple<string, string, set<string>>(value.first, value2.first, same_books));
		}
				
	}*/

	cout << "Show Compare: " << endl;
	for (auto value : number_books) {
		if (value.first >= 2) {
			cout << get<0>(value.second) << " and " << get<1>(value.second) << " has " << value.first
				<< " they are: ";
			for (auto vvv : get<2>(value.second)) {
				cout << vvv << " ";
			}
			cout << endl;
		}
		else continue;
	}
	
	

	return 0;
}
template<typename T>
T generate_rand(const T& min, const T& max) {
    // 创建一个随机数引擎
    std::random_device rd;
    std::mt19937 gen(rd());

    // 定义随机数的范围
    /*int min = 1;
    int max = 52;*/

    // 创建一个分布对象,指定随机数的范围
    std::uniform_int_distribution<> dis(min, max);

    // 生成随机数
    /*int random_num = dis(gen);*/
    return dis(gen);

}
set<string> generate_set(const int& min, const int& max) {
	set<string> pbset;
	string name;
	int rand_times = generate_rand(4, 6);
	for (int i = 0; i < rand_times; i++) {
		pbset.emplace(books[generate_rand(0, 9)]);
	}
	return pbset;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值