【问题标题】:Do we need a head node in a circular linked list我们是否需要循环链表中的头节点
【发布时间】:2018-02-19 05:26:20
【问题描述】:

我需要创建一个循环链表。但是,我不确定我是否应该拥有一个 head 节点。如果我包含一个head 节点,我将能够轻松清空所有内容。但是最后一个元素必须指向head 指向的节点?我不确定这是否会使事情变得容易或变得更难。

【问题讨论】:

  • 由于它是循环的,因此您本身不需要“头”节点。但是您在任何给定时间都需要指向列表中某个节点的指针
  • 从你有参考的节点开始释放下一个节点,直到你绕完一圈。非常类似于单链表,但不是头对尾,而是头对头
  • 如果它是单链接的,如果我们的入口点不是头部,则无法获取对先前节点的引用。如果它是双重链接的,那么任何任意节点都可以,尽管这使得搜索变得困难,因为现在你必须双向搜索
  • 要创建一个循环列表,您不需要头节点。所有元素都指向下一个节点,最后一个指向第一个节点,以找到一个元素,您可以遍历整个列表,直到到达您开始使用的那个。这意味着头部可以完全任意,列表中的每个元素都可以充当头部。需要注意的是,根据具体实现,您可能希望实现双向链表以缩短许多链表操作的执行时间
  • 无论列表如何实现,每种类型都可以用于相同的目的。因此,如果插入总是在列表的尾部,则列表的前面可能很重要。即使列表是循环的,这也可能是正确的。

标签: c pointers linked-list


【解决方案1】:

对于循环链表,头节点(在这种情况下通常称为 sentinel 节点)仅在您需要跟踪元素的插入顺序时才有用,因为要维护一个订单,你需要知道起点。

对于单链表,这通常不是考虑因素,因为如果插入顺序很重要,那么首先使列表循环没有任何意义。但是,对于 双向链接 列表,它变得很有用,因为这样您就有了一个可以在任一方向遍历的列表:LIFO 或 FIFO。

例如,带有哨兵节点的空双向循环列表如下所示:

哨兵节点是持久的,通常不携带任何有效载荷。添加节点后,列表开始如下所示:

如您所见,这允许按照插入节点的顺序(使用 next 指针)或相反的顺序(使用 prev 指针)遍历列表。

同样,对于单链表,如果需要插入顺序,那么使列表循环从一开始就违背了目的。如果不需要插入顺序,那么你必须随身携带一个哨兵节点是没有意义的,因为你从不使用它。任何旧节点都可以。

【讨论】:

    【解决方案2】:

    循环链表不需要 head 节点,因为实际上没有头。但它确实需要一个指向列表中some节点的指针,以便您可以访问所有元素。

    在释放列表方面,正常的列表扫描将在处理指向null 的节点后停止。循环列表非常相似,只是您记住了您开始的节点,因此您可以在释放指向它的节点后停止。这种野兽的伪代码如下所示:

    def deleteAll(someNode by reference):
        # Do nothing for empty list.
    
        if someNode == null:
            return
    
        # Process each node, stopping after one that points to start node.
    
        nodeToDelete = someNode
        do:
            nextNode = nodeToDelete.next
            free nodeToDelete
            nodeToDelete = nextNode
        until nodeToDelete == someNode
    
        # Mark list as empty.
    
        someNode = null
    

    【讨论】:

      猜你喜欢
      • 2023-04-02
      • 2013-08-26
      • 2012-06-08
      • 1970-01-01
      • 2013-10-28
      • 2012-03-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-06
      相关资源
      最近更新 更多