剑指offer算法题之单链表的删除结点操作--面试题13:在O(1)时间删除链表结点
来源:互联网 发布:linux 重启apache命令 编辑:程序博客网 时间:2024/06/06 18:09
题目如下:
- 常见删除链表结点的顺序遍历法
单链表最常见的删除结点操作:就是从链表的头结点开始,顺序遍历查找要删除的结点,找到该结点后删除即可。
如下图(a)所示链表中,我们想删除链表结点i,可以从链表的头结点a开始顺序遍历 ,发现h结点的m_pNext指针指向的结点就是i结点,于是我们可以安全的删除结点i,把指针指向下一个结点j。指针调整之后我们就可以安全的删除结点i,并保证链表没有断开,这就是顺序查找的思路,因此时间复杂度就是O(n)。- O(1)的删除结点法
我们之所以需要从头开始查找,是因为我们需要得到将被删除的结点的前面一个结点。因为在单链表中没有指向前面结点的指针,所以只能从头结点开始顺序查找。但是根据本题提供的条件,我们发现,本题提供了删除结点的指针,也就是说删除几点后面的结点很容易找到。那么我们的解决思路是这样的:我们要删除结点i,先把i的下个结点j的值复制到结点i上,然后把j结点删除(也就是把i的指针指向结点j的下个结点,然后删除结点j),这样达到的效果刚好是把结点i删除了。
上面这种删除方式存在一种特殊情况,当删除的结点在链表的尾部的时候,此结点后面的结点内容是空,因此没办法进行复制,因此这种情况是需要用顺序遍历删除结点的。
最后注意,如果链表只存在一个结点,删除后我们需要把链表的头结点设置为NULL。
在编写代码过程中,需要注意的问题:
1、创建链表结点模块,因为链表结点里面包含数据域和指针域,因此需要动态申请空间。
2、输出链表各结点的模块中,输出函数语句:
printf(“%d \t”,pNode->m_nKey); 中的’\t’表示后面空四个字符。
3、由于上面申请了内存空间,为了防止内存泄漏,需要在程序结束时释放内存空间,也就是delete整个链表的每个结点。4、O(1)的删除链表结点模块,也是本题考查的主要算法。共分为三种情况:1)删除结点在链表中间 2)删除结点的链表只含一个结点 3)删除结点在链表的末尾。
1) 首先找到删除结点后驱结点的后驱结点:
ListNode* pDoubleNext=pNext->m_pNext ; 接着把后驱结点的值复制给删除结点,最后把删除结点的指针指向pDoubleNext 。最后注意释放 (pToBeDeleted->m_nKey)。
2)只有一个结点的情况,直接删除头结点,然后把链表置空。
3)当删除结点是最后一个结点时,使用顺序查找找到最后一个结点,然后删除即可,同时也注意对删除结点释放空间。列表内容
- 整个系统(包括链表的建立,链表结点的删除,链表结点的输出)代码如下:
#include "stdafx.h"#include <list>struct ListNode { int m_nKey; ListNode* m_pNext; };//创建链表结点ListNode* CreateListNode(int value){ if(value==NULL) exit(1); ListNode* pNode=new ListNode;//申请空间存储数据 pNode->m_nKey=value; pNode->m_pNext=NULL; return pNode;}//链接各结点,生成链表void ConnectListNodes(ListNode* pNode , ListNode* pNext){ if(pNode==NULL) exit(1); pNode->m_pNext=pNext;}//输出链表各结点void PrintList(ListNode* pHead){ printf("PrintList starts.\n"); ListNode* pNode=pHead; while(pNode!=NULL) { printf("%d \t",pNode->m_nKey); pNode=pNode->m_pNext; } printf("\nPrintList ends.\n");}//输出链表单个结点void printListNode(ListNode* pNode){ printf("%d \n",pNode->m_nKey);}void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted){ if(!pListHead||!pToBeDeleted) return; ListNode* pNext=pToBeDeleted->m_pNext; //删除的结点不是链表尾结点 if(pNext->m_nKey) { ListNode* pDoubleNext=pNext->m_pNext; pToBeDeleted->m_nKey=pNext->m_nKey; pToBeDeleted->m_pNext=pDoubleNext; free(pNext);// return ; } //链表只有一个结点 else if(* pListHead==pToBeDeleted) { delete * pListHead; pToBeDeleted=NULL; * pListHead=NULL; } //删除的结点是最后一个结点 else { ListNode * tmp= * pListHead; //ListNode * pretmp; //此处排除一个结点的情况,因此判断应该是头结点后一个结点开始的 while(tmp->m_pNext!=pToBeDeleted) { // pretmp=tmp; tmp=tmp->m_pNext; } tmp->m_pNext=NULL; free(pToBeDeleted); return ; }}//生成测试模块void Test(ListNode* pHead,ListNode* pDeleteNode){ printf("the original list is : \n"); PrintList(pHead); printf("the node to be delete is : \n"); printListNode(pDeleteNode); DeleteNode( &pHead ,pDeleteNode);// printf("the result list is : \n"); PrintList(pHead);}// 链表中有多个结点,删除中间的结点void Test1(){ ListNode* pNode1 = CreateListNode(1); ListNode* pNode2 = CreateListNode(2); ListNode* pNode3 = CreateListNode(3); ListNode* pNode4 = CreateListNode(4); ListNode* pNode5 = CreateListNode(5); ConnectListNodes(pNode1, pNode2); ConnectListNodes(pNode2, pNode3); ConnectListNodes(pNode3, pNode4); ConnectListNodes(pNode4, pNode5); Test(pNode1, pNode3); //DestroyList(pNode1);}int main(){ Test1(); system("pause"); return 0;}
- 剑指offer算法题之单链表的删除结点操作--面试题13:在O(1)时间删除链表结点
- 剑指Offer学习之面试题13 :在O(1)时间删除链表结点
- 剑指offer之面试题13在O(1)时间删除链表结点
- 剑指Offer之面试题13:在O(1)时间删除链表结点
- 【剑指Offer学习】【面试题13 :在O(1)时间删除链表结点】
- 剑指offer 面试题13:在O(1)时间删除链表结点(C++版)
- 剑指offer-面试题 13:在 O( 1)时间删除链表结点
- 剑指offer--面试题13:在O(1)时间删除链表结点
- 剑指Offer面试题13[在O(1)时间删除表的结点]
- [剑指offer][面试题13]在O(1)时间删除链表结点
- 《剑指Offer》面试题13:在O(1)时间删除链表结点
- 《剑指Offer》学习笔记--面试题13:在O(1)时间删除链表结点
- 剑指offer--面试题13:在O(1)时间删除链表结点--Java实现
- 剑指offer-面试题13:在O(1)时间删除链表结点
- 剑指Offer----面试题13:在O(1)时间删除链表结点
- 剑指Offer:面试题13——在O(1)时间删除链表结点
- 剑指offer面试题13:在O(1)时间删除链表结点
- 剑指offer——面试题13:在O(1)时间删除链表结点
- Leetcode 464. Can I Win
- 选择排序
- 一些java基础错题总结
- day04错误处理、环境表、内存管理技术
- 解决myeclise对js的报错问题
- 剑指offer算法题之单链表的删除结点操作--面试题13:在O(1)时间删除链表结点
- odoo10 基本字段
- 2017.07.30 总结
- 2017.7.30
- leetcode 剑指offer重复题目
- dump
- 摄像机标定学习笔记(5) 关于张正友平面标定方法
- day05内存管理技术
- 凸包的直径——旋转卡壳