六道链表经典算法题,带你体验链表算法魅力

本文介绍了使用快慢指针解决链表的中间节点问题,以及如何删除链表中等于给定值的节点、反转链表、合并有序链表、分割链表和处理环形链表的约瑟夫问题。详细展示了相关算法和代码实现。
摘要由CSDN通过智能技术生成

第一道题

给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点

这道题读完题目的话

很多人的思路是遍历链表,根据节点个数,然后返回中间节点

但今天我们讲的思路称之为快慢指针

既然是快慢指针,那么一定有两个指针,并且两个指针的前进速度也不相同

所以在这里,快指针一次前进两个节点,慢指针一次前进一个节点

这样的话,当节点是奇数时,快指针的next指向NULL时,慢指针刚好在中间位置

当节点是偶数是,当快指针指向为NULL时,慢指针也在第二个中间节点

这样代码就完成了

第二道题

删除链表中等于给定值 val 的所有节点

这道题,读完,很多人会想,可以遍历链表,然后把等于val的节点给定点删除,然后以后成为一个新的链表,并返回新的头结点

但今天我要用的方法是重新建立一个链表,返回新链表的头结点

怎么做呢?

定义三个指针,一个头结点指针,一个尾结点,指针一个普通指针

第一个指针负责遍历链表

判断新链表是否为空,是空的就让它的头结点尾结点都等于第一个指针

如果新链表不为空,那么说明新链表的头结点已经有了数据

所以让指针赋值给尾结点的next,再让尾结点等于它的next

最后要判断一下

如果尾结点不为空,那么就说明它有它的next成员,这是让它的next指向空

最后返回头结点指针

代码如图

第三道题

反转一个单链表

大多数人的思路可能是遍历链表,然后从后往前遍历

但这个思路有局限性

因为翻转的是单链表而不是双链表。

单链表可以从前往后遍历,无法从后往前遍历

第二种思路就是遍历链表后,新建一个链表,然后不断尾插

但这个思路写下来太麻烦

所以在这里我将第三种思路

三指针反转链表

首先,我先判断n2是否为空

不为空

那么就让n2的next指向n1

修改完后让n1等于n2,n2等于n3,n3等于n3的next

然后继续判断n2是否为空

不为空

就继续让n2的next指向n1

修改完后让n1等于n2,n2等于n3,n3等于n3的next

循环进行,直到n2为空

代码如下

第四道题

将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的

很多人的思路应该是两个指针,分别指向两个链表,然后比较节点值,谁小倒插谁

在这里呢我们新思路就是创建一个新链表

我们创建两个指针,l1和l2,然后分别指向两个链表的头结点,然后创建一个新的头结点和尾结点,指向为空。

 当l1和l2相同时,就讲第一个链表插入新链表,然后让第一个链表往前遍历

当l1和l2不等时,谁小便让谁在前面

知道第一个链表为空

然后判断第二个链表是否为空

为空则返回新链表

不为空,那么就让链表而全部插入到新链表中

最后返回新链表

但是要注意,两个链表是否为空,一链表为空返回链表二,二链表为空返回链表一

第五道题

分割链表

在这里,我们的思路是创建两个链表

一个大链表,一个小链表

大于等于分装到大连表中

小于的分装到小链表中

怎么做呢?

首先是为了简化代码,不在判断是否为空

我们利用macllo函数开辟两个空间

再创建三个节点

一个节点负责遍历链表

另外两个分别指向两个开辟的空间的头节点

然后进行分装处理进行尾插

直到遍历完链表

然后再让大小链表进行连接

这里要让小链表的指针指向大链表的有效节点,而非开辟空间的第一个节点

typedef struct ListNode ListNode;
struct ListNode* partition(struct ListNode* head, int x)
{
	if (head == NULL) {
		return head;
	}
	//创建带头的大小链表
	ListNode* lessHead, * lessTail;
	ListNode* greaterHead, * greaterTail;

	lessHead = lessTail = (ListNode*)malloc(sizeof(ListNode));
	greaterHead = greaterTail = (ListNode*)malloc(sizeof(ListNode));

	//遍历原链表,将节点放到对应的原链表中
	ListNode* pcur = head;
	while (pcur)
	{
		if (pcur->val < x)
		{
			//放到小链表中
			lessTail->next = pcur;
			lessTail = lessTail->next;
		}
		else
		{
			//放到大链表中
			greaterTail->next = pcur;
			greaterTail = greaterTail->next;
		}
		pcur = pcur->next;

	}
	//防止出现死循环,要让大链表的尾next指向为空
	greaterTail->next = NULL;

	//大小链表首尾相连
	lessTail->next = greaterHead->next;
	ListNode* ret = lessHead->next;
	free(greaterHead);
	free(lessHead);
	return ret;
}

这是题的代码

由于博主忘了题在哪里了,所以就重新打了一遍

没有截图。。

第六道题

环形链表的约瑟夫问题

这道题我觉得挺有意思的

这个人有一个著名的约瑟夫问题

感兴趣的小伙伴可以去搜一搜看一看

这题的意思就是数到m的人离开后

继续从下一个人开始重新数

直到另一个m出现

一直循环

直到最后一个人

所以

我们需要创建一个关于n的不带头单向循环链表

并且逢m删除当前节点

ok

以上就是今天所讲的六道题目

代码很详细

希望对各位有帮助

看到这里

给个三连不过分吧

  • 35
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值