【问题标题】:linked list or array to store strings in C用于在 C 中存储字符串的链表或数组
【发布时间】:2012-11-29 02:46:34
【问题描述】:

在 C 中,我需要存储一个可能相对较大(数千个项目)的短字符串 (char*) 列表。
字符串可以删除或插入但不能修改,顺序不重要。
我不知道这样做更有效的数据结构是什么。
我可以使用结构:

struct node_s {
  char *str;
  node_s *next;
}

或一个 char * 数组:

char **strings;

我不需要直接访问字符串,我只需要它们存在,因为旁边的另一个数据结构(radix trie)维护着字符串某些部分的指针。

【问题讨论】:

  • 你想要随机访问还是顺序访问?
  • 你应该支持频繁查找吗?因为如果这样做,您可能需要考虑使用某种字典(平衡树或哈希图),而不是线性数据结构。
  • more efficient 是什么意思?在插入、删除、移位、搜索方面效率高吗?
  • 事实上,我不需要直接访问字符串,我只需要它们存在,因为另一个结构(radix trie)在字符串的某些部分上有指针。我刚刚修改了我的帖子以使其准确。
  • 如果字符串应该是不可变的,你可能想在你的结构中声明 *str 一个常量。

标签: c arrays string linked-list


【解决方案1】:

所以,如果我理解正确的话,字符串列表不是访问数据的主要方式,它只是一个指针的“清理列表”,必须释放这些指针,而不必遍历所有其他指针,现在已经过时了数据。

在这种情况下,我会使用链表,但不是以正常方式。您上面的node_s 要求,对于每个字符串,您为结构执行一个malloc,为字符串本身执行一个。

相反,我会定义一个这样的结构:

struct string_list {
  struct string_list *next;
  char data[0];
};

零长度数组在结构中不占用空间,但为您提供了一个可以使用的类型化地址。然后,您可以为结构 真正的字符串分配内存:

struct string_list *newstr = malloc (sizeof(struct string_list) + my_desired_size);

然后您将数据放在newstr->data,并链接next 指针:

newstr->next = list_head;
strcpy (newstr->data, my_data, my_desired_size);
list_head = newstr;

当需要释放字符串时,只需要一个free。哦,当然还有修复链接。

【讨论】:

  • @ams:您在结构中定义了一个char string[0],不应该是char data[0],因为您strcpy 到了一个尚未定义的newstr->data?尽管如此,向头部添加数据是个好主意。
  • 现已修复。很好发现。
【解决方案2】:

当您在初始化时不知道确切的条目数时,使用链表通常比使用数组更好。

数组具有固定大小。当您不知道将拥有多少条目并且想要使用数组时,您有两种选择。要么你分配一个比你需要的任何东西都大得多的数组,这是对内存的巨大浪费(而且,通常很难事先知道合理的上限应该是多少)。或者你从一个小数组开始,等到它满了。然后分配一个新的更大的数组,将所有条目复制到新数组中并释放旧数组,这是对 CPU 周期的巨大浪费。

但是使用链表,您就不会有这个问题,因为它们可以动态增长和缩小。

但要注意各种操作的运行时间差异。

在数组中,通过索引获取元素非常快。但是删除具有特定索引的元素而不留下空条目是非常昂贵的,因为后面的每个元素都必须向后移动一个索引。在中间插入一个条目而不覆盖现有条目同样昂贵,因为您必须将后面的所有内容向前移动一个。

对于链表,删除或插入中间的节点很快(当你已经有了它的前导节点时),因为除了插入的节点和它的前导节点之外没有其他节点需要被触及。但是找到必须执行此操作的节点可能会很昂贵,因为您必须通过之前的所有节点跟踪链接。

当您需要快速查找和快速插入/删除时,使用binary tree 是一个不错的折衷方案。

【讨论】:

  • 无论是数组还是链表听起来都不是特别适合这种情况。一棵包含数千个字符串的二叉树,按字母顺序排序,也会变得很慢。
  • 在发表评论之前,我实际上已经建议了:)
【解决方案3】:

当您有大量项目并且想要频繁添加/删除项目时,同时访问时间接近随机访问 O(log n),您应该考虑使用hash table

如果在节点上添加数千个,链表的访问时间会非常慢,而数组不适合频繁添加/删除。

【讨论】:

    【解决方案4】:

    这取决于你想用它们做什么。

    如果顺序不重要,我认为大多数操作将是添加\删除.. 如果是真的,你需要选择列表数据结构(第一个变体)。

    如果您需要对元素进行恒定时间访问,则数组很好,但在无序数组中,这将不起作用.. 搜索某些字符串将花费 O(n) 时间,就像在列表中一样。

    【讨论】:

      【解决方案5】:

      实际上,char **strings 只是一个字符串数组。数组≠链表。那么node_s 绝对是解决方案。

      【讨论】:

        【解决方案6】:

        这取决于你的程序。

        如果你知道字符串的数量。我建议你使用数组

        如果你不知道字符串的个数我建议你使用链表

        如果字符串将在 C 中定义为常量。你可以这样使用:

        char *strings[1000] = {
          "string 0",
          "string 1",
          "string 2",
          "string 3",
           .
           .
           .
          "string 999"
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-01-21
          • 2012-07-12
          • 1970-01-01
          • 2015-04-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-05-04
          相关资源
          最近更新 更多