使用双指针在链表中插入一个节点
Inserting a Node in a linked list using double pointers
我最近看到了一个使用双指针从单个链表中删除节点的实现。除了使代码更美观之外,这种实现在效率方面有什么好处吗?另外,我如何实现一个类似的方法来插入一个节点到一个链表(不跟踪以前的节点)。我真的很好奇是否有更好的算法来实现这个
Node* Delete(Node *head, int value)
{
Node **pp = &head; /* pointer to a pointer */
Node *entry = head;
while (entry )
{
if (entry->value == value)
{
*pp = entry->next;
}
pp = &entry->next;
entry = entry->next;
}
return head;
}
对于只存储头而不存储尾的列表的后面插入(这意味着可以接受线性时间插入的小列表),可以通过间接引入额外的指针来消除特殊情况:
简单版本(指针指向节点的指针)
void List::push_back(int value)
{
// Point to the node link (pointer to pointer to node),
// not to the node.
Node** link = &head;
// While the link is not null, point to the next link.
while (*link)
link = &(*link)->next;
// Set the link to the new node.
*link = new Node(value, nullptr);
}
…你可以简化为:
void List::push_back(int value)
{
Node** link = &head;
for (; *link; link = &(*link)->next) {}
*link = new Node(value, nullptr);
}
与之相对的是:
复杂版本(指针指向节点)
void List::push_back(int value)
{
if (head)
{
// If the list is not empty, walk to the back and
// insert there.
Node* node = head;
while (node->next)
node = node->next;
node->next = new Node(value, nullptr);
}
else
{
// If the list is empty, set the head to the new node.
head = new Node(value, nullptr);
}
}
或者为了公平起见,删除注释:
void List::push_back(int value)
{
if (head)
{
Node* node = head;
for (; node->next; node = node->next) {}
node->next = new Node(value, nullptr);
}
else
head = new Node(value, nullptr);
}
简单版本无特殊情况
第一个版本不需要特殊的空列表的主要原因是,如果我们想象head
是空的:
Node** link = &head; // pointer to pointer to null
for (; *link; link = &(*link)->next) {}
*link = new Node(value, nullptr);
则for
循环条件立即为假,然后我们将新节点分配给head
。当使用指针指向指针时,不必在循环外单独检查这种情况。
插入排序
如果你想做一个插入排序,而不是简单地插入到后面,然后:
void List::insert_sorted(int value)
{
Node** link = &head;
for (; *link && (*link)->value < value; link = &(*link)->next) {}
// New node will be inserted to the back of the list
// or before the first node whose value >= 'value'.
*link = new Node(value, *link);
}
至于性能,不确定消除额外的分支会有多大不同,但它肯定会使代码更紧凑,并降低其圈复杂度。Linus认为这种风格"很有品味"的原因是,在C语言中,你经常需要编写链表逻辑,因为它不那么容易,而且泛化链表并不一定值得,因为我们没有类模板,所以用一种更小、更优雅、更少出错的方式来编写这些东西是很方便的。此外,它还表明您对指针的理解相当好。
这个实现除了使代码更漂亮之外在效率方面有任何好处。
没有什么可以与之比较的,很难说,但这和你从链表中删除一个节点一样有效。请注意,函数名Delete应该更准确地称为Remove,因为它实际上并没有清除它从列表中删除的节点。
一种方法是向前看。最好在Delete函数格式的示例中展示。我也可以实现插入节点的类似方法到一个链表(不跟踪前一个节点)。
void insert(Node *head, int value)
{
Node *entry = head;
while (entry)
{
if (entry->next == NULL)
{
entry->next = new Node(NULL, value);
return;
}
else if (value < entry->next->value)
{
entry->next = new Node(entry->next, value);
return;
}
entry = entry->next;
}
}
相关文章:
- 为什么我们要为avl树实现返回一个指向节点的指针,而不是void函数
- 为什么C++对链表中的下一个节点使用指针,而像 C# 或 Java 这样的语言只使用类 Node 的名称?
- 编写一个函数来删除单链表中的节点(尾部除外),仅授予对该节点的访问权限
- 创建了一个链表,但如何删除 c++ 中的"所有"节点
- 在C++的链表末尾插入一个节点
- 节点是否为空,即使它有一个值?
- 在解决链表问题时创建一个额外的节点是一个好习惯吗?
- 插入一个基本的单向链表节点似乎破坏了我的 c++ 代码?
- 在单链表前面添加一个节点后,我无法遍历每个节点
- 删除链接列表中剩余的最后一个节点
- 避免在使用链接列表从 deque 中删除最后一个节点时出现内存泄漏
- 如果我们不创建一个新节点并使用指针插入数据并建立链接(在链表中)怎么办?
- 给一个图 G 找到此图中的所有节点 blob,以便 node.color 属性 = 特定颜色
- 如何在级别上打印树,给定一个结构,该结构保存节点的值及其父节点的值,对于树中的每个节点
- 为什么T是未定义的?我正在尝试实现一个用于双链表的节点类,它不喜欢我使用友元运算符后的T
- C++中是否有一个函数可以为您获取指向该节点的所有指针的地址空间
- C++循环链表删除,计数从下一个节点开始
- 在由邻接列表表示的树中查找节点到另一个给定节点之间的路径
- 如何在 c++ 中实现 avl 树,每个节点都是另一个 avl 树
- 使用异或实现双链表,每个节点一个指针