【单链表四道经典例题(必会)】

本文详细介绍了四个关于单链表的经典问题:逆置单链表、判断链表相交、检测回文链表以及查找链表环。通过基本思想和代码实现,展示了如何解决这些问题。对于链表相交,通过比较尾节点和计算链表长度判断;对于回文,采用双指针法对比;对于环问题,利用快慢指针检测。这些方法有助于深入理解链表操作。
摘要由CSDN通过智能技术生成

①逆置单链表
②链表的相交问题
③判断链表是否存在回文
④链表的环问题

第一道题: 逆置单链表

<1> 基本思想:我们将单链表的节点从前到后全部头插一次即可。
在这里插入图片描述
<2> 代码实现

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<assert.h>

typedef struct List
{
	int data;
	struct List* next;
}List,*PList;

void Init_List(PList L)
{
	assert(L != NULL);
	L->next = NULL;
}

void Insert_tail(PList L, int val)
{
	assert(L != NULL);
	struct List* pnewnode = (struct List*)malloc(sizeof(List) * 1);
	assert(pnewnode != NULL);
	pnewnode->data = val;

	struct List* p = L;
	for (p; p->next != NULL; p = p->next);

	pnewnode->next = p->next;
	p->next = pnewnode;
}

void Reverse(PList L)
{
	assert(L != NULL);
	struct List* p = L->next;
	L->next = NULL;

	struct List* q = p->next;
	while (p != q)
	{
		p->next = L->next;
		L->next = p;
		p = q;
		if (q->next != NULL)
		{
			q = q->next;
		}
	}
	p->next = L->next;
	L->next = p;
}

void Show(PList L)
{
	assert(L != NULL);
	struct List* p = L->next;
	for (p; p != NULL; p = p->next)
	{
		printf("%d ", p->data);
	}
	printf("\n\n");
}

int main()
{
	List head;
	Init_List(&head);
	printf("初始表:");
	Insert_tail(&head, 1);
	Insert_tail(&head, 3);
	Insert_tail(&head, 5);
	Insert_tail(&head, 7);
	Insert_tail(&head, 9);
	Show(&head);

	printf("逆置后:");
	Reverse(&head);
	Show(&head);
	return 0;
}

<3> 结果演示
在这里插入图片描述
第二道题 链表的相交问题
(1)判断两个链表是否相交?
(2)如果相交请找到相交的节点。

**<1>**基本思想:
(1)若两个链表相交则尾节点一定相等
在这里插入图片描述
(2)先比较两个链表的长度,定义两个指针变量,分别指向两个链表,让长的那个链表先走(长 - 短)长度的节点,然后两个指针一起向后走,当两个指针相遇时,则为相交的节点

<2> 代码实现

bool Intersect(PList L1, PList L2)
{
	struct List* p = L1;
	struct List* q = L2;

	for (p; p->next != NULL; p = p->next);
	for (q; q->next != NULL; q = q->next);

	if (p == q)
	{
		return true;
	}
	else
	{
		return false;
	}
}

int getsize(PList L)
{
	struct List* p = L->next;
	int length = 0;
	for (p; p != NULL; p = p->next)
	{
		length++;
	}
	return length;
}

struct List* getsect(PList L1, PList L2)
{
	int length1 = getsize(L1);
	int length2 = getsize(L2);

	struct List* p = length1 > length2 ? L1->next : L2->next;
	struct List* q = length1 > length2 ? L2->next : L1->next;

	for (int i = 0; i < abs(length1 - length2); i++)
	{
		p = p->next;
	}

	while(p != q)
	{
		p = p->next;
		q = q->next;
	}
	return p;
}

第三道题 判断链表是否存在回文

<1> 基本思想: 将单链表中的数据全部放到一个数组中,分别定义两个变量保存开始的下标和最后一个数据的下标,分别从前向后,从后向前,一一对比,若相等则分别走一次继续比较,(若不相等直接退出,即没有回文),直到两个变量相等或者交叉停止,返回真,即有回文。

<2> 代码实现

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<stdbool.h>

typedef struct List
{
	int data;
	struct List* next;
}List, * PList;

void Init_List(PList L)
{
	L->next = NULL;
}

void Insert_tail(PList L,int val)
{
	struct List* pnewnode = (struct List*)malloc(sizeof(List));
	pnewnode->data = val;
	struct List* p = L;
	for (p; p->next != NULL; p = p->next);
	pnewnode->next = p->next;
	p->next = pnewnode;
}

int getsize(PList L)
{
	struct List* p = L->next;
	int length = 0;
	for (p; p != NULL; p = p->next)
	{
		length++;
	}
	return length;
}

bool Identify(PList L)
{
	int length = getsize(L);
	int* ar = (int*)malloc(sizeof(int) * length);
	struct List* p = L->next;
	int i = 0;
	for (p; p!= NULL; p = p->next)
	{
		ar[i++] = p->data;
	}

	int left = 0;
	int right = length - 1;
	while (left < right)
	{
		if (ar[left] != ar[right])
		{
			return false;
		}
		else
		{
			left++;
			right--;
		}
	}
	return true;
}

int show(PList L)
{
	struct List* p = L->next;
	for (p; p != NULL; p = p->next)
	{
		printf("%d ", p->data);
	}
	printf("\n");
}

int main()
{
	List head;
	Init_List(&head);
	Insert_tail(&head, 1);
	Insert_tail(&head, 2);
	Insert_tail(&head, 3);
	Insert_tail(&head, 2);
	Insert_tail(&head, 1);

	show(&head);

	if (Identify(&head))
	{
		printf("存在回文\n");
	}
	else
	{
		printf("不存在回文\n");
	}
	return 0;
}

<3> 结果演示
在这里插入图片描述

第四道题 链表的环问题
(1)判断链表是否存在环
(2)若存在,找到入环节点

<1> 基本思想
(1)使用快慢指针来判断是否存在环,一个慢指针一次让他走一个节点,一个快指针一次让他走两个节点,若存在环则两指针会相等,只要快指针为NULL则不存在环

在这里插入图片描述
(2)在这里插入图片描述

<2> 代码实现

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<stdbool.h>
#include<assert.h>

typedef struct List
{
	int data;
	struct List* next;
}List, * PList;

void Init_List(PList L)
{
	L->next = NULL;
}

List* haveCirde(PList L)
{
	assert(L->next->next != NULL);
	struct List* slow = L->next;
	struct List* fast = L->next->next;

	while (fast != NULL && fast != slow)
	{
		slow = slow->next;
		if (fast->next == NULL)
		{
			return NULL;
		}
		else
		{
			fast = fast->next->next;
		}
	}
	if (fast == NULL)
	{
		return NULL;
	}
	else
	{
		printf("存在环");
	}

	struct List* p = L->next;
	struct List* q = fast;
	while (p != q)
	{
		p = p->next;
		q = q->next;
	}
	return q;
}

这四道题都是单链表中比较经典的题目,希望这篇博客能帮助大家更好的学习这些题目。
感谢阅读!

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逐梦的白鹰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值