繁体   English   中英

链表和结构体数组之间的区别?

[英]Difference between linked lists and array of structs?

这些代码段有什么区别?

1)

struct MyStruct
{
    int num;
} ms[2];

ms[0].num = 5;
ms[1].num = 15;

2)

struct MyStruct
{
    int num;
    MyStruct *next;
};

MyStruct *ms = new MyStruct;
ms->num = 5;
ms->next = new MyStruct;
ms->next->num = 15;

一般而言,我可能对链接列表和列表有些困惑,它们对某些东西特别有用吗? 请给我更多解释。

您的第一个定义...

struct MyStruct
{
    int num;
} ms[1];

...创建一个具有单个元素的静态分配数组。 您无法在程序运行时更改数组的大小; 此数组永远不会包含一个以上的元素。 您可以通过直接索引访问数组中的项目; 例如,假设您已定义了适当大小的数组,则ms[5]将为您提供数组中的第六个元素(请记住,C和C ++数组的索引为0,因此第一个元素为ms[0] )。

您的第二个定义...

struct MyStruct
{
    int num;
    MyStruct *next;
};

...创建一个动态分配的链表。 该列表的内存是在运行时动态分配的,并且链接列表可以在程序的生命周期内增长(或缩小)。 与数组不同,您不能直接访问列表中的任何元素。 要到达第六个元素,您必须从第一个元素开始,然后重复5次。

关于代码中的错误,第一个构造静态数目的MyStruct元素并将它们存储在ms数组中,因此ms是MyStruct结构的数组,当然,这意味着您只能将其包含2个元素,稍后您不能将任何其他元素添加到ms数组,尽管您限制了MyStruct元素的数量,但是在第二种情况下,当您拥有链接列表时,可以根据需要链接任意数量的MyStruct元素,这将导致动态数量在MyStruct元素中,第二种情况使您可以在运行时添加任意数量的MyStruct,第二种情况在概念上应在内存中看起来像这样:

[ MyStruct#1 ] ----> [ MyStruct#2 ] ----> [ NULL ]

例如,NULL可能是MyStruct#3,而第一个是:

[ MyStruct#1 ] ----> [ MyStruct#2 ]

就是这样,不能添加MyStruct#3。

现在,让我们看一下您编写的代码:

struct MyStruct
{
    int num;
} ms[1];

ms[1]的确意味着为我创建一个包含MyStruct元素的ms数组。
接下来的代码假定您创建了两个:

ms[0].num = 5;
ms[1].num = 15

因此应该是:

struct MyStruct
{
    int num;
} ms[2];

它将正常工作! 并记住我为此所做的简单说明:
[ MyStruct#1 ] ----> [ MyStruct#2 ]

第二种情况:

struct MyStruct
{
    int num;
    MyStruct *next;
};

MyStruct *ms = new MyStruct;
ms->num = 5;
ms->next = new MyStruct;
ms->next->num = 15;

如果将源代码另存为.cpp则此代码将使用new的C ++运算符,并且可以将其编译为C ++应用程序而不会出错,而对于C,语法应如下更改:

struct MyStruct
{
    int num;
    MyStruct *next;
};

MyStruct *ms = (MyStruct *) malloc(sizeof MyStruct);
ms->num = 5;
ms->next = (MyStruct *) malloc(sizeof MyStruct);
ms->next->num = 15;

并且不要忘记在malloc()函数中包含#include <stdlib.h> ,您可以在此处阅读有关此函数的更多信息。
作为第一种情况,请记住我对链表的说明:
[ MyStruct#1 ] ----> [ MyStruct#2 ] ----> [ NULL ]

NULL实际上是ms-> next MyStruct结构的下一个元素,为解释它,我们还记得ms-> next是MyStruct的指针,我们在堆中分配了一个空间,所以现在它指向一个内存块具有相同大小的MyStruct结构 最后,这是一个Stackoverflow问题,涉及何时使用链表以及何时使用数组,因此您可以确切地知道为什么世界各地的人们有时更喜欢链表而其他时候更喜欢数组。

哦,我的朋友,有数十种不同类型的数据结构,它们几乎只容纳一堆num值或其他值。 程序员不只是对所有内容使用数组的原因是所需内存量的差异以及执行对您的特定需求最重要的任何操作的简便性。

链接列表在添加或删除单个项目时非常快。 折衷方案是在列表中间找到一个项目相对较慢,并且next指针需要额外的内存。 适当大小的数组在内存中非常紧凑,您可以非常快速地访问中间的项目,但是要在末尾添加新项目,您必须事先知道最大元素数,这通常是不可能的或浪费的内存,或者重新分配更大的数组并复制所有内容,这很慢。

因此,某人不知道列表需要多大,而大多数人只需要处理列表开头或结尾的项目,或者总是循环遍历整个列表,并且比起保存列表来,他更关心执行速度。几个字节的内存,很可能会在数组上选择一个链表。

一般而言,列表和数组之间的主要区别是:

  • 列表中的顺序是明确的 每个元素都存储前一个/后一个元素的位置。 数组中的顺序是隐式的 假定每个元素都具有一个前一个/后一个元素。 请注意,单个列表可能包含多个顺序。 例如,您可能会遇到类似

     struct dualList { T data1; K data2; struct dualList *nextT; struct dualList *nextK; }; 
    这样您就可以通过两种不同的方式对同一列表进行排序,一种是通过data1 ,另一种是通过data2

  • 相邻的数组元素位于相邻的内存位置; 相邻列表元素不必位于相邻位置。

  • 数组提供对元素的随机访问; 列表仅提供顺序访问(即,您必须沿着列表查找元素)。

  • 数组(通常)的长度固定为1-向数组中添加元素或从数组中删除元素不会改变数组的大小。 列表可以根据需要增加或缩小。

列表非常适合维护动态更改的值序列,尤其是在值需要保持顺序的情况下。 由于您不能随机访问元素,因此它们对于存储需要快速且频繁地检索的相对静态数据并不那么热。


  1. 您可以通过动态声明内存来解决此问题,然后根据需要使用realloc调整该内存块的大小,但是需要谨慎进行,并且可能有点PITA。

当元素顺序很重要并且元素的数量事先未知时,链接列表很有用。 此外,访问链表中的元素需要O(n)时间。 在列表中查找元素时,最坏的情况是,您必须查看列表中的每个元素。

对于数组,必须事先知道该数字。 在C语言中定义数组时,必须传递其大小。 另一方面,访问数组元素需要O(1)时间,因为可以通过索引寻址元素。 对于链接列表,这是不可能的。

但是,这不是与C ++有关的问题,因为链接列表和数组的概念并不与C ++相关。

数组是连续的预分配内存块,而链表是通过指针( *next )彼此链接的运行时分配的( malloc )内存(不一定是连续的)内存的集合。 如果您在编译时知道需要存储的最大元素数量,则通常将使用structs数组。 但是,如果您不知道将需要存储的最大元素数量,则structs的链接列表很有用。 同样,通过链接列表,元素的数量可以更改,添加和删除元素。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM