例如,我想创建一个将节点添加到列表的函数(insertNode
)。每次我想要添加一个节点,或者将所有节点存储在一个数组中,并且通过将数组作为参数传递并调用insertNode
一次,调用insertNode
会更快吗?剩下的功能呢?
代码示例:
typedef struct Data {
int *myArray; //the array where all integers are stored
int firstAvailablePos; //the first free position of myArray
} Data;
insertNode(Data *data, int newNum) {
(data->myArray)[data->firstAvailablePos] = newNum;
(data->firstAvailablePos)++;
}
alt_insertNode(Data *data, int *array, int arraySize) {
int i;
for(i = 0; i < arraySize; i++)
(data->myarray)[i] = array[i];
}
在main
中,两个选项是:
许多函数调用
while (...) {
...
insertNode(data, newNum);
}
一个函数调用
anArraySize = 0;
while (...) {
...
anArray[i] = newNum;
anArraySize++;
...
}
alt_insertNode(data, anArray, anArraySize);
答案 0 :(得分:1)
这取决于底层列表实现的结构。如果这是一个数组并且insertNode附加它,它将被复制到内存中的新位置,其中有更多可用空间,以便新元素也适合。新元素也获得memcpyd。这很快,因为它发生在内核而不是用户空间程序中。
另一方面,如果您有类似链接列表的东西,其中存储了以阵列形式存在的其他列表的指针。甚至不必复制列表中的所有元素,只需向链表插入一个新指针,指向包含新元素的数组。那会非常快。
我目前所知道的最佳答案是:取决于。
答案 1 :(得分:1)
函数调用比迭代更昂贵。如果通过调用insertNode函数插入节点,则需要进行一些迭代(取决于您要插入的位置)以在列表中插入该节点,但如果要插入大量节点,则每次都需要调用该函数。这可能是时间昂贵。
如果通过将某个节点放入数组来插入节点,最后调用insertNode将数组的节点复制到列表中。这次insertNode将被调用更少的时间,但是交互次数将增加。这不会是时间成本,就像函数调用一样。
有一件事需要注意,你需要额外的数据存储空间。
答案 2 :(得分:1)
您的代码存在问题:
您使用过时的语法进行函数定义。现代C代码不再支持隐式返回类型,您应将其指定为void
。
您使用无关的括号使代码看起来很尴尬。
函数insertNode
不会检查myArray
指向的数组是否足够大。如果需要,您应该检查并重新分配数组。
函数alt_insertNode
不会检查可用空间,也不会更新firstAvailablePos
。
根据您的重新分配方案以及您的编译器允许优化的积极程度,批量插入值比逐个插入值可能更有效,特别是如果您不分配中间数组与malloc()
。对特定测试用例进行基准测试将告诉您哪个更有效。但请注意,使代码尽可能简单具有重要价值。
以下是可用于运行测试的更完整的实现:
typedef struct Data {
int *myArray; // the array where all integers are stored
size_t size; // the number of int that can be stored
size_t firstAvailablePos; // the first free position of myArray
} Data;
/* reallocating the array with a simple exponential growth */
int insertNode(Data *data, int newNum) {
if (data->firstAvailablePos == data->size) {
size_t newSize = (data->size < 32) ? 32 : data->size + data->size / 2;
int *array = realloc(myArray, newSize * sizeof(*array));
if (array == NULL)
return -1;
data->myArray = array;
data->size = newSize;
}
data->myArray[data->firstAvailablePos++] = newNum;
return 0;
}
int alt_insertNode(Data *data, int *array, size_t arraySize) {
if (data->firstAvailablePos + arraySize > data->size) {
size_t newSize = (data->size < 32) ? 32 : data->size + data->size / 2;
while (newSize < data->firstAvailablePos + arraySize) {
newSize += newSize / 2;
}
int *array = realloc(myArray, newSize * sizeof(*array));
if (array == NULL)
return -1;
data->myArray = array;
data->size = newSize;
}
memcpy(data->myArray + data->firstAvailablePos, array, arraySize * sizeof(*array));
data->firstAvailablePos += arraySize;
return 0;
}
答案 3 :(得分:0)
这取决于程序中的许多内容。具体来说,节点是按某种算法排序还是顺序不重要?如果是这样,传递数组节点或单独插入将没有太大区别(因为排序块或信息并将节点插入到排序位置应该是等效的。)
您可能还会考虑程序中的哪个点需要在列表中插入节点。如果你的列表使用了动态内存,那么有必要在需要的时候有一个函数在需要的时候插入一个节点。
答案 4 :(得分:0)
这取决于调用代码的外观,但一般来说,如果可以内联,则短函数调用将具有零开销。创建一个临时数组只是为了避免函数调用开销几乎肯定是一个错误 - 但在某些情况下&#34;批处理&#34;这样的东西可以避免一堆每个插入的开销,可能会感觉到。
尝试两者并进行基准测试。