C语言笔记35 •单链表经典算法OJ题•

1.合并两个升序链表

问题:

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

代码实现:

ListNode* lowlisthead=(ListNode*)malloc(sizeof(ListNode));

新颖之处就是创建头节点(哨兵位)能够减少代码,不用每次都判断链表是否为NULL,

注意的是:最后函数的返回值是头节点的下一个地址(lowlisthead->next)

//========1.合并两个升序链表(创建头节点 简化代码)==========
typedef int SLTDataType;
 
typedef struct SListnode
{
	SLTDataType val;
	struct SListnode* next;
}ListNode;
 
ListNode* createNode(SLTDataType val)
{
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
	if (newnode == NULL)
	{
		perror("malloc");
		exit(1);
	}
	newnode->val = val;
	newnode->next = NULL;
	return newnode;
}
 
ListNode* mergeTwoLists(ListNode* L1, ListNode* L2)
{
	ListNode* lowlisthead=(ListNode*)malloc(sizeof(ListNode));
	ListNode* pcur = lowlisthead;
 
	while (L1 && L2)
	{
		if (L1->val < L2->val)
		{
		
			pcur->next = L1;
			pcur = pcur->next;
			L1 = L1->next;
		}
		else
		{
			pcur->next = L2;
			pcur = pcur->next;
			L2 = L2->next;
		}
		//pcur = pcur->next; 不能将判断语句里面的节点指针的移动 放在这里 ,确保在每次链接节点后正确地移动当前指针 pcur
	}
	if (L1)
	{
		pcur->next = L1;
	}
	if (L2)
	{
		pcur->next = L2;
	}
	return lowlisthead->next;
 
}
 
int main()
{
	ListNode* list1, * list2;//创建两个链表
 
	list1 = createNode(1);
	list1->next = createNode(2);
	list1->next->next = createNode(4);
 
	list2 = createNode(1);
	list2->next = createNode(3);
	list2->next->next = createNode(5);
 
	ListNode* head = mergeTwoLists(list1, list2);
	while (head)
	{
		printf("%d ", head->val);
		head = head->next;
	}
	return 0;
}

//2.合并两个升序链表(不创建头节点)
 
typedef int SLTDataType; 
 
typedef struct SListnode
{
	SLTDataType val;
	struct SListnode* next;
}ListNode;
 
ListNode* createNode(SLTDataType val)
{
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
	if (newnode == NULL)
	{
		perror("malloc");
		exit(1);
	}
	newnode->val = val;
	newnode->next = NULL;
	return newnode;
}
 
//ListNode* mergeTwoLists(ListNode* L1, ListNode* L2)
//{
//	ListNode* lowlisthead, * highlisthead;
//	lowlisthead = highlisthead = NULL;
//	
//	ListNode* pcur1, *pcur2;
//	pcur1 =lowlisthead;
//	pcur2 = highlisthead;
//	while(L1 && L2)
//	{
//		if (L1->val < L2->val)
//		{
//			if (lowlisthead == NULL)
//			{
//				lowlisthead = L1;
//			}
//			else
//			{
//				pcur1->next = L1;
//				pcur1 = pcur1->next;
//			}
//			L1 = L1->next;
//		}
//		else
//		{
//			if (highlisthead == NULL)
//			{
//				highlisthead = L2;
//			}
//			else
//			{
//				pcur2->next = L2;
//				pcur2 = pcur2->next;
//			}
//			L2 = L2->next;
//		}
//	}
//	if (L1)
//	{
//		pcur1->next = L1;
//	}
//	if (L2)
//	{
//		pcur2->next = L2;
//	}
//
//}
 
ListNode* mergeTwoLists(ListNode* L1, ListNode* L2)
{
	ListNode* lowlisthead, * pcur;
	pcur = lowlisthead= NULL;
	
	while (L1 && L2)
	{
		if (L1->val < L2->val)
		{
			if (lowlisthead == NULL)
			{
				lowlisthead = pcur = L1;
			}
			else
			{
				pcur->next = L1;
				pcur = pcur->next;
			}
			L1 = L1->next;
		}
		else
		{
			if (lowlisthead == NULL)
			{
				lowlisthead = pcur = L2;
			}
			else
			{
				pcur->next = L2;
				pcur = pcur->next;
			}
			L2 = L2->next;
		}
		//pcur = pcur->next; 不能将判断语句里面的节点指针的移动 放在这里 ,确保在每次链接节点后正确地移动当前指针 pcur
	}
	if (L1)
	{
		pcur->next = L1;
	}
	if (L2)
	{
		pcur->next = L2;
	}
	return lowlisthead;
 
}
 
