剑指Offer-13-在O(1)时间删除链表结点
2015-11-11 16:55
459 查看
题目:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。链表结点与函数的定义如下:
struct ListNode {
int value;
ListNode *pNext;
};
思路:
一般的删除结点的思路为依次扫描链表,获取被删结点的前向指针,时间复杂度为O(n);
另一种思路是不实际删除本结点,而是大致采用被删结点覆盖别删结点后续结点的方式。
ListNode *t =pToBeDeleted->next;
pToBeDeleted->value = t->value;
pToBeDeleted->next = t->next;
然后删除t结点即可。
在这种思路下,被删结点实际上分为三种情况:
1、被删结点存在后续结点。时间复杂度为O(1);
2、被删结点不存在后续结点但链表有多个结点,这是仍然需要使用遍历的方式获取被删结点的前向指针,时间复杂度为O(n)。
3、被删链表只存在一个结点,这是需要删除结点并且将头指针赋NULL;
这时的时间复杂度为 O((1*【n-1】+n*【1】)/n),即O(1)。
struct ListNode {
int value;
ListNode *pNext;
};
思路:
一般的删除结点的思路为依次扫描链表,获取被删结点的前向指针,时间复杂度为O(n);
另一种思路是不实际删除本结点,而是大致采用被删结点覆盖别删结点后续结点的方式。
ListNode *t =pToBeDeleted->next;
pToBeDeleted->value = t->value;
pToBeDeleted->next = t->next;
然后删除t结点即可。
在这种思路下,被删结点实际上分为三种情况:
1、被删结点存在后续结点。时间复杂度为O(1);
2、被删结点不存在后续结点但链表有多个结点,这是仍然需要使用遍历的方式获取被删结点的前向指针,时间复杂度为O(n)。
3、被删链表只存在一个结点,这是需要删除结点并且将头指针赋NULL;
这时的时间复杂度为 O((1*【n-1】+n*【1】)/n),即O(1)。
#include <iostream> using namespace std; struct ListNode { int value; ListNode *pNext; }; /** *判断结点是否属于某链表,属于返回true,不属于返回false */ bool isExist(ListNode *pHead,ListNode *p) { bool exist = false; if(pHead == NULL || p == NULL) { exist = false; } else { while(pHead != NULL) { if(pHead->value == p->value) { exist = true; break; } pHead = pHead->pNext; } } return exist; } /** *删除链表中的某结点 */ void DeleteNode(ListNode **pHead, ListNode *pToBeDeleted) { if(pHead == NULL || pToBeDeleted == NULL) { return; } if(!isExist(*pHead,pToBeDeleted)) { //所需删除的结点不在链表中 return; } //尾结点不为空 if(pToBeDeleted->pNext != NULL) { ListNode *p = pToBeDeleted->pNext; pToBeDeleted->value = p->value; pToBeDeleted->pNext = p->pNext; delete p; p = NULL; } //链表中只存在一个结点 else if(*pHead == pToBeDeleted) { delete pToBeDeleted; *pHead = NULL; pToBeDeleted = NULL; } //链表中只包含多个结点 else { ListNode *p = *pHead; while(p->pNext != pToBeDeleted) { p = p->pNext; } p->pNext = NULL; delete pToBeDeleted; pToBeDeleted = NULL; } } /** * 向链表中插入结点 */ void insertList(ListNode **pHead,ListNode *value) { ListNode *head = *pHead; if(head == NULL) { *pHead = value; } else { while(head->pNext != NULL) { head = head->pNext; } head->pNext = value; } } /** * 向链表中插入结点 */ void insertList(ListNode **pHead,int value) { ListNode *p = new ListNode(); p->value = value; p->pNext = NULL; insertList(pHead,p); } /** * 打印链表 */ void print(ListNode *p) { while(p) { cout<<p->value<<" "; p = p->pNext; } cout<<endl; } int main() { //构造链表 ListNode *head = NULL; ListNode *p1 = new ListNode(); p1->value = 1; p1->pNext = NULL; insertList(&head,p1); ListNode *p2 = new ListNode(); p2->value = 2; p2->pNext = NULL; insertList(&head,p2); ListNode *p3 = new ListNode(); p3->value = 3; p3->pNext = NULL; insertList(&head,p3); ListNode *p4 = new ListNode(); p4->value = 4; p4->pNext = NULL; //测试实例 //1,所删结点不在链表中 //2.删除中间普通结点 //3.删除尾结点 //4,删除既是头结点又是尾结点的结点 //1,所删结点不在链表中 DeleteNode(&head,p4); print(head); //2.删除中间普通结点 DeleteNode(&head,p2); print(head); //3.删除尾结点 //此时最后一个结点已经变成p2,如果参数是p3无效 DeleteNode(&head,p2); print(head); //4,删除既是头结点又是尾结点的结点 DeleteNode(&head,p1); print(head); return 0; }
相关文章推荐
- [C/C++]反转链表
- 关于指针的一些事情
- C#实现基于链表的内存记事本实例
- C# Pointer指针应用实例简述
- C++智能指针实例详解
- C++指向函数的指针实例解析
- 关于c语言指针的两处小tip分享
- 浅析iterator与指针的区别
- 探讨C++中数组名与指针的用法比较分析
- 详解C++中的指针、数组指针与函数指针
- C语言实现带头结点的链表的创建、查找、插入、删除操作
- C++中字符串以及数组和指针的互相使用讲解
- C语言安全之数组长度与指针实例解析
- C++中指向对象的常指针与指向常对象的指针详解
- 指向变量的常指针与指向常变量的指针详细解析
- C#通过指针实现快速拷贝的方法
- C++实现简单的学生管理系统
- php中将指针移动到数据集初始位置的实现代码[mysql_data_seek]
- C#通过指针读取文件的方法
- C语言指针学习经验总结浅谈