对字符串使用 set_union

Using set_union for strings

本文关键字:union set 字符串      更新时间:2023-10-16

我有两个向量,我需要它们在第三个向量中的并集(不指定第三个向量的大小(

std::vector<std::string> a = {"a","b"};
std::vector<std::string> b = {"d","c"};
std::vector<std::string> c;
std::set_union(a.begin(),a.end(),b.begin(),b.end(),c.begin());
std::cout<<c[1];

这将编译,但给出一个空输出。

算法std::set_union需要有序序列。 在您的字符串示例中,第一个向量按升序排序,第二个向量按降序排序。

此外,向量c为空,因此您不能在算法调用中使用表达式c.begin()。您需要使用std::back_insert_iterator.

对于字符串示例,算法的调用可以如下所示,如演示程序所示。

#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>

int main() 
{
std::vector<std::string> a = { "a", "b" };
std::vector<std::string> b = { "d", "c" };
std::vector<std::string> c;
std::set_union( std::begin( a ), std::end( a ), 
std::rbegin( b ), std::rend( b ),
std::back_inserter( c ) );
for ( const auto &s : c ) std::cout << s << ' ';
std::cout << 'n';
return 0;
}

它的输出是

a b c d 

否则,您需要对向量进行排序。

如果您可能无法对原始向量进行排序,则可以使用以下方法

#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>

int main() 
{
std::vector<std::string> a = { "a", "b" };
std::vector<std::string> b = { "d", "c", "a" };
std::vector<std::string> c( a );
c.insert( std::end( c ), std::begin( b ), std::end( b ) );
std::sort( std::begin( c ), std::end( c ) );
c.erase( std::unique( std::begin( c ), std::end( c ) ), std::end( c ) );
for ( const auto &s : c ) std::cout << s << ' ';
std::cout << 'n';
return 0;
}

程序输出为

a b c d

你的代码有两个问题:

  1. 您没有阅读std::set_union的要求 - 输入范围必须根据给定的比较函数进行排序(在您的情况下operator<( - 这不适用于b.
  2. 该算法不能通过c.begin()调整c的大小;它保持为空,并且您写出界外。使用std::back_insert_iterator.

使用std::set_union()算法的替代方法是使用std::setstd::unordered_set容器来存储两个向量的所有元素,然后从该容器初始化生成的向量。

这种方法的缺点是,额外的容器需要跨两个向量的唯一元素数量的线性空间。

使用哪个容器将取决于您是否需要对生成的向量进行排序。如果您不需要对生成的向量进行排序,则可以使用std::unordered_set

std::vector<std::string> make_unsorted_union(const std::vector<std::string>& a,
const std::vector<std::string>& b)
{
std::unordered_set<std::string> st;
for (auto& str: a)
st.insert(str);
for (auto& str: b)
st.insert(str);
return std::vector<std::string>(st.begin(), st.end());
}

将元素插入std::unordered_set平均可以在恒定时间内完成。

如果需要对生成的向量进行排序,则可以改用std::set

std::vector<std::string> make_sorted_union(const std::vector<std::string>& a,
const std::vector<std::string>& b)
{
std::set<std::string> st;
for (auto& str: a)
st.insert(str);
for (auto& str: b)
st.insert(str);
return std::vector<std::string>(st.begin(), st.end());
}

这些函数可以按如下方式使用:

int main() {
std::vector<std::string> a = {"a", "z", "z", "b", "z"};
std::vector<std::string> b = {"d", "v", "c", "x", "e"};
std::vector<std::string> c = make_unsorted_union(a, b);
for (auto& str: c)
std::cout << str << ' ';
std::cout << 'n';
c = make_sorted_union(a, b);
for (auto& str: c)
std::cout << str << ' ';
std::cout << 'n';
}

我这个程序的输出是:

e c x b v d z a 
a b c d e v x z