将元素插入已排序的向量中
Posted
技术标签:
【中文标题】将元素插入已排序的向量中【英文标题】:Inserting element into sorted vector 【发布时间】:2012-10-05 05:31:19 【问题描述】:我编写了一个 C++ 程序,目的是快速将一个元素插入一个排序的向量中。它有时有效,但并非一直有效,我无法弄清楚原因。当我用纸和铅笔按照算法进行操作时,它可以解决,但是出了点问题。请帮忙?
#include <time.h>
#include <cstdlib>
#include <vector>
#include <iostream>
using namespace std;
vector<int> sortedVec;
int main()
// Random seed
srand(time(NULL));
// Put in n random elements
for (int i = 0; i < 10; i++) sortedVec.push_back(rand()%10);
// Sort the vector
bool swapped = true;
int endDecrement = 0;
while (swapped)
swapped = false;
endDecrement++;
for (int i = 0; i < sortedVec.size()-endDecrement; i++)
if (sortedVec.at(i) > sortedVec.at(i+1))
int swap = sortedVec.at(i);
sortedVec.at(i) = sortedVec.at(i+1);
sortedVec.at(i+1) = swap;
swapped = true;
cout<<"Sorted random list:"<<endl;
for (int i = 0; i < sortedVec.size(); i++) cout<<sortedVec.at(i)<<endl;
int toInsert = rand()%10;
cout<<"Random element to insert = "<<toInsert<<endl;
// Insert a random int to the sorted vector
int minIndex = 0;
int maxIndex = sortedVec.size()-1;
while (true)
int mid = (maxIndex-minIndex)>>1;
if (toInsert == sortedVec.at(mid) || maxIndex-minIndex < 2)
sortedVec.insert(sortedVec.begin()+mid, toInsert);
break;
else if (toInsert < sortedVec.at(mid)) maxIndex = mid;
else if (toInsert > sortedVec.at(mid)) minIndex = mid;
cout<<"Random list with inserted element:"<<endl;
for (int i = 0; i < sortedVec.size(); i++) cout<<sortedVec.at(i)<<endl;
return 0;
【问题讨论】:
你为什么不使用std::set
来为你排序元素?而事件如果你想使用vector,你可以使用std::sort
实现排序,并使用std::equal_range
算法找到插入的位置,而不是自己写。
如果您打算这样做,是否有理由不使用std::sort
进行排序并使用std::upper_bound
查找插入点? (但如果你想按顺序插入,这真的不是最好的方法,IMO)。
@Jerry Coffin,这是一个虚拟程序,用于在不同的程序中解决相同的问题。另一个程序执行 A* 搜索并将新节点插入到名为树的向量中。问题是我不知道如何将 std::upper_bound 与 Node 类中的值一起使用(我是 C++ 的新手)。 Node 类有一个名为 fVal 的 int,我想用它来确定插入向量的位置。如果我能得到 std::upper_bound 来检查 tree.at(whatever position).fVal 那就太好了。
"a vector named tree" 可能应该是 std::set
或 std::multiset
,具体取决于您的需要 - 尽管我同意,如果您有其他代码假设它是 vector
,则迁移可以是也很痛。
@asimes:是的,你可以这样做——upper_bound
允许你指定一个比较函数/函子。在你的情况下,它的逻辑只是return a.fval < b.fval;
【参考方案1】:
正如 cmets 所指出的,您提出的解决基本问题的方法相当复杂。
在随机生成器初始化中将time(NULL)
替换为一个常数,可以使您的问题更有吸引力,该常数可以调试观察到的行为。
没有那个,我会为罪魁祸首出价:
int maxIndex = sortedVec.size()-1;
我觉得应该是
int maxIndex = sortedVec.size();
或者你从不考虑顶部元素。
【讨论】:
不幸的是,它仍然不能每次都工作。这是一个虚拟程序,用于解决类似的棘手问题。另一个问题总是有未知的传入值被插入到一个向量中,该向量充满了具有未知但已排序值的元素。 如果你打算在生产代码中使用它,我也强烈建议使用已经在 STL 中编码的函数。还有第二个罪魁祸首:maxIndex-minIndex < 2
暗示您没有进行最后一次比较。应该是maxIndex == minIndex
。
@LeGEC,我很确定对于每种可能的情况,maxIndex 并不总是等于 minIndex。我确实尝试过进行更改,但仍然无法正常工作。在进行 chac 的更改并使用 maxIndex-minIndex
最后一点,mid
应该是 (maxIndex+minIndex)>>1;
(而不是 (maxIndex-minIndex)>>1;
)。我坚持:使用标准算法。 std::upper_bound
有一个模板版本,您可以在其中提供比较功能。
@LeGEC:这是真正的错误!当您需要使用 STL 时,您显然是完全正确的。【参考方案2】:
基于 cmets,假设我们有一个类似这样的结构:
struct data
int fval;
// other stuff we don't care about right now
;
而且,我们假设我们有一个向量:
std::vector<data> items;
如果我们想在向量中按顺序插入一个新项目,我们不真的想在std::insert
之后进行二分搜索。这需要 O(log N) 搜索,然后是 O(N) 插入。相反,我们可以将两者结合起来,因此我们只需要一个 O(N) 操作即可找到正确的位置并进行插入。这是一个简单的版本:
void insert(std::vector<int> &vec, int new_val)
if (vec.empty())
vec.push_back(new_val);
return;
vec.resize(vec.size()+1);
std::vector<int>::reverse_iterator pos = vec.rbegin();
for ( ; *(pos+1) > new_val && (pos+1) != vec.rend(); ++pos)
*pos = *(pos+1);
*pos = new_val;
在您的情况下,您想插入一个data
结构,并比较(pos+1)->fval > new_val.fval
,但基本思想几乎相同。实际上,这应该可能实现为通用算法,但我目前没有时间。
【讨论】:
【参考方案3】:标准库中有用于排序的工具:
#include <algorithm>
#include <vector>
template <typename T, typename A, typename C>
class SortedVector
public:
SortedVector()
// Initialization
template <typename It>
SortedVector(It begin, It end): _data(begin, end)
std::sort(_data.begin(), _data.end(), _comparator);
// if we wanted unicity
_data.erase(std::unique(_data.begin(), _data.end(), _comparator), _data.end());
// Addition of element (without checking for unicity)
void add(T const& element)
_data.push_back(element);
std::inplace_merge(_data.begin(), prev(_data.end()), _data.end(), _comparator);
// or simply: std::sort(_data.begin(), _data.end(), _comparator);
// it is surprisingly efficient actually because most sort implementations
// account for partially sorted range. It is not, however, stable.
// Addition of element with unicity check
bool add(T const& element)
typename std::vector<T, A>::iterator it =
std::lower_bound(_data.begin(), _data.end(), element, _comparator);
if (it != _data.end() and not _comparator(element, *it))
return false;
size_t const n = it - _data.begin();
_data.push_back(element);
std::copy(_data.begin() + n, _data.end() - 1, _data.begin() + n + 1);
// C++11: std::move
_data[n] = element;
private:
std::vector<T, A> _data;
C _comparator;
;
【讨论】:
+1 但我认为删除n
会更好,因为std::copy(it, std::prev(_data.end()), std::next(it)); *it = element;
也会这样做,而且会是“std
-cleaner”。而且我认为您需要在第一个add
中包含<iterator>
和std
-qualify prev
。好吧,也许没有 C++11,但it
还是比_data.begin()+n
好。
@ChristianRau:实际上,it
被 push_back
调用(可能)无效。
@ChristianRau:我不会说你愚蠢,当搞砸这么容易时,界面有点糟糕......【参考方案4】:
我写了一个 C++ 程序,目的是快速将一个元素插入一个排序的向量中
你不应该那样做。 std::vector 不适合快速插入到自定义位置。 编辑:顺便说一句,您正在更换,而不是插入。因为使用矢量是可以的。
您的代码也因不使用标准函数而受到影响。 std::sort,如果你真的想手动交换元素,你也有 std::swap。
这也是不必要的:
int mid = (maxIndex-minIndex)>>1;
编译器可以并且很容易将 /2 优化为 >>1;
编辑:
您的代码已损坏,希望这会告诉您原因: http://ideone.com/pV5oW
【讨论】:
【参考方案5】:我更改了它,并且很确定它现在适用于所有情况:
if (toInsert < sortedVec.at(0)) sortedVec.insert(sortedVec.begin(), toInsert);
else if (toInsert > sortedVec.at(sortedVec.size()-1)) sortedVec.push_back(toInsert);
else
int minIndex = 0;
int maxIndex = sortedVec.size();
while (true)
int mid = (maxIndex+minIndex)>>1;
if (toInsert == sortedVec.at(mid) || maxIndex-minIndex < 2)
sortedVec.insert(sortedVec.begin()+mid+1, toInsert);
break;
else if (toInsert < sortedVec.at(mid)) maxIndex = mid;
else if (toInsert > sortedVec.at(mid)) minIndex = mid;
@LeGEC 和@chac,感谢您研究我发布的算法,它帮助很大。 @Jerry Coffin,我确实让 std::upper_bound 可以为此工作,但不能为我的 Node 类的变量工作,不过也谢谢你。
【讨论】:
它不起作用。先插入 1 而不是 0 将产生向量 (1,0) 这里你可以找到下界cplusplus.com/reference/algorithm/lower_bound的正确实现@ 您能进一步解释一下吗?你的意思是如果你从一个空的vector
开始,插入1,然后是0?我尝试这样做时遇到错误。当我写这篇文章时,我假设列表中已经包含元素。
是的,在开始时它不适用于空向量时就是这种情况。
我想我的意思是你是如何让它产生一个元素 V = 1, 0 的向量。当我更改程序以使用带有空向量的代码时,它只会引发错误。以上是关于将元素插入已排序的向量中的主要内容,如果未能解决你的问题,请参考以下文章