6. 有序数组¶
在很多场景下,我们需要数组元素是有序的。对于这类需求,有两种满足的方法:
让数组保持无序;在需要时,临时进行(部分)排序;
让数组本身保持有序;
排序需要时间。而数组排序时,大对象在数组空间内的拷贝/移动也代价高昂。因而,无论是临时性的排序,还是 让数组本身保持有序,都有两种选择:
对于小对象,可以让对象自身进行移动;
对于大对象,则最好使用索引进行排序。
对于元素本身保持无序,需要时临时进行排序的数组,可以通过 Sort
或者 SortObject
进行排序;
而对于自身需要维持有序的数组而言,本库提供了以简单 插入排序 为算法的有序数组。
6.1. OrderedObjectArray¶
OrderedObjectArray<T,N,COMPARE>
是一种维持数组元素自身有序的一种数组。
模版的第三个参数 COMPARE
,决定了数组元素的顺序。其本身的默认实现为 T::operator<
,但你可以
指定任何一种对比类型,比如:
struct Foo {
int a;
explicit Foo(int a) : a{a} {}
~Foo() { a = 10; }
};
auto FooLess = [](Foo const& l, Foo const& r) {
return l.a > r.a;
};
OrderedObjectArray<Foo, 10, decltype(FooLess)> array;
6.2. IndexedOrderedArray¶
IndexedOrderedArray<T,N,COMPARE>
通过 索引 来维持数组元素顺序, 而数组元素本身是完全
无序的,甚至是非连续的。这样保证了数组元素一旦在某个 slot 上创建,在整个生命周期存在期间,完全不会
移动位置(无论是删除操作,还是 Replace
相关操作)。取而代之,变化和移动的,是数组元素的索引。
因而,IndexedOrderedArray
要比 OrderedObjectArray
耗费更多的空间(索引所需的空间,以及空间占用位图),
但在维持有序方面,性能更高。
注意
事实上,ObjectArray
也有它的索引版本 : IndexedArray
。它们都是将 ScatteredArray
当作一个
数组空间分配器,并通过索引数组来保持 Contiguous 属性。
这样的做法,可以让需要频繁修改,比如进行 Append
, Erase
, Sort
, Rotate
等操作,但同时对象
的 move
成本又比较大的数组,具备性能优势。
6.3. 自动选择¶
上述两种有序数组,提供了完全一致的接口。程序员拥有根据需要自主选择的权利。
但如果你有选择困难症,则可以使用 OrderedArray<T,N,COMPARE>
,它会根据一定的条件,自动从二者之中选择一个(而条件是可以集中进行统一维护)。
6.4. 接口¶
对于有序数组而言,由于本身已经有序,因而不再提供 Sort
相关的任何接口,也不能创建 SortObject
。除此
之外,它们拥有与普通数组完全一致的接口。