[英]What's the fastest way to extract non-zero indices from a byte array in C++
我有一個字節數組
unsigned char* array=new unsigned char[4000000];
...
我想得到數組中所有非零元素的索引。
當然,我可以做到以下
for(int i=0;i<size;i++)
{
if(array[i]!=0) somevector.push_back(i);
}
有比這更快的算法嗎?
更新1我可以看到多數回答是否定的。 我希望有一些我不知道的神奇位操作。 有些人建議排序,但在這種情況下並不可行。 但是非常感謝你的所有答案。
更新2自此問題發布4年零4個月后,@ wim建議這個答案看起來很有希望 。
除非您的矢量是有序的,否則如果您使用單線程程序,這是執行您想要執行的操作的最有效算法。 您可以嘗試優化要存儲結果的數據結構,但這是您能夠做到的最佳時間。
如果非零值相對較少,您可以使用的一個技巧是標記值:
unsigned char old_value = array[size-1];
array[size-1] = 1; // make sure we find a non-zero eventually
int i=0;
for (;;) {
while (array[i]==0) ++i; // tighter loop
if (i==size-1) break;
somevector.push_back(i);
++i;
}
array[size-1] = old_value;
if (old_value!=0) {
somevector.push_back(size-1);
}
這避免了必須在每次迭代時檢查索引和值。
對於一個大部分為零的字節數組,作為稀疏數組,您可以通過一次比較4個字節來利用32位CPU。 實際比較一次完成4個字節,但是如果任何字節都不為零,那么你必須確定無符號長整數中的哪些字節是非零的,因此需要花費更多精力。 如果數組實際上是稀疏的,則通過比較保存的時間可以補償確定哪些字節非零的額外工作。
最簡單的方法是將unsigned char數組的大小設置為4個字節的倍數,這樣您就不必擔心在循環完成后執行最后幾個字節。
我建議對此進行時序研究,因為它純粹是猜測的,並且有一個點,數組變得非稀疏,這比簡單的循環需要更多的時間。
我要問的一個問題是你用數組的非零元素的偏移向量做什么,以及你是否可以取消向量。 另一個問題是,如果您需要向量,是否可以在將元素放入數組時構建向量。
unsigned char* array=new unsigned char[4000000];
......
unsigned long *pUlaw = (unsigned long *)array;
for ( ; pUlaw < array + 4000000; pUlaw++) {
if (*pUlaw) {
// at least one byte is non-zero
unsigned char *pUlawByte = (unsigned char *)pUlaw;
if (*pUlawByte)
somevector.push_back(pUlawByte - array);
if (*(pUlawByte+1))
somevector.push_back(pUlawByte - array + 1);
if (*(pUlawByte+2))
somevector.push_back(pUlawByte - array + 2);
if (*(pUlawByte+3))
somevector.push_back(pUlawByte - array + 3);
}
}
您可以做的唯一提高速度的方法是使用並發。
這不是你問題的真正答案,但我試圖想象你想要解決的問題。
有時在矩陣上執行操作(在數學意義上),當您知道絕大多數矩陣元素將為零(稀疏矩陣)時,可以改進操作。 您可以通過不使用大數組來進行這樣的優化,而只需存儲指示非零元素的對{index,value}。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.