int main()
{
	ListNode* list1,*list2;//创建两个链表
 
	list1 = createNode(1);
	list1->next= createNode(2);
	list1->next->next = createNode(4);
 
	list2 = createNode(1);
	list2->next = createNode(3);
	list2->next->next = createNode(5);
 
	ListNode* head = mergeTwoLists(list1, list2);
	while(head)
	{
		printf("%d ", head->val);
		head = head->next;
	}
	return 0;
}

2.移除链表元素

问题:

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

代码实现:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
 
 
 
typedef int SLTDataType;
 
typedef struct SListnode
{
	SLTDataType val;
	struct SListnode* next;
}ListNode;
 
ListNode* createNode(SLTDataType val)
{
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
	if (newnode == NULL)
	{
		perror("malloc");
		exit(1);
	}
	newnode->val = val;
	newnode->next = NULL;
	return newnode;
}
 
 
 
struct ListNode* removeElements(struct ListNode* head, int val)
{
	ListNode* pur = head;
 
	ListNode* newhead, *newtail;//创建新链表
	newhead = newtail = NULL;//表头 表尾初始化
 
	while (pur)
	{
		if (pur->val != val)
		{
			if (newhead == NULL)
			{
				newhead = newtail = pur;
			}
			else
			{
				newtail->next = pur;
				newtail = newtail->next;
			}
		}
		pur = pur->next;
	}
	if (newtail)
	{
		newtail->next=NULL;
	}
	return newhead;
}
 
int main()
{
	ListNode* node1, * node2, * node3, * node4, * node5, * node6, * node7;
 
	node1        =        createNode(1);
	node2 = node1->next = createNode(2);
	node3 = node2->next = createNode(6);
	node4 = node3->next = createNode(3);
	node5 = node4->next = createNode(4);
	node6 = node5->next = createNode(5);
	node7 = node6->next = createNode(6);//创建一个链表
 
	ListNode* newhead = removeElements(node1, 6);//移除链表元素:6
 
	while (newhead)
	{
		printf("%d ", newhead->val);
		newhead = newhead->next;
	}
	return 0;
}

3. 反转链表

问题:

给你单链表的头节点 head,请你反转链表,并返回反转后的链表。

 代码实现:

//3.反转链表
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
 
 
 
typedef int SLTDataType;
 
typedef struct SListnode
{
	SLTDataType val;
	struct SListnode* next;
}ListNode;
 
ListNode* createNode(SLTDataType val)
{
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
	if (newnode == NULL)
	{
		perror("malloc");
		exit(1);
	}
	newnode->val = val;
	newnode->next = NULL;
	return newnode;
}
 
 
 
struct ListNode* reverseList(struct ListNode* head)
{
	if (head == NULL)
	{
		return head;
	}
	ListNode* n1,*n2,*n3 ;
	n1= NULL, n2=head, n3=n2->next;//创建三个节点
	while (n2)
	{
		n2->next = n1;// 指针逆向
		n1 = n2;
		n2 = n3;
		if (n3)
		{
			n3 = n3->next;
		}
	}
	return n1;
}
 
int main()
{
	ListNode* node1, * node2, * node3, * node4, * node5;
 
	node1 = createNode(1);
	node2 = node1->next = createNode(2);
	node3 = node2->next = createNode(3);
	node4 = node3->next = createNode(4);
	node5 = node4->next = createNode(5);//创建一个链表
 
	ListNode* newhead = reverseList(node1);//反转链表
 
	while (newhead)
	{
		printf("%d ", newhead->val);
		newhead = newhead->next;
	}
	return 0;
}

4. 查找链表的中间结点

问题:

给你单链表的头结点 head ,请你找出并返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点。

代码实现:

//4.查找链表的中间结点
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
 
 
typedef int SLTDataType;
 
typedef struct SListnode
{
	SLTDataType val;
	struct SListnode* next;
}ListNode;
 
ListNode* createNode(SLTDataType val)
{
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
	if (newnode == NULL)
	{
		perror("malloc");
		exit(1);
	}
	newnode->val = val;
	newnode->next = NULL;
	return newnode;
}
 
 
 
struct ListNode* middleNode(struct ListNode* head)
{
	if (head == NULL)
	{
		return head;
	}
	ListNode* slow, * fast;
	slow = fast= head;
	while (fast && fast->next)
	{
		slow = slow->next;
		fast = fast->next->next;
	}
	return slow;
}
 
