为什么在C?中实现链表的实现中使用指针很重要?
例如:
typedef struct item
{
type data;
struct item *next;
} Item;
typedef struct list
Item *head;
} List;
如果Ill在没有指针的情况下使用相同的实现会发生什么?
答案 0 :(得分:13)
嗯,你最终会得到像这样的东西
typedef struct item
{
type data;
struct item next;
} Item;
现在C编译器将试图找出Item
的大小。但由于next
嵌入在Item
中,因此最终会得到这样的等式
size-of-Item = size-of-type + size-of-Item
这是无限的。因此我们遇到了问题。因此,C需要指针,所以你有
size-of-Item = size-of-type + size-of-pointer
已关闭。更有趣的是,即使你在Java,Python或Haskell等语言中这样做,你也会隐含地存储一个指针(他们说引用)来打破循环。他们只是向你隐瞒事实。
答案 1 :(得分:8)
您实际上并不需要使用指针来实现公开链接列表接口的数据结构,但做需要它们才能提供性能链表的特征。
指针的替代方案是什么?那么,item
需要有一些方法来引用下一个项目。由于各种原因,它无法聚合下一个项目,其中一个原因是这会使结构“递归”,因此无法实现:
// does not compile -- an item has an item has an item has an item has...
typedef struct item
{
type data;
struct item next;
} Item;
你可以做的是拥有一系列项目并在其上实现链接列表:
Item *storage[100];
typedef struct item
{
type data;
int next; // points to the index inside storage of the next item
} Item;
看起来它会起作用;你可以有一个将项目添加到列表中的函数和另一个删除它们的函数:
void add_after(Item *new, Item *existing);
void remove(Item *existing);
这些函数会从数组中删除existing
(注意更新前一项的next
“指针”),创建一个空槽,或找到existing
项和在new
的空白插槽中插入storage
(更新next
指向那里)。
这样做的问题在于,这使得add_after
和remove
操作无法在恒定时间内实现,因为您现在需要搜索数组并在空间不足时重新分配它。
由于常量时间添加/删除是人们使用链表的 原因,这使得非指针方法仅作为智力练习有用。对于真实列表,使用指针意味着您可以在固定时间内执行这些操作。
答案 2 :(得分:4)
如果没有指针,每个列表项都包含另一个列表项(next
),其中包含另一个列表项。其中又包含另一个列表项。等等。
你最终会得到一个无限大的数据结构,它会使用无限量的内存,当然这是无法工作的。
答案 3 :(得分:4)
指针用于动态分配内存。
您可以将列表实现为一个简单的数组,但这意味着您要分配一个连续的内存区域,这对于大型列表来说效率不高。此外,数组更难以扩展(如果达到其最大大小,则必须重新分配它)。
因此,对于大型列表,动态分配是首选,对于每个元素,它可以在任何地方,无论是否连续地将它分配到内存中,并且您可以轻松地扩展它。
此外,您无法存储在struct item
另一个struct item
中,因为该结构尚未定义且无法确定结构的大小:
无法完成:
typedef struct item
{
type data;
struct item next;
} Item;
因此使用指针是因为在编译结构时可以确定指针的大小(该平台上的整数的大小)。
答案 4 :(得分:3)
您不需要指针来在C中创建列表。如果指针列表更可取,取决于您的应用程序。人们在使用语言实现指针概念之前使用了链表。对于某些人(使用指针)来说,有时候只能理解它。您不需要具有数据的结构。
一个简单的数组就可以了。你需要:
-1
(在指针术语中表示nil
或NULL
),或0 .. N-1
表示:链接的下一个元素的数组索引。 索引数组的索引表示数据数组中项的索引。这就是你所需要的一切。
数组而不是指针列表可能有
请阅读here。
因此,您的示例将如下所示:
type data[N]; // or: type *data = new type [N];
int links[N]; // or: int *links = new int [N];
这应该是从一个简单的测试用例开始所需的全部内容。
答案 5 :(得分:1)
c
中指针的重要性的优点: -
执行速度会很快。
指针允许我们访问函数之外的变量。
减少代码的大小。
没有指针: -
代码大小会增加。
我们无法有效维护数据。
在列表中,指针用于指向列表中的下一个项目。如果未声明指针,则表示您无法从列表中访问多个项目。
如果你在运行时动态分配一些内存,那么指针就非常需要。
答案 6 :(得分:0)
有不止一种“清单”。您显示的实现是“链接列表”。没有指针就没有“链接”,所以我们需要查看其他类型的列表。
所以,首先,如果你只是从结构定义中删除*
会发生什么:它不会编译。你可以在另一个结构中包含一个结构,但是如果有递归那么结构将具有不会发生的无限大小!
如何将数组作为列表:
struct item list[100];
是的,这会奏效,但现在你的清单是固定的。
好的,让我们动态分配列表:
struct item *list = malloc(sizeof(struct item));
然后,每次添加到列表时,您都必须执行此操作:
list = realloc(list, newcount * sizeof(struct item));
list[newitem] = blah;
好的,这有效,但现在我们经常重新分配内存,导致大量内存副本和效率低下。
另一方面,如果列表很少更新,这样更节省空间,这可能是一件好事。
使用数组的另一个缺点是诸如推,弹,排序,反转等操作变得更加昂贵;它们都意味着多个内存副本。
还有其他类型的“列表”,但它们都涉及指针,所以我想我们可以在这里忽略它们。