当我们仅拥有欲删除节点的指针而非前置节点指针时,是否可能在单链表中删除中间节点?删除后,前置节点应指向被删除节点的下一个节点。
当我们仅拥有欲删除节点的指针而非前置节点指针时,是否可能在单链表中删除中间节点?删除后,前置节点应指向被删除节点的下一个节点。
这肯定更像是一道问答题而不是一个真正的问题。但是,如果我们允许做一些假设,它可以在O(1)时间内解决。为了实现这一点,列表指向的结构必须是可复制的。算法如下:
我们有一个类似于以下结构的列表: ... -> Node(i-1) -> Node(i) -> Node(i+1) -> ...,我们需要删除Node(i)。
伪代码:
void delete_node(Node* pNode)
{
pNode->Data = pNode->Next->Data; // Assume that SData::operator=(SData&) exists.
Node* pTemp = pNode->Next->Next;
delete(pNode->Next);
pNode->Next = pTemp;
}
迈克。
假设有这样一个结构的列表:
A -> B -> C -> D
如果你只有指向B的指针并想要删除它,你可以尝试这样做:
tempList = B->next;
*B = *tempList;
free(tempList);
那么列表看起来将会是:
A -> B -> D
但B将保留C的旧内容,从实质上删除了B中原有的内容。如果其他代码段持有指向C的指针,这种方法就不起作用。如果您试图删除节点D,也不会起作用。如果想要进行此类操作,则需要使用一个虚拟的尾节点来构建列表,该节点并不真正使用,以便确保没有有用的节点具有NULL下一个指针。这对于存储在节点中的数据量较小的列表效果更好,如:
struct List { struct List *next; MyData *data; };
可能没问题,但是其中
struct HeavyList { struct HeavyList *next; char data[8192]; };
可能会有点繁琐。
不可能。
有一些黑科技可以模拟删除。
但是它们都不会真正删除指针所指向的节点。
如果你在列表中有外部指针指向节点,那么删除后面的节点并将其内容复制到要删除的实际节点的常见解决方案会产生副作用,此时指向后续节点的外部指针将会变得悬空。
一种方法是在数据中插入一个空值。每当您遍历列表时,都会跟踪上一个节点。如果您发现空数据,则修复列表并转到下一个节点。
如果您想保持列表的可遍历性,就不能这样做。您需要更新前一个节点以链接到下一个节点。
你怎么会陷入这种情况呢?你在尝试做什么让你问这个问题?
你必须顺着链表向下遍历寻找前一个节点。这会使得删除操作的时间复杂度变为O(n**2)。如果你是唯一进行删除操作的代码,实践中你可以通过缓存前一个节点并从那里开始搜索来提高效率。但是否能带来好处取决于删除操作的模式。