排序时在空 std::vector 上使用 insert()

Using insert() on empty std::vector when sorting

本文关键字:insert vector std 排序      更新时间:2023-10-16

我知道理想情况下要添加到std::vector而不必担心我应该使用push_back()。但是,我的问题是,我需要一个干净的代码来检查我输入的值是否已经在std::vector中,如果没有,我必须按顺序升序排列。为此,我正在做:

vector<Book>::iterator it;
it = std::find(books.begin(), books.end(), b);
if (it != books.end()) {
*it = b; // if b exists in books, overwrite the iterator
}
else {
vector<Book>::iterator _it;
_it = lower_bound(books.begin(), books.end(), b);
books.insert(_it, b); // here on an empty vector, _it has no values
}

仅当std::vector中尚不存在值b时,else才会运行。如果这是针对它检查的第一个值,则else运行(因为它为空),并且std::iterator位于books[0](?)。

让我对使用它持谨慎态度的是,在调试时,在insert()行上,_it的值显示为"错误读取......"对于std::iterator指向的每个成员。现在程序功能并产生预期的结果,但它是错误的吗?

你正在做的事情工作正常。然而,这不是最有效的方法。使用std::find不会利用向量中的数据已排序的事实,它会访问每个元素,直到找到正确的元素。

您可以从一开始就使用std::lower_bound而不是std::find因为如果元素存在,它将找到您的元素,如果不存在,它将找到插入新元素的正确位置。

此外,它将使用二叉搜索,因此它将比std::find更快地突飞猛进。此外,您最终不会两次找到插入/替换点。

像这样的事情应该做:

void insert_or_replace(std::vector<Book>& books, Book const& b)
{
std::vector<Book>::iterator it;
it = std::lower_bound(books.begin(), books.end(), b);
if(it != books.end() && *it == b)
*it = b;
else
books.insert(it, b);
}

这都是定义良好的行为。

lower_bound将返回空范围的结束迭代器(在您的情况下books.end()),或者b是否应该在最后一个元素之后。insert将在迭代器传递给它之前添加新元素,因此这将在end之前。 在空向量中,这将具有将元素添加到向量的效果。

代码非常好。对于空向量lower_bound(books.begin(), books.end(), b)将返回end()迭代器。将其传递给 std::vector::insert 将正常工作。

pos- 将在其之前插入内容的迭代器。pos可能是迭代器end()

关于您的担忧:

让我对使用它持谨慎态度的是,在调试时,在insert()行上,_it的值显示为"读取错误......"对于std::iterator指向的每个成员。

这是因为end()迭代器指向最后一个元素后面的位置,因此对它的尊重是无效的(获取不存在的元素)。