我不認爲std::list
將永遠是這個用例的不錯選擇。雖然插入效率非常低,但您需要遍歷列表以找到插入的正確位置,這使得O(n)複雜。
如果你想保持簡單,std::set
已經好多了,甚至比std::list
更簡單。它以平衡樹的形式實現,所以插入的複雜度爲O(log n),只需調用容器上的insert()
方法即可完成。迭代器按照排序順序爲您提供元素。它在迭代期間確實存在非本地內存訪問模式的缺點,這使得它不能緩存。
想到另一種方法,直覺上應該是非常有效的。其基本思想是類似於@ratchet_freak已經提出,但它不會複製在每次迭代整個向量:
- 包含數據的主要部分是一個
std::vector
,它始終保持排序的容器。
- 將新元素添加到「溢出」容器中,該容器可以是
std::set
或保留排序的另一std::vector
。這隻允許達到一定的大小。
- 迭代時,同時遍歷主容器和溢出容器,使用與合併類似的邏輯。
- 當溢流容器達到尺寸限制時,將其與主容器合併,產生新的主容器。
代碼此草圖:
const size_t OVERFLOW_SIZE = 32;
// Ping pong between two vectors when merging.
std::vector<Entry> mainVecs[2];
unsigned activeIdx = 0;
std::vector<Entry> overflowVec;
overflowVec.reserve(OVERFLOW_SIZE);
void insert(const Entry& entry) {
std::vector<Entry>::iterator pos =
std::upper_bound(overflowVec.begin(), overflowVec.end(), entry);
overflowVec.insert(pos, 1, entry);
if (overflowVec.size() == OVERFLOW_SIZE) {
std::merge(mainVecs[activeIdx].begin(), mainVecs[activeIdx].end(),
overflowVec.begin(), overflowVec.end(),
mainVecs[1 - activeIdx].begin());
mainVecs[activeIdx].clear();
overflowVec.clear();
activeIdx = 1 - activeIdx;
}
}
void draw() {
std::vector<Entry>::const_iterator mainIt = mainVecs[activeIdx].begin();
std::vector<Entry>::const_iterator mainEndIt = mainVecs[activeIdx].begin();
std::vector<Entry>::const_iterator overflowIt = overflowVec.begin();
std::vector<Entry>::const_iterator overflowEndIt = overflowVec.end();
for (;;) {
if (overflowIt == overflowEndIt) {
if (mainIt == mainEndIt) {
break;
}
draw(*mainIt);
++mainIt;
} else if (mainIt == mainEndIt) {
if (overflowIt == overflowEndIt) {
break;
}
draw(*overflowIt);
++overflowIt;
} else if (*mainIt < *overflowIt) {
draw(*mainIt);
++mainIt;
} else {
draw(*overflowIt);
++overflowIt;
}
}
}
如果要存儲的指針我會考慮使用'的std :: VECTOR'代替。一旦列表大小和對象大小開始變得非常大,'std :: list'只會在隨機插入時變得更好。 – sjdowling 2014-10-29 15:48:11