(C++)剑指offer—删除链表中的重复节点(不保留重复节点)

删除链表中的重复节点(不保留重复节点)

例如:
原链表为:1->2->2->3->3->4
新链表为:1->4
网上找了关于这个题目的解答,答案五花八门,感觉或多或少有些问题(要么考虑不全,要么没有内存管理),于是下定决心自己写一个,当然别人的过程也会对自己有一点启发。由于代码中注释较为详细,话不多说,直接上菜

//对已排好序的链表,删除重复节点(不保留重复节点)
#define _CRTDBG_MAP_ALLOC//检测内存泄漏
#include<iostream>
using namespace std;
//定义节点类
class ListNode
{
public:
	ListNode(int value, ListNode* pNext)//有参构造
	{
		this->m_Value = value;
		this->m_pNext = pNext;
	}
	int m_Value;
	ListNode* m_pNext;
};
//删除重复节点函数(传入头结点,返回头结点)
ListNode* deleteDuplication(ListNode* head)
{
	//如果头结点或头结点的下个节点为空,直接返回头结点
	if (head == NULL || head->m_pNext == NULL)
		return head;
	//为防止头结点即是重复节点,创建一个root节点,且root->m_pNext=head
	ListNode* root = new ListNode(0, head); m_Value值随意,这只是一个辅助根节点
	ListNode* pre = root;
	ListNode* cur = head;  //当前节点cur从头结点开始,依次向下判断
	while (cur != NULL && cur->m_pNext != NULL)//两者缺一不可
	{
		//不相等最简单,直接往后推
		if (cur->m_Value != cur->m_pNext->m_Value)
		{
			pre = pre->m_pNext;
			cur = cur->m_pNext;
		}
		else
		{
			//注意:重复节点可能不止两个,也许有若干个连续重复的节点,需要while循环,一个个找出来
			//此时cur指向的是第一个重复的节点
			while (cur->m_pNext != NULL && cur->m_Value == cur->m_pNext->m_Value)
			{
				ListNode* temp = cur; //用临时指针指向cur,便于后面释放cur内存
				cur = cur->m_pNext;   //更新cur,使它指向第二个重复的节点
				delete temp;          //释放前一个cur内存
			}
			//此时cur指向相同节点的最后一个,而在上面的while循环中并没有释放掉这块内存
			ListNode* temp = cur;     //temp指向当前节点(上面的while并没有释放最后一个相同值的内存)
			pre->m_pNext = cur->m_pNext;
			cur = cur->m_pNext;       //此时cur指向重复节点之后的新的节点(3)
			delete temp;              //temp(cur)中的内容已经保存好后,释放
		}
	}
	//删除完之后,由于root->m_pNext才是真正的根节点,因此需要返回root->m_pNext
	//由于root是辅助的根节点,需要释放,因此先保存root下面的m_pNext,再释放root
	ListNode* newHead = root->m_pNext;
	delete root;
	return newHead;
}
//遍历链表中的m_Value值
void DisplayList(ListNode* head)
{
	if (head == NULL)
		return;
	ListNode* temp = head;
	while (temp != NULL)
	{
		cout << temp->m_Value << " ";
		temp = temp->m_pNext;
	}
	cout << endl;
}
//测试函数
void test()
{
	//简单制作一个链表,头结点为node1,尾节点为node5
	ListNode* node5 = new ListNode(3, NULL);
	ListNode* node4 = new ListNode(3, node5);
	ListNode* node3 = new ListNode(2, node4);
	ListNode* node2 = new ListNode(2, node3);
	ListNode* node1 = new ListNode(1, node2);
	cout << "删除前:" << endl;
	DisplayList(node1);
	ListNode* newHead = deleteDuplication(node1);
	cout << "删除后:" << endl;
	DisplayList(newHead);
}
int main()
{
	//_CrtSetBreakAlloc(159);//定位泄漏位置
	test();
	_CrtDumpMemoryLeaks(); //检测内存是否发生泄漏
	system("pause");
	return 0;
}

大家可以多试验几种情况,我试验多种情况均无误。

内存泄漏方面

除了链表中未删除的节点之外,其他无内存泄漏。
具体检测方法:由于我用的是VS,所以调试以上代码后在VS的输出区往上翻会有
在这里插入图片描述
中括号里的159即是内存泄漏位置,大家可以将第88行的注释去掉,再运行时就会针对node1产生中断,说明node1处有内存泄漏,当然不同环境可能这个值不一样,具体根据输出结果改动。

此问题的另一种情况

当然这个问题的另一种情况是删除重复节点,并保留一个重复节点,例如:
原链表为:1->2->2->3>3;
删除后为:1->2->3;
关于这个问题,大家可以参考我的另一篇文章
https://blog.csdn.net/weixin_43459041/article/details/107349795

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值