检查数组中元素是否已更改的最有效方法

时间:2014-01-18 02:03:08

标签: c arrays performance hash

我在c中有一个数组,只有在数组中的元素发生了变化时才需要执行某些操作。然而,为此采取的时间和记忆非常重要。我意识到一种有效的方法可能是散列数组的所有元素并将结果与​​之前的结果进行比较。如果它们匹配则意味着元素不会改变。但我想知道这是否是最有效的做事方式。此外,由于数组只有8个字节长(每个元素1个字节),散列函数最不耗时?

阵列中的元素实际上是从另一个微控制器接收的。因此,根据其他微控制器测量的是否相同,它们可能会也可能不会发生变化

5 个答案:

答案 0 :(得分:2)

如果您没有绑定到一个简单的数组,您可以创建一个“MRU”结构列表,其中结构可以包含一个标志,指示该项目自上次检查后是否已更改。

每次更改项目时,设置“已更改标志”并将其移至列表的开头。当您需要检查更改的项目时,您将从头部遍历列表并取消设置已更改的标志,并在第一个元素处停止并且未设置其更改标记。

抱歉,我错过了关于阵列只有8个字节长的部分。有了这些信息以及编辑中的新信息,我认为以前的建议并不理想。

如果数组只有8个字节长,为什么不只是缓存前一个数组的副本并将其与接收到的新数组进行比较?

以下是我对比较“快捷方式”的评论的澄清。如何实现这将取决于所使用的平台上sizeof(int)的内容。

使用64位整数,您可以通过一次比较来确定数组是否已更改。例如:

#define ARR_SIZE 8

unsigned char cachedArr[ARR_SIZE];
unsigned char targetArr[ARR_SIZE];

unsigned int *ic = (unsigned int *)cachedArr;
unsigned int *it = (unsigned int *)targetArr;

// This assertion needs to be true for this implementation to work 
// correctly.
assert(sizeof(int) == sizeof(cachedArr));

/* 
** ... 
** assume initialization and other suff here 
** leading into the main loop that is receiving the target array data.
** ...
*/

if (*ic != *it)
{
    // Target array has changed; find out which element(s) changed.
    // If you only cared that there was a change and did not care 
    // to know which specific element(s) had changed you could forego
    // this loop altogether.
    for (int i = 0; i < ARR_SIZE; i++)
    {
        if (cachedArr[i] != targetArr[i])
        {
            // Do whatever needs to be done based on the i'th element
            // changed
        }
    }

    // Cache the array again since it has changed.
    memcpy(cachedArr, targetArr, sizeof(cachedArr));
}
// else no change to the array

如果原生整数大小小于64位,则可以使用相同的理论,但是您必须遍历数组sizeof(cachedArr) / sizeof(unsigned int)次;如果变化是在测试的最后一个块中,那么将会出现最坏情况(但并非一直存在)。

应该注意的是,通过执行任何char到整数类型的转换,您可能需要考虑对齐(如果char数据与适当的字大小边界对齐)。

然而,进一步思考这个问题,完全展开循环可能会更好:

if (cachedArr[0] != targetArr[0])
{
    doElement0ChangedWork();
}
if (cachedArr[1] != targetArr[1])
{
    doElement1ChangedWork();
}
if (cachedArr[2] != targetArr[2])
{
    doElement2ChangedWork();
}
if (cachedArr[3] != targetArr[3])
{
    doElement3ChangedWork();
}
if (cachedArr[4] != targetArr[4])
{
    doElement4ChangedWork();
}
if (cachedArr[5] != targetArr[5])
{
    doElement5ChangedWork();
}
if (cachedArr[6] != targetArr[6])
{
    doElement6ChangedWork();
}
if (cachedArr[7] != targetArr[7])
{
    doElement7ChangedWork();
}

同样,取决于是否知道哪些特定元素可以被收紧。这将导致需要更多的指令存储器,但消除了循环开销(良好的旧存储器与速度权衡)。

与任何时间/内存相关的测试一样,测量,比较,调整和重复,直到达到预期的结果。

答案 1 :(得分:1)

  

仅当数组中的元素已更改时

除了你之外还有谁会改变它们?您可以跟踪自上次执行操作后是否进行了更改。

如果您不想这样做(可能是因为它需要在太多地方记录更改,或者因为记录保留会花费太多时间,或者因为另一个线程或其他硬件正在弄乱阵列),只需将数组的旧内容保存在单独的数组中。它只有8个字节。如果要查看是否有任何更改,请将当前数组与逐个元素进行复制。

答案 2 :(得分:1)

正如其他人所说,只有代码改变了元素才会改变元素。

也许这些数据可以被其他用户更改?否则你会知道你改变了一个条目。

就哈希函数而言,此数组只能有2 ^ 8 = 256个不同的值。哈希函数在这里不会有用。此外,必须计算哈希函数,这会花费内存,因此我认为这不适用于您的应用程序。

我会比较比特,直到你发现一个已经改变。如果一个已经改变,你将在你的阵列发生变化之前平均检查4位(假设每个位同样可能改变)。

如果一个没有改变,这是最糟糕的情况,你必须检查所有八位,得出结论没有改变。

答案 3 :(得分:1)

如果数组只有8个字节长,则可以将其视为long long类型号。假设原始数组是char数据[8]。

long long * pData = (logn long *)data;
long long olddata = *pData;

if ( olddata != *pData )
{
      // detect which one changed
}

我的意思是,通过这种方式您可以一次性操作所有数据,这比使用索引访问每个元素要快得多。在这种情况下,哈希速度较慢。

答案 4 :(得分:0)

如果它是面向字节的,只有8个元素,那么执行XOR功能将比任何其他比较更有效。

如果((LocalArray [0] ^收到数组[0])&amp;(LocalArray [1] ^收到数组[1])&amp; ...)

{

//是的,它已被更改

}