realloc vs链表:无随机访问

时间:2015-11-09 16:46:55

标签: c

我正在编写包含这种结构的应用程序:

typedef struct Triangle{
    struct Triangle* Neighbor[3];

    some other datas...
} Triangle;

每个三角形有3个邻居。请注意,三角形是双重连接的,因为三角形的邻居包含当前三角形作为其邻居。 我的算法将遍历图表,有时会添加一个新的三角形,有时会删除一个。它以1个三角形开头,最后我们将有 N 三角形。

我事先知道 M N 的平均值,我们也知道 N 很少大于 2M < / strong>(可能是5%的时间)

为了给你一个更好的视图,这段代码更新了Triangle的邻居。

void update_triangle_neighbors(Triangle* T, Triangle* oldptr, Triangle* newptr){
    if(T->Neighbor[0]==oldptr)
        T->Neighbor[0] = newptr;
    else if(T->Neighbor[1]==oldptr)
        T->Neighbor[1] = newptr;
    else
        T->Neighbor[2] = newptr;
}

我有两个选择:

  • 1:立即分配一个 2M 三角形数组,如果我们想添加一个新三角形,如果数组已满,则重新分配1.5x之前的大小

    要删除我有指针*toRemove的三角形,我必须:

    • 1.1:我更新了邻居:

      for(i=0; i<3; i++)
          update_triangle_neighbors(&(toRemove->Neighbor[i]), toRemove, NULL)
      
    • 1.2:更新要链接到*toRemove的最后一个三角形的邻居,而不是之前的最后一个三角形

      for(i=0; i<3; i++)
          update_triangle_neighbors(&(LastTriangle->Neighbor[i]), LastTriangle, toRemove)
      
    • 1.3:*LastTriangle复制到*toRemove并减少包含数组大小的变量
  • 2:每次我必须添加或删除三角形时,请使用 malloc free 。 要删除我有指针*toRemove的三角形,我必须:

    • 2.1:请参阅 1.1。
    • 2.2 释放内存:free(toRemove)

方法 1 的优点是它只有一个malloc 95%的时间,并且它可以通过仅分配一个大数组来改善空间局部性。缺点是删除有点复杂,如果有太多的三角形,我们将不得不做realloc

您认为最好的主意是什么? (这是一个大学项目,我不知道我是否有时间实施这两个项目并做基准测试)

TL; DR:当您几乎知道阵列的大小但不知道必须随机访问时,预先分配的链表或普通链表。

编辑:谢谢大家的好建议!我之后回答了我自己的问题,但我仍然愿意接受建议:)

2 个答案:

答案 0 :(得分:1)

正如Andrew Henle指出的那样,realloc()无法正常工作,因为它可能会更改整个数组内存中的位置,并且所有Triangle*指针都会指向错误的地址。我可以用我的数组中的索引替换Triangle*指针,但这会使我的所有内容复杂化,特别是对于调试。

因此,我认为我会采用迄今为止最简单的第二种方法。此外,根本没有证据表明第一种方法可以更快。

加速比

如果我想在程序运行良好时加快我的程序,我仍然可以实现我自己的malloc&#39;以这种方式(建议hexasoft):

  • 在开头分配一个2M的三角形阵列
  • 每个malloc调用
    • 如果该数组中仍有空格,请提供指向可用空间的指针
    • 如果没有剩余空间,只需在其他地方分配(在95%的情况下,程序将在没有发生这种情况的情况下终止一次)
  

为什么你甚至会想到在这种情况下做一个realloc?

我真的不知道,回想起来真是太愚蠢了。地方在这里并不是那么重要,我准备移山而只是为了获得一点点。

答案 1 :(得分:0)

我只会使用calloc来分配(它为你的内存零), 并且可以自由地释放...如果你在现代操作系统上运行,那么应该没有多少惩罚...

如果在你的研究中你发现你需要做别的事情,那么在那里查看选项,但我认为无论如何重新分配代码气味,如果你有一个以上的指针,那么使用它真的很糟糕记忆......