【问题标题】:How to properly use sentinel nodes?如何正确使用哨点节点?
【发布时间】:2018-03-29 22:17:45
【问题描述】:

会有多个(密切相关的)问题,而不是一个问题。为了我们的舒适,我会相应地给它们编号。

基于this Wikipedia articlethis question和讲座,我想我已经理解了哨兵节点背后的想法以及它们在链表中的用法。但是,即使在阅读了这些材料后,我仍然不清楚一些事情。

我得到了一个双向链表的基本实现(它只存储 int 值),任务是更改实现,使其使用如下哨兵节点:

Illustrative image(还不能嵌入图片,抱歉)

问题 1

我假设列表的head 变量将指向第一个真实节点(在哨兵节点之后的那个),而tail 变量将简单地指向最后一个节点。我是正确的还是应该 head 指向哨兵节点?我在这里寻求最佳实践或最标准的方法。

问题 2

我了解在列表中搜索值时,我不再需要检查 nullptr,因为我使用的是哨兵节点。由于列表由于哨兵节点而基本上形成了一个圆圈,因此我必须在遍历整个列表并到达它之后终止它。我可以通过将我正在寻找的值放在哨兵节点中并将其用作排序的哨兵值然后检查循环结束时是否从哨兵节点返回结果来做到这一点吗?一些消息来源声称哨点节点根本不应该存储任何值。我的方法是否正确/合理有效?

问题 3

当简单地迭代而不搜索特定值(例如计算节点,将整个列表输出到控制台)时,我是否必须像检查 nullptr 一样检查哨兵节点(以终止迭代循环)还是有不同的或更聪明的方式来做到这一点?

【问题讨论】:

  • 只是出于好奇,在您的图像中,为什么列表的最后一个节点没有指向哨兵的下一个 ptr?
  • 这是个好问题,我什至没有注意到(我不是它的创造者)。我会自动假设最后一个元素的“下一个”将是哨兵节点,而哨兵节点的“上一个”将是最后一个元素。所以它会形成一个圆圈。
  • 好的,那么在这种情况下,这不仅仅是一个双向链表,而是引入哨兵将使它成为一个修改后的循环双向链表

标签: c++ algorithm data-structures linked-list sentinel


【解决方案1】:

回答 1

是的,这是哨兵节点采取的有效位置。 headtail 可以指向数据的实际开始和结束。但是您的adddelete 函数需要注意由于哨兵节点在列表边界处引起的异常

回答 2

是的,这是一个有效的搜索策略,实际上被称为Elephant in Cairo 技术

答案 3

是的,哨兵节点的目的是让你知道它是哨兵节点。您可以只维护一个指向此哨兵节点的常量指针(或您选择的任何语言支持),以检查您是否在哨兵节点,或者只是在节点中粘贴一个标志。

【讨论】:

  • 广告答案 3 - 向通用节点结构/类添加一个标志,例如 isSentinel 并检查它?
  • 老实说,我更喜欢指针方法,因为它做的假设更少,但是是的,如果这是不可能的,那么像你建议的那样的标志将在哨兵节点是常规的特殊类的情况下工作节点。
  • 在我的情况下,指针方法似乎更容易,谢谢。甚至可以在不循环列表的情况下有效地使用单个哨兵节点吗?我不这么认为,但也许我错了。
  • 您能详细说明一下吗?如果您的哨兵节点位于列表的开头/结尾,则其目的是通知您,当您通过它时,您已经成功地“循环”了一次列表。我会说哨兵最有效地达到了它的目的,你有什么想法?
  • 我的意思是从技术上讲你可以,但是你的哨兵的效率会大大降低,你有两种类型的残局需要检查。如果您的哨兵将坐在开头而不是最后,那么您必须在末尾检查null,如果哨兵坐在最后,则相反。理想情况下,这种情况下的哨兵策略是替换检查 null,所以我不建议这样做
猜你喜欢
  • 1970-01-01
  • 2014-07-27
  • 2016-03-03
  • 1970-01-01
  • 1970-01-01
  • 2016-04-21
  • 1970-01-01
  • 1970-01-01
  • 2019-10-28
相关资源
最近更新 更多