您的位置:首页 > 其它

有一个单项的链表,在没有头结点的情况下,只知道有一个指向结点B的指针p,假设这个结点B不是尾结点,删除该节点B。

2016-03-19 20:58 731 查看
**

问题:有一个单项的链表,在没有头结点的情况下,只知道有一个指向结点B的指针p,假设这个结点B不是尾结点,删除该节点B。

**

p->data = p->next->data;
p->next = p->next->next;
free(p->next)


解析:要删除p指向的结点B,必须要将结点B前后的两个节点A和C连接起来,但是该单链表没有头结点,因此无法追溯到A,也就无法将A和C相连了。无法删除结点B,但我们可以删除B的后继结点C,并通过p->next = p->next->next重新将链表连接起来,而唯一丢失的是结点C的数据项data。因此,我们只需要将结点C的数据项取代结点B的数据项,然后将真正指向结点C的指针删除即可是实现将结点B删除。

**

扩展题目: 给定链表的头指针和一个结点指针,在O(1)时间删除该结点。

**

解析:在链表中删除一个结点,最常规的做法是从链表的头结点开始,顺序查找要删除的结点,找到之后再删除。由于需要顺序查找,时间复杂度自然是O(n)。我们之所以需要从头结点开始查找要删除的结点,是因为我们需要得到要删除的结点的前面一个结点。我们试着换一种思路。我们可以从给定的结点得到它的下一个结点。这个时候我们实际删除的是它的下一个结点,由于我们已经得到实际删除的结点的前面一个结点,因此完全是可以实现的。当然,在删除之前,我们需要把给定结点的下一个结点的数据拷贝到给定的结点中。此时,时间复杂度为O(1)。上面的思路还有一个问题:如果删除的结点位于链表的尾部,没有下一个结点,怎么办?我们仍从链表的头结点开始,顺便遍历得到给定结点的前序结点,并完成删除操作。这个时间复杂度是O(n)。题目要求在O(1)时间完成删除操作,这个算法是不是不符合要求。实际上,假设链表总共有n个结点,我们的算法在n-1总情况下时间复杂度是O(1),只有当给定的结点处于链表尾部的时候,时间复杂度为O(n)。那么平均时间复杂度[(n-1)*O(1)+O(n)]/n,仍然是O(1)。

void DeleteRandomNode(Node *pListHead, Node *pCurrent)
{
assert(pCurrent!=NULL || pListHead!=NULL);
if(pCurrent->next!=NULL)        //要删除的结点不是最后一个结点
{
Node *pNext = pCurrent->next;
pCurrent->data = pNext->data;
pCurrent->next = pNext->next;
delete pNext;
pNext = NULL;
}
else
{
Node *pNode = pListHead;
while(pNode->next!=pCurrent)       //得到要删除结点的前继结点
{
pNode = pNode->next;
}
pNode->next = NULL;
delete pCurrent;
pCurrent = NULL;
}
}


**

同类问题:假设有一个没有头指针的单链表,一个指针p指向单链表中的一个结点(不是第一个,也不是最后一个),请在该结点之前插入一个新的结点q。

**

//在p结点后添加q,然后交换p和q的数据域即可。
q->next = p->next;
p->next = q;
swap(&p->data, &q->value);


代码实例:

#include <QtCore/QCoreApplication>
#include <iostream>
#include <assert.h>
#include <malloc.h>

struct ListNode
{
int data;
ListNode *next;
};

typedef ListNode Node;

//参数必须是指向指针的指针,因为要修改指针,所以要考虑“参数本地拷贝”问题
void initList(Node **pList)
{
*pList = (Node*)malloc(sizeof(Node));
(*pList)->next = NULL;
}

//第一个参数不必是指向指针的指针,因为函数内只修改指针指向的数据,所以不用担心“参数本地拷贝”问题
void insertList(Node *pList, int data)
{
Node* pNewNode = (Node*)malloc(sizeof(Node));
pNewNode->data = data;
pNewNode->next = pList->next;
pList->next = pNewNode;
}

void DeleteRandomNode(Node *pCurrent)
{
assert(pCurrent!=NULL);
Node *pNext = pCurrent->next;
if(pNext!=NULL)
{
pCurrent->next = pNext->next;
pCurrent->data = pNext->data;
delete pNext;
pNext = NULL;
}
}

void DeleteRandomNode(Node *pListHead, Node *pCurrent) { assert(pCurrent!=NULL || pListHead!=NULL); if(pCurrent->next!=NULL) //要删除的结点不是最后一个结点 { Node *pNext = pCurrent->next; pCurrent->data = pNext->data; pCurrent->next = pNext->next; delete pNext; pNext = NULL; } else { Node *pNode = pListHead; while(pNode->next!=pCurrent) //得到要删除结点的前继结点 { pNode = pNode->next; } pNode->next = NULL; delete pCurrent; pCurrent = NULL; } }

//打印链表元素
void PrintListNormally(Node *pListHead)
{
Node *pTempNode = pListHead->next;
while(pTempNode!=NULL)
{
std::cout<<pTempNode->data<<std::endl;
pTempNode = pTempNode->next;
}
}

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);

Node *pHead = NULL;

initList(&pHead);

//int i;
for(int i=9; i>=0; i--)
{
insertList(pHead,i);
}

PrintListNormally(pHead);

std::cout<<"\n";

Node *pNext = pHead->next->next;
DeleteRandomNode(pNext);

PrintListNormally(pHead);

return a.exec();
}


参考自:

/article/8770874.html

http://www.cnblogs.com/fickleness/archive/2013/06/25/3154950.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: