【问题标题】:Why the first node of a linked list is declared as a pointer?为什么链表的第一个节点被声明为指针?
【发布时间】:2015-10-19 11:56:11
【问题描述】:

现在我知道为什么在定义链表时使用指针了。 仅仅因为结构不能有递归定义,如果没有指针,编译器将无法计算节点结构的大小。

struct list{
        int data;
        struct list* next;    // this is fine
};

但是当我将链表的第一个节点声明为:

struct list* head;

为什么这必须是一个指针?不能简单地声明为

struct list head;

这个地址用于进一步的用途?请澄清我的疑问。

【问题讨论】:

  • 如何表示一个空列表?
  • 那么这是第一个节点用作指针的唯一原因吗...?
  • 链接列表中的所有其他节点都是一个指针。
  • @copo: 不,因为类/结构不能声明与自身类型相同的非指针成员,因为此时它不是完全定义的类型。它只能声明一个指向其自身类型的成员。
  • 否 -- 通过将其声明为指针,您可以通过更改它指向的列表条目来移动头记录

标签: c++ c pointers linked-list structure


【解决方案1】:

你可以这样声明一个列表

struct list head = {};

但是在实现访问列表的功能时会有一些困难。他们必须考虑到第一个节点不用作列表的其他节点,并且第一个节点data的数据成员也没有使用。

通常列表的声明方式如下

struct List
{
    // some other stuff as for example constructors and member functions
    struct node
    {
        int data;
        struct node* next;    // this is fine
    } head;
};

List list = {};

或者在 C++ 中你可以简单地编写

struct List
{
    // some other stuff as for example constructors and member functions
    struct node
    {
        int data;
        struct node* next;    // this is fine
    } head = nullptr;
};

List list;

当然你可以自己定义 List 的默认构造函数。

在这种情况下,例如检查列表是否为空,定义以下成员函数就足够了

struct List
{
    bool empty() const { return head == nullptr; }

    // some other stuff as for example constructors and member functions

    struct node
    {
        int data;
        struct node* next;    // this is fine
    } head;
};

【讨论】:

  • 总而言之,表示空链表变得很复杂。
  • @copo 拥有一个实际上没有被使用的空节点并没有太大意义,而且这些函数确实让阅读其实现的读者更加困惑。
【解决方案2】:

这个问题没有明确的答案。无论哪种方式,你都可以做到。这个问题的答案取决于您希望如何组织您的链表以及您希望如何表示一个 列表。

你有两个选择:

  1. 没有“虚拟”头部元素的列表。在这种情况下,empty 列表由 head 指针中的 null 表示

    struct list* head = NULL;
    

    这就是您问题的答案:我们将其声明为 指针,以便能够通过将 head 指针设置为 null 来表示 列表。

  2. 带有“虚拟”头部元素的列表。在这种情况下,列表的第一个元素不用于存储实际的用户数据:它只是用作列表的起始“虚拟”元素。它被声明为

    struct list head = { 0 };
    

    上面表示一个空列表,因为head.next 为空并且head 对象本身“不计算在内”。

    即如果您愿意,可以这样声明。请记住,head 并不是真正的列表元素。实际元素在head 之后开始。

并且,与往常一样,请记住,当您使用非动态分配的对象时,这些对象的生命周期受范围规则控制。如果您想覆盖这些规则并手动控制对象的生命周期,那么您别无选择,只能动态分配它们,因此使用指针。

【讨论】:

  • 是的,在我看来,我们声明了一个指针,以便我们也可以表示一个空列表,如果不使用指针会变得复杂。
【解决方案3】:

简单来说,如果你的头是链表的起始节点,那么它只会包含链表开始的第一个节点的地址。这样做是为了避免一般程序员的混淆。由于头将仅包含地址,因此,它被声明为指针。但是你想要声明的方式也很好,只需相应地编码。提示:如果您稍后想要对链表进行一些更改,例如在链表开头进行删除或插入操作,您将面临问题,因为您将需要另一个指针变量。所以最好将第一个节点声明为指针。

【讨论】:

  • 是的。也代表空列表。
  • 是的..确实,您可以简单地将起点指向更新的节点:)
猜你喜欢
  • 1970-01-01
  • 2020-02-09
  • 1970-01-01
  • 1970-01-01
  • 2023-03-25
  • 2015-06-15
  • 1970-01-01
  • 1970-01-01
  • 2020-07-20
相关资源
最近更新 更多