代码问题.使用矢量删除相同的数字,除了它的最后一个入口
Problem with code. Using vector delete same numbers except the last entrance of it
程序不起作用,但没有错误。我需要删除最后一个条目以外的数字。我们有 1 2 3 4 1 2 5 7 8 0 0 我们需要得到 3 4 1 2 5 8 8 0。
包含的库:vector,iostream。
'
vector<int> MyVector = {1,2,3,4,1,2,5,7,8,0,0};
vector<int>::iterator it;
for (int i = MyVector.size() - 1; i > 0; ++i)
{
int x = MyVector.at(i);
for ( it = MyVector.end() - 1; it >= MyVector.begin(); it--)
{
if (*it == x)
{
MyVector.erase(it);
}
}
}
从这个erase
参考:
在擦除点或之后使迭代器和引用失效
[强调我的]
这意味着您传递给erase
的迭代器本身将失效,并且无法再使用。您需要使用erase
返回的迭代器:
it = MyVector.erase(it);
对于初学者来说,这个循环
for (int i = MyVector.size() - 1; i > 0; ++i)
^^^
没有意义。至少你应该写
for (int i = MyVector.size() - 1; i > 0; --i)
^^^
使用该方法后erase
当前的迭代器it
变得无效。
您可以使用反向迭代器和标准算法std::find
。
这是一个演示程序
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
int main()
{
std::vector<int> v = { 1, 2, 3, 4, 1, 2, 5, 7, 8, 0, 0 };
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << 'n';
for ( auto it = std::rbegin( v ); it != std::rend( v ); )
{
if ( std::find( it.base(), std::end( v ), *it ) != std::end( v ) )
{
it = std::reverse_iterator( v.erase( std::prev( it.base() ) ) );
}
else
{
++it;
}
}
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << 'n';
}
程序输出为
1 2 3 4 1 2 5 7 8 0 0
3 4 1 2 5 7 8 0
我认为这是你将要获得的结果。
您可以为此类任务编写通用算法。例如
template <typename ForwardIterator>
ForwardIterator remove_duplicates( ForwardIterator first, ForwardIterator last )
{
for ( ; first != last; ++first )
{
last = std::remove( std::next( first ), last, *first );
}
return last;
}
并使用向量的反向迭代器调用它。
这是一个演示程序。
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
template <typename ForwardIterator>
ForwardIterator remove_duplicates( ForwardIterator first, ForwardIterator last )
{
for ( ; first != last; ++first )
{
last = std::remove( std::next( first ), last, *first );
}
return last;
}
int main()
{
std::vector<int> v = { 1, 2, 3, 4, 5, 4, 3, 2, 1 };
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << 'n';
v.erase( remove_duplicates( std::begin( v ), std::end( v ) ), std::end( v ) );
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << 'n';
std::cout << 'n';
v.assign( { 1, 2, 3, 4, 5, 4, 3, 2, 1 } );
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << 'n';
v.erase( std::begin( v ), remove_duplicates( std::rbegin( v ), std::rend( v ) ).base() );
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << 'n';
}
它的输出是
1 2 3 4 5 4 3 2 1
1 2 3 4 5
1 2 3 4 5 4 3 2 1
5 4 3 2 1
首先展示了如何删除除第一个条目之外的重复值。然后展示了如何删除除最后一个条目之外的重复值。
从您的代码中,我知道您想从向量中删除重复项。有很多方法可以做到这一点,例如,您可以通过以下方式创建std::set
std::set my_set(my_vector.begin(),my_vector.end());
该集合将不包含重复项,即基本上与您希望保留在向量中的元素相同。从 cpp 首选项
范围构造函数。使用以下内容构造容器 范围 [第一个,最后一个(。如果范围内的多个元素具有 比较等效,未指定插入哪个元素 (待LWG2844(。
如果你需要它,你可以把set
变回一个vector
,尽管一个不重复和排序的容器无论如何都是一个集合。如果不需要对结果进行排序,可以使用 std::unordered_set
。
>erase
在移除的位置或之后使迭代器失效。这是使其工作的一种方法:
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
int main()
{
std::vector<int> MyVector{ 1, 2, 3, 4, 1, 2, 5, 7, 8, 0, 0 };
auto beg{ MyVector.begin() };
for (auto it{ MyVector.rbegin() }, rend{ MyVector.rend() }; it != rend; /* empty */)
{
it = std::reverse_iterator(std::remove(beg, std::next(it).base(), *it));
}
MyVector.erase(std::unique(beg, MyVector.end()), MyVector.end());
}
您的算法具有很大的复杂性:O(N^2( 用于检测重复项,以及擦除元素的复杂性。在最坏的情况下,它可能是 O(N^3(。
其他答案表明如何使用 std::vector 和迭代器的校正获得良好的结果,但没有解决复杂性问题
这个答案提供了一个O(nlogn(方法,使用std::vector。
方法:
1. sort indices according to array values
2. detect positions where to erase
3. build a new vector with kept values
重要的一点是使用稳定的排序,以确保只保留最后一个副本。
计划:
#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
// 1. sort indices according to array values
// 2. detect positions where to erase
// 3. build a new vector with kept values
std::vector<int> remove_duplicate (const std::vector<int>& x) {
std::vector<int> index (x.size());
std::iota (index.begin(), index.end(), 0);
std::stable_sort (index.begin(), index.end(), [&] (int i, int j) {return x[i] < x[j];});
std::vector<bool> erase (x.size());
for (int i = 0; i < x.size() - 1; ++i) {
erase[index[i]] = x[index[i]] == x[index[i+1]];
}
erase[index[x.size()-1]] = false;
std::vector<int> result;
for (int i = 0; i < x.size() - 1; ++i) {
if (!erase[i]) result.push_back(x[i]);
}
return result;
}
int main() {
std::vector<int> MyVector = {1,2,3,4,1,2,5,7,8,0,0};
auto result = remove_duplicate (MyVector);
for (auto i: result) {
std::cout << i << " ";
}
std::cout << "n";
return 0;
}
- 比较并显示使用最小值(a,b)和最大值(a、b)升序排列的4个数字
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- 检查输入是否不是整数或数字
- 如何(从固定列表中)选择一个数字序列,该序列将与目标数字相加
- 如何用数字处理log(0)
- 最高有效数字侧的第N位
- 如何获取一个数字的前3位
- 查找最接近的大于当前数字的数字的索引
- 找到两对数字,使它们的乘积的绝对差最小化
- 我想做一个彼此不同但重复出现的数字
- 将数字转换为字母(例如:123 转换为一二三)
- C++如何计算用户输入的数字中的偶数位数
- 如何在C++中确定文本文件中的元素是字符还是数字
- 打印数字图案
- C++问题:用户认为数字1-100,程序提出问题不超过6次即可得到答案。无法正确
- 如何检查一个c++字符串中有多少相同的字符/数字
- 求出有多少个数字是完美平方,而sqrt()是L,R范围内的素数
- 将数字打印成文字
- 当使用比格式支持的精度更高的精度来显示数字时,会写出什么数据
- 代码问题.使用矢量删除相同的数字,除了它的最后一个入口