题目描述
给定一个单向链表的头指真和结点指针,定义一个函数在O(1)的时间内删除该结点。链表,链表结点和函数定义如下:
//链表结点
typedef struct ListNode
{
int m_nValue;
struct ListNode* next;
}ListNode,*pListNode;
//函数
void DeleteNode(pListNode* pListHead, pListNode pos);
思路分析
常规做法(O(n))
假设删除结点pos所指向的结点 i ,我们的常规做法是从*pListHead开始遍历,找到 i 结点前面的那个结点,将那个pos所指向结点的指针域给它前面结点的指针域,然后释放pos所指向的结点,但是这种做法要遍历链表,时间复杂度为O(n),显然不符合条件。
代码实现
void DeleteNode(pListNode* pListHead, pListNode pos)
{
assert(pListHead != NULL);
assert(pos != NULL);
ListNode* cur = *pListHead;
//删除的结点是尾结点(链表的长度大于等于2)、
if (pos->next == NULL)
{
while (cur->next == pos)
{
cur = cur->next;
}
cur->next = NULL;
free(pos);
pos = NULL;
}
//如果链表只要一个结点,正好那个结点是要删除的结点
else
{
*pListHead = NULL;
free(pos);
pos = NULL;
}
}
覆盖数据法(O(1))
以上图作为分析,假设要删除 i 结点,我们可以将先将 i 后边的那个结点的数据域给前面的那个结点的数据域,然后删除后边的那个结点也同样可以达到目的,这样很巧妙的没有去遍历链表。但是这个思路有一个问题就是不能删除尾结点,因为尾结点后边没有可以替换删除的结点了,要删除尾结点只能从头遍历了。
代码实现
void DeleteNode(pListNode* pListHead, pListNode pos)
{
assert(pListHead != NULL);
assert(pos != NULL);
ListNode* cur = *pListHead;
ListNode* del = NULL;
//删除的结点是尾结点(链表的长度大于等于2)、
if (pos->next == NULL)
{
while (cur->next == pos)
{
cur = cur->next;
}
cur->next =NULL;
free(pos);
pos = NULL;
}
//如果链表只要一个结点,正好那个结点是要删除的结点
else if (*pListHead == pos)
{
*pListHead = NULL;
free(pos);
pos = NULL;
}
//删除的结点不是尾结点(链表的长度大于等于2)
else
{
del = pos->next;
pos->m_nValue = del->m_nValue;
pos->next = del->next;
free(del);
del = NULL;
}
}