所有,
这个问题的延续这一个 。 我认为STL错过这个功能,但它只是我的恕我直言。
现在的问题。
请考虑下面的代码:
class Foo
{
public:
Foo();
int paramA, paramB;
std::string name;
};
struct Sorter
{
bool operator()(const Foo &foo1, const Foo &foo2) const
{
switch( paramSorter )
{
case 1:
return foo1.paramA < foo2.paramA;
case 2:
return foo1.paramB < foo2.paramB;
default:
return foo1.name < foo2.name;
}
}
int paramSorter;
};
int main()
{
std::vector<Foo> foo;
Sorter sorter;
sorter.paramSorter = 0;
// fill the vector
std::sort( foo.begin(), foo.end(), sorter );
}
在任何给定时刻的载体可以重新排序。 该类还具有被分拣机结构中使用的吸气剂的方法。
什么是插入在载体中的新元素的最有效方法是什么?
情况我已经是:
我有一个网格(电子表格)中,使用一类的排序矢量。 在任何给定时间的矢量可以被重新排序,并且网格将相应地显示已排序的数据。
现在我需要在矢量/格中插入一个新元素。 我可以插入,然后重新排序,然后重新显示整个电网,但是这是非常低效的特别是对大电网。
任何帮助,将不胜感激。
Answer 1:
简单问题的答案:
template< typename T >
typename std::vector<T>::iterator
insert_sorted( std::vector<T> & vec, T const& item )
{
return vec.insert
(
std::upper_bound( vec.begin(), vec.end(), item ),
item
);
}
与谓词版本。
template< typename T, typename Pred >
typename std::vector<T>::iterator
insert_sorted( std::vector<T> & vec, T const& item, Pred pred )
{
return vec.insert
(
std::upper_bound( vec.begin(), vec.end(), item, pred ),
item
);
}
其中pred是类型T的严格有序的谓词
对于这项工作的输入矢量必须已经在这个谓词进行排序。
在这样的复杂度O(log N)
为upper_bound
搜索(找出在哪里插入),但到O(N)
用于插入本身。
为了更好的复杂性,你可以使用std::set<T>
如果有不会是任何重复或std::multiset<T>
是否有可能重复。 这些将被自动保留的排序顺序为您和您也可以指定对这些自己的断言。
有各种其他的事情你可以做这是更复杂,例如管理vector
和set
/ multiset
/ sorted vector
新增项目则当有足够多的合并这些。 任何一种通过您的收藏迭代都需要通过两个集合运行。
使用第二向量具有保持你的数据结构紧凑的优点。 在这里你的“新添加的”项目vector
会比较小,因此,在插入时间将是O(M)
其中M
是该向量的大小,可能会比更可行O(N)
每次在大载体插入的。 合并将是O(N+M)
比更好O(NM)
将在同一时间内插入一个,所以在总这将是O(N+M) + O(M²)
以插入M
元素然后合并。
你可能会保持插入载体在其能力了,所以当你长大,你不会做任何重新分配,只是移动元素。
Answer 2:
如果你需要保持矢量排序的时候,首先你可能会考虑是否使用std::set
或std::multiset
不会简化你的代码。
如果你真的需要一个排序向量,并希望快速插入一个元素,但不希望强制实施的分类准则,以满足所有的时间,那么你可以先使用std::lower_bound()
来找到一个位置其中元件应在对数时间被插入排序范围,然后使用insert()
的成员函数vector
在该位置插入元件。
如果性能是一个问题,考虑基准std::list
VS std::vector
。 对于小件物品, std::vector
被称为是因为较高的缓存命中率的速度较快,但insert()
操作本身是计算速度更快的名单(无需四处移动元素)。
Answer 3:
只是注意,你可以使用upper_bound
以及根据您的需要。 upper_bound
将确保等同于其他人会出现在他们的序列结束新条目, lower_bound
将保证等同于其他人会出现在他们的序列开始新的条目。 可对于某些实现有用的(也许可以共享一个“位置”类,但并非所有的他们的详细资料!)
两者都将向你保证矢量保持排序根据<
元素的结果,尽管插入lower_bound
将意味着移动更多的元素。
例:
insert 7 @ lower_bound of { 5, 7, 7, 9 } => { 5, *7*, 7, 7, 9 }
insert 7 @ upper_bound of { 5, 7, 7, 9 } => { 5, 7, 7, *7*, 9 }
Answer 4:
取而代之的插入和排序。 你应该做一个查找,然后插入
保持排序的载体。 (排序一次)。 当你插入
发现比喻为更大,以你要插入一个第一要素。
只是位置之前执行插入。
通过这种方式,矢量保持排序。
这是怎么一回事的例子。
start {} empty vector
insert 1 -> find first greater returns end() = 1 -> insert at 1 -> {1}
insert 5 -> find first greater returns end() = 2 -> insert at 2 -> {1,5}
insert 3 -> find first greater returns 2 -> insert at 2 -> {1,3,5}
insert 4 -> find first greater returns 3 -> insert at 3 -> {1,3,4,5}
Answer 5:
当你要排序顺序之间切换,您可以使用多个索引数据结构,其中的每一个你保持健康有序(可能是某种平衡树的,比如std ::地图,其排序键映射到矢量指数,或std ::设为存储指向您选择obects - 但具有不同的比较函数)。
下面是该做这个库: http://www.boost.org/doc/libs/1_53_0/libs/multi_index/doc/index.html
对于每一个变化(新元素或密钥更新的插入),你必须更新所有索引数据结构,或者它们标记为无效。
这工作如果没有“太多”的排序顺序,而不是“太多”的数据结构的更新。 否则 - 运气不好,你必须重新排序每次你想改变顺序。
换句话说:您所需要的更多的指数(以加快查找操作),你需要更新操作的时间就越多。 与每个标需要,当然内存。
为了保持指数的数量小,你可以用它结合了多个领域的指数了若干个领域,以支持更复杂的排序顺序某些查询引擎。 就像一个SQL查询优化。 但是,这可能是矫枉过正...
例如:如果你有两个域,A和B,可以支持4个排序顺序:
- 一个
- b
- 第一A然后B
- 第一B,则一个
与2个索引(3和4)。 随着越来越多的领域,排序顺序的可能组合变大,速度快。 但是,你仍然可以使用这种种“几乎你想要它”,并在查询过程中,那种你不能与指数赶上,因为所需的其余字段的索引。 对于整个数据的有序输出,这并没有太大的帮助。 但是,如果你只是想查找一些元素,第一个“缩小”可以帮助很多。
Answer 6:
假设你真的想用一个矢量,以及排序绕圈或键不改变(所以已经插入元素的顺序始终保持不变):在末尾插入元素,然后将其移动到前面一步一个脚印时间,直到前述元素并不是越大。
它不能做得更快(关于渐近复杂性,或“大O表示法”),因为你必须将所有大要素。 这就是为什么STL不提供这样做的原因 - 因为它是在载体低效的,如果你需要它,你不应该使用它们。
编辑:另一种假设:元素比较并不比移动它们昂贵得多。 看评论。
编辑2:正如我的第一个假设不成立(您想更改排序绕圈),报废这个答案,看到我的另外一个: https://stackoverflow.com/a/15843955/1413374
文章来源: how do you insert the value in a sorted vector?