如何将std::set赋值给二维std::vector<int>并实现指定排序矩阵
嘿,我来帮你逐个解决这些C++容器的问题,看起来你在处理矩阵和有序无重复元素的场景时遇到了几个具体的卡点,咱们一步步来:
std::vector<std::vector<std::set<int>>> 其实这个初始化很直接,和普通二维vector的初始化逻辑一致,只是把内层的int换成了set<int>。比如如果你需要创建一个m行n列的矩阵,每个位置都是空的set,可以这么写:
#include <vector> #include <set> int main() { int rows = 3; int cols = 3; // 初始化:rows个vector,每个vector包含cols个空std::set<int> std::vector<std::vector<std::set<int>>> cart(rows, std::vector<std::set<int>>(cols)); return 0; }
如果需要给某些set预先填充元素,也可以用初始化列表嵌套:
std::vector<std::vector<std::set<int>>> cart = { {{1,2}, {3}, {4,5}}, {{6}, {7,8}, {9}} };
你遇到的核心问题是std::set不支持随机访问(没有operator[]),所以不能直接用下标取元素。这里有两种可靠的解决方式:
方式一:迭代器遍历逐个赋值
先初始化好二维vector的大小,然后用set的迭代器逐个填充元素:
#include <vector> #include <set> #include <iostream> int main() { std::set<int> num_set = {1,2,3,4,5,6,7,8,9}; std::vector<std::vector<int>> mat(3, std::vector<int>(3)); // 3x3矩阵 auto set_it = num_set.begin(); for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { mat[i][j] = *set_it++; // 迭代器后移,逐个赋值 } } // 打印验证 for (const auto& row : mat) { for (int num : row) { std::cout << num << " "; } std::cout << "\n"; } return 0; }
方式二:用std::copy填充单行(避免崩溃的正确姿势)
之前用std::copy崩溃大概率是因为目标vector的行没有初始化足够的空间,或者拷贝范围不匹配。如果要填充单行,可以这么做:
// 填充第一行:取set的前3个元素 std::copy(num_set.begin(), std::next(num_set.begin(), 3), mat[0].begin()); // 填充第二行:取接下来的3个 std::copy(std::next(num_set.begin(), 3), std::next(num_set.begin(), 6), mat[1].begin()); // 填充第三行:取最后3个 std::copy(std::next(num_set.begin(), 6), num_set.end(), mat[2].begin());
这里std::next(it, n)用来获取迭代器后移n步的位置,确保拷贝的范围是有效的,同时目标行mat[i]已经被初始化为大小3,所以mat[i].begin()是有效的迭代器,不会导致越界。
Cart[it1][it2].insert(number)是否可行? 答案是可以,但要注意迭代器的正确用法。不过你的写法有点小问题:it1如果是vector<vector<set<int>>>的迭代器,Cart[it1]是不对的(下标需要整数,不是迭代器)。正确的写法应该是先解引用行迭代器,再操作内层的set迭代器,或者用范围for循环更简洁:
用迭代器的写法
std::vector<std::vector<std::set<int>>> cart(3, std::vector<std::set<int>>(3)); int number = 5; // 行迭代器 auto row_it = cart.begin(); while (row_it != cart.end()) { // 内层set的迭代器 auto set_it = row_it->begin(); while (set_it != row_it->end()) { set_it->insert(number); // 给每个set插入number ++set_it; } ++row_it; }
更简洁的范围for写法
如果不需要显式使用迭代器,推荐用范围for,代码可读性更高:
for (auto& row : cart) { // 遍历每一行 for (auto& s : row) { // 遍历行内的每个set s.insert(number); } }
你想要的矩阵是按列优先的顺序排列(1,4,7;2,5,8;3,6,9),不需要先按行排序再交换,直接按目标顺序填充是最优的,避免额外的交换开销。
思路:因为set是有序的,我们可以先遍历列,再遍历行,把set的元素依次填充到矩阵的对应位置:
#include <vector> #include <set> #include <iostream> int main() { std::set<int> num_set = {1,2,3,4,5,6,7,8,9}; std::vector<std::vector<int>> mat(3, std::vector<int>(3)); auto set_it = num_set.begin(); // 先遍历列,再遍历行 for (int j = 0; j < 3; ++j) { for (int i = 0; i < 3; ++i) { mat[i][j] = *set_it++; } } // 打印结果:就是你想要的格式 for (const auto& row : mat) { for (int num : row) { std::cout << num << " "; } std::cout << "\n"; } return 0; }
这样一步到位,不需要任何后续的排序或交换操作,时间复杂度是O(n)(n是元素总数),比先按行填充再交换的O(n + k)(k是交换次数)更高效。
内容的提问来源于stack exchange,提问作者Megasa3

