数据结构-单链表的多指针问题

问题1:实现对单链表的逆序

思路:单链表想要逆序,本质上是改变链表中各个节点间的相互关系,而决定各个节点间相互关系的也只有不同节点间的指针,指针决定了节点的先后顺序。因此,想要实现对单链表的逆序,关键是将链表中的指针翻转过来,让从A-->B的变成从B-->A的。

整个过程的思路如下:

 代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
typedef  int SLTDateType;
struct ListNode
{
	SLTDateType data;
	struct ListNode* next;
};//首先初始化节点的结构体类型并宏定义变量类型    
struct ListNode* reverseList(struct ListNode* head)
{
	if (head == NULL)
		return NULL;//如果头指针为空的话,说明整个链表为空,也就没有研究的必要了
	struct ListNode* n1, * n2, * n3;//创建三个节点类型的指针n1,n2,n3
	n1 = NULL;
	n2 = head;
	n3 = head->next;
	while (n2)//当n2不为空指针时,循环一直继续
	{
		n2->next = n1;//将n2所指向节点的指针赋为空指针
		n1 = n2;//把n2的地址赋给n1,亦即让n1指向原先n2指向的节点
		n2 = n3;//让n2指向原先n3指向的节点
		if (n3)//如果n3不为空,则n3向后移动一位
			n3 = n3->next;
	}
	return n1;
}

问题1的另一种实现方法:头插法(实现方式不同,但核心思想一致,都是改变指针的方向。cur-->next=newhead,newhead再向后移,newhead=cur,还要有一个指针next保存指针的地址,避免因为指针cur的变化让指针丢失)

 

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
typedef  int SLTDateType;
struct ListNode
{
	SLTDateType data;
	struct ListNode* next;
};//首先初始化节点的结构体类型并宏定义变量类型    
struct ListNode* reverseList(struct ListNode* head)
{
	struct ListNode* cur = head;//将头指针赋给结构体型指针cur
	struct ListNode* newhead = NULL;//创建一个结构体型空指针newhead
	while (cur)//当指针cur不为空时,整个while循环会一直继续
	{
		struct ListNode* next = cur->next;//向后移动的同时为指针cur留下了一份拷贝,接下来就可以对指针cur随意进行变化了
		cur->next = newhead;//本方法的核心思想,即反转指针
		newhead = cur;
		cur = next;//下面的这两步都是按部就班的向后移动指针
	}
	return newhead;//在全部处理完之后,newhead变成了单链表的头节点,返回newhead即可
}

问题2:中间节点问题,对于有奇数个节点的单链表,找出期中间那个节点,对于有偶数个节点的链表,找出其中间两个节点的后一个。

思路:这类问题要利用快慢指针的思想,一个指针走的较快,另一个较慢,当快指针的速度是慢指针的二倍时,快指针走到链表末端时,慢指针正好走到中间节点处。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
typedef  int SLTDateType;
struct ListNode
{
	SLTDateType data;
	struct ListNode* next;
};//首先初始化节点的结构体类型并宏定义变量类型    
struct ListNode* reverseList(struct ListNode* head)
{
	struct ListNode* slow, * fast;//定义两个结构体类型指针
	slow = fast = head;//将头指针的赋给两个指针
	while (fast && fast->next)//括号内的判断条件是,只有指针fast和指针fast->next都不为空时,while循环才会继续下去,只要有一个为空,就说明
		//奇数个的单链表或者偶数个的单链表已经走完了
	{
		slow = slow->next;
		fast = fast->next->next;//指针slow一个循环向后走有一位,指针fast一个循环向后走两位
	}
	return slow;//程序运行完时,指针slow指向的节点就是我想要找的中间节点
}

问题3:寻找链表中的倒数第k个节点。

思路:仍然是双指针的思路,先让一个指针向后移动k位,然后再让另一个节点和已经移动k位的节点同时移动,两指针速度相同,当已经移动k位的指针向后移动到链表末端时,后移动的指针恰好指向链表的倒数第k个元素。

 

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
typedef  int SLTDateType;
struct ListNode
{
	SLTDateType data;
	struct ListNode* next;
};//首先初始化节点的结构体类型并宏定义变量类型    
struct ListNode* reverseList(struct ListNode* head)
{
	struct ListNode* first, * after;
	first = after = head;
	int i = 0;
	int k = 0;
	for (i = 0; i < k; i++)
	{
		if (first == NULL)
		{
			return NULL;
		}
		first = first->next;
	}
	while (first != NULL)
	{
		first = first->next;
		after = after->next;
	}
	return after;
}

问题4:合并两个有序链表

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
typedef  int SLTDateType;
struct ListNode
{
	SLTDateType data;
	struct ListNode* next;
};//首先初始化节点的结构体类型并宏定义变量类型    
struct ListNode* reverseList(struct ListNode* l1, struct ListNode* l2)//list node列表节点
{
	if (l1 == NULL)
		return l2;
	if (l2 == NULL)
		return l1;//以上这两个if都代表如果其中一个单链表为空的话,则返回另一个链表的指针(也就相当于返回整个链表)
	struct ListNode* head = NULL, * tail = NULL;//创建两个空指针
	while (l1 && l2)//只有当两个指针都不为空时,while循环才会继续
	{
		if (l1->data < l2->data)//如果指针l1指向节点的数据小于l2指向节点的数据
		{
			if (head == NULL)//如果指针为空,即我想要创建的新链表内还没有插入任何元素
			{
				head = tail = l1;//将两指针都指向插入的第一个节点
			}
			else//如果最终的链表内已经有节点了,则
			{
				tail->next = l1;//哪一个单链表上的节点的值小,尾节点就向哪一个链表延申伸
				tail = l1;//这里有一个思维上的省略过程,两步合起来看即tail=tail->next
			}
			l1 = l1->next;
		}
		else
		{
			if (head == NULL)//head指针的作用金局限于标记我要得出的单链表的头节点
			{
				head = tail = l2;
			}
			else
			{
				tail->next = l2;
				tail = l2;//tail->next=l2即相当于把指针l2指向的节点变成最后排序得到的单链表的尾节点,而且当单链表变长时,
				//尾节点也要实时更新,向后挪
			}
			l2 = l2->next;
		}
	}
	if (l1)
	{
		tail->next = l1;
	}
	if (l2)
	{
		tail->next = l2;
	}//当其中一个单链表全部比较完之后,另外一个也没有继续比较的意义了,直接插在最后得出的链表之后
	return head;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值