6

我写了一段代码,其中有一个数据:

unsigned char buf[4096]; // data in chunks of size 4k
unsigned counter[256];

我将每 3 个连续字节的 i/p 数据相加并存储 ans。例如:温度[4096];临时[0] = buf[0] + buf[1] + buf[2];... 直到 4096

然后使用以下代码从 temp 的结果生成直方图:

for(i = 0; i < 4096; i++)
counter[temp[i]]++;

对直方图进行排序(冒泡排序),然后取前 8 个最常出现的值。代码在linux内核(2.6.35)中运行

我面临的问题是,如果我删除排序部分,执行代码所需的时间非常快(在我的笔记本电脑上为 6 微秒,使用 gettimeofday func 测量)。但是在引入排序之后,这个过程在很大程度上减慢了(44微秒)。排序功能本身需要 20 微秒,我不明白为什么时间会增加这么多。我使用 cachegrind 进行了内存分析,结果是正常的,我什至尝试禁用抢占,但它仍然没有显示任何差异。如果有人可以在这里帮助我。谢谢!

4

2 回答 2

2

冒泡排序很慢,它比较和交换您的值高达 4096*4096 = 16,777,216 次。如果您只需要 8 个最佳值,那么选择 1 个扫描肯定会更快。类似的东西。

 const uint_t n = 8;
 uint_t best[n] = {0};
 uint_t index[n] = {0};
 uint_t j;

 for(uint_t i=0; i<4096; i++) {

   if(counter[i] > best[n-1]) {
     for(j=n-2; j && counter[i] > best[j]; j--);           /* Find the insertion position, as our value might be bigger than the value at position n-1. */
     memmove(&best [j+1], &best[j] , (n-1 -j) * sizeof best[0]);      /* Shift the values beyond j up 1  */
     memmove(&index[j+1], &index[j], (n-1 -j) * sizeof index[0]);
     best[j] = counter[i];                                 /* Put the current best value at the top */
     index[j] = i;                                         /* Store the index in the second array to know where the best value was. */
   }
 }

这样,您只需比较一次值,并且成本memmove可以忽略不计,因为您的选择数组很小。无需对数组进行排序,此算法为 O(nm),其中 n 是数组的大小,m 是您选择的大小。最好的排序是 O((n.log2 n).m)。因此,如果 m 小而 n 大,任何通用排序算法都无法击败它。

编辑:我为索引添加了数组。

EDIT2:引入第二个以纠正我在第一个实例中遇到的基本错误。

EDIT3:评论:memmove允许大小为 0,基本上是一个 nop。

于 2011-07-05T14:02:47.843 回答
1

冒泡排序很慢...... O(N^2) 复杂度......如果你想要更快的性能,使用像堆这样的数据结构,或者在你的数组上运行快速排序算法,这两者都会给你 O (N log N) 排序过程的复杂度。此外,这两种方法也适用于固定长度的数组。

于 2011-07-05T13:56:18.410 回答