int main()
{
	ListNode* node1, * node2, * node3, * node4, * node5, * node6;
 
	node1 = createNode(1);
	node2 = node1->next = createNode(2);
	node3 = node2->next = createNode(3);
	node4 = node3->next = createNode(4);
	node5 = node4->next = createNode(5);
	//node6 = node5->next = createNode(6);//创建一个链表
 
	ListNode* node = middleNode(node1);
	printf("%d", node->val);
 
	return 0;
}

5.分割链表

问题:

给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。你不需要 保留 每个分区中各节点的初始相对位置

代码实现:

//5.分割链表
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
 
 
 
typedef int SLTDataType;
 
typedef struct SListnode
{
	SLTDataType val;
	struct SListnode* next;
}ListNode;
 
ListNode* createNode(SLTDataType val)
{
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
	if (newnode == NULL)
	{
		perror("malloc");
		exit(1);
	}
	newnode->val = val;
	newnode->next = NULL;
	return newnode;
}
 
 
 
struct ListNode* partition(struct ListNode* head, int x)
{
	ListNode* pcur = head;
	ListNode* Lhead = (ListNode*)malloc(sizeof(ListNode));
	ListNode* Hhead = (ListNode*)malloc(sizeof(ListNode));
 
	ListNode* L1 = Lhead;
	ListNode* L2 = Hhead;
 
 
	while (pcur)
	{
		if (pcur->val < x)
		{
			L1->next = pcur;//L1相当于Lhead的末尾结点指针(初始状态都是链表的头),每进循环一次,往前走一步
			L1 = L1->next;
		}
		else
		{
			L2->next = pcur;//L2相当于Hhead的末尾结点指针(初始状态都是链表的头),每进循环一次,往前走一步
			L2 = L2->next;
		}
		pcur = pcur->next;
	}
	L2->next = NULL;//修改Hhead链表 末尾节点指向的指针进行初始化,如果没有这个,代码可能就会出现死循环 因为不确定head最后一个节点是否为Hhead链表的最后一个节点,为了保险起见 就使L2->next = NULL
	L1->next = Hhead->next;
 
	return Lhead->next;
}
 
int main()
{
	ListNode* node1, * node2, * node3, * node4, * node5, * node6;
 
	node1 = createNode(1);
	node2 = node1->next = createNode(4);
	node3 = node2->next = createNode(3);
	node4 = node3->next = createNode(2);
	node5 = node4->next = createNode(5);
	node6 = node5->next = createNode(5);//创建一个链表
 
	ListNode* newhead = partition(node1, 3);
 
	while (newhead)
	{
		printf("%d ", newhead->val);
		newhead = newhead->next;
	}
 
	return 0;
}

6.环形链表的约瑟夫问题

问题:

编号为 1 到 n 的 n 个人围成一圈。从编号为 1 的人开始报数,报到 m 的人离开。

下一个人继续从 1 开始报数。

n-1 轮结束以后,只剩下一个人,问最后留下的这个人编号是多少?

数据范围: 1≤𝑛,𝑚≤100001≤n,m≤10000

进阶:空间复杂度 𝑂(1)O(1),时间复杂度 𝑂(𝑛)O(n)

代码实现:

//6.环形链表的约瑟夫问题
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
 
 
 
 
typedef int SLTDataType;
 
typedef struct SListnode
{
	SLTDataType val;
	struct SListnode* next;
}ListNode;
 
ListNode* createNode(SLTDataType val)
{
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
	if (newnode == NULL)
	{
		perror("malloc");
		exit(1);
	}
	newnode->val = val;
	newnode->next = NULL;
	return newnode;
}
 
//创建带环链表
ListNode* createCircleList(int n)
{
	ListNode* phead= createNode(1);
	ListNode* ptail = phead;
	for (int i = 2; i <= n; i++)
	{
		ptail->next = createNode(i);
		ptail = ptail->next;
	}
	ptail->next = phead;//首尾相连,链表成环
	return ptail;
}
 
int person_num(int n,int m)
{
	ListNode* ptail = createCircleList(n);
	ListNode* pcur = ptail->next;
	int count = 1;
	while (ptail->next != ptail)
	{
		if (count == m)//销毁节点
		{
			ptail->next = pcur->next;
			free(pcur);
			pcur = ptail->next;
			count = 1;
		}
		else
		{
			ptail = ptail->next;//等价于ptail = pcur;
			pcur  = pcur->next;
			count++;
		}
	}
	return ptail->val;
 
}
 
int main()
{
	int person = person_num(5, 2);
	printf("%d", person);
 
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值