链表面试题(三)

9【查找单链表的中间结点,要求只能遍历一次链表】,10【查找单链表的倒数第k个结点,要求只能遍历一遍链表】,11【删除链表的倒数第k个结点】,12 【复杂链表的复制】

创建链表 打印链表在上一篇,戳链接 点击打开链接
9.【查找单链表的中间结点,要求只能遍历一次链表】,创建两个指针,都从链表的开头向后遍历,一个一次走一步,一个一次走两步,等到快指针走到链表结束,慢指针也就走到了链表中间结点处
SListNode* SListFindMidNode(SListNode* list)
{
	if (list == NULL || list->_next == NULL)//链表为空或者只有一个结点,就没有必要查找了
		return list;
	SListNode* pSlow = list;//慢指针
	SListNode* pQuick = list;//快指针
	while (pQuick->_next != NULL)
	{
		pSlow = pSlow->_next;
		pQuick = pQuick->_next;
		if (pQuick->_next != NULL)
			pQuick = pQuick->_next;//快指针走的第二步
	}
	return pSlow;
}
10,【查找单链表的倒数第k个结点,要求只能遍历一次链表】,同样的,也是创建两个指针都指向链表开始,让快指针先走K步,然后两个指针在一起一步一步的走,直到快指针走到了链表结束,那么这时慢指针就指向了倒数第K个结点
SListNode* SListFindTailKNode(SListNode* list, size_t k)
{
	if (k == 0 || list == NULL)//链表不存在或者k不存在
		return NULL;
	SListNode* pSlow = list;
	SListNode* pQuick = list;
	while (k > 1 && pQuick != NULL)//快指针先走K步
	{
		pQuick = pQuick->_next;
		k--;
	}
	if (k < 1 || pQuick == NULL)//链表的长度不足以让快指针走K步,那么就不存在倒数第K个结点
		return NULL;
	while (pQuick->_next != NULL)//两个指针一起走,直到快指针走到结束处
	{
		pQuick = pQuick->_next;
		pSlow = pSlow->_next;
	}
	return pSlow;
}
11,【删除链表的倒数第K个结点】,先调用上面的函数(第10个)找到倒数第K个结点,判断它是否是最后一个结点,是的话直接free然后置空,不是的话,调用删除非尾结点的函数(第2个)
SListNode* SListDelTailKNode(SListNode* list, size_t k)
{
	assert(list);
	assert(k > 0);
	SListNode* g = SListFindTailKNode(list, k);//函数详情见上一个函数
	if (g->_next != NULL)
	{
		SListDelNonTailNode(g);//函数详情戳本篇博客开头的链接
	}
	else
	{
		free(g);
		g = NULL;
	}
	return list;
}
12,【复杂链表的复制】,一个链表的每个节点,有一个next指针指向下一个结点,还有一个random指针指向这个链表中的一个随机结点,或者NULL,现在要求实现复制这个链表,返回复制后的新链表,首先给你复杂链表的结构
typedef struct ComplexListNode
{
	int _data;
	ComplexListNode* _next;//指向下一结点
	ComplexListNode* _random;//随机指向一个结点
}ComplexListNode;

首先复制链表,并将结点挨个串起来,然后复制random指针,因为是挨着的,所以复制链表的random在原链表random的后面,将random复制好之后再将俩链表解开

ComplexListNode* CopyComplexList(ComplexListNode* list)
{
	ComplexListNode* p = list;
	while (p)//复制链表并将俩个链表串起来
	{
		ComplexListNode* pClone = NULL;
		pClone->_data = p->_data;
		pClone->_next = p->_next;
		pClone->_random = NULL;
		p->_next = pClone;
		p = pClone->_next;
	}
	p = list;
	ComplexListNode* pClone = NULL;
	while(p)//克隆原链表的random指针
	{
		pClone = p->_next;
		if (pClone->_random)
			pClone->_random = p->_random->_next;//新链表的random指针是原先链表指针的random的下一个
		p = pClone->_next;
	}
	p = list;
	ComplexListNode* pClone = NULL;
	ComplexListNode* pCloneList = NULL;
	if (p != NULL)//头结点
	{
		pCloneList = p->_next;
		pClone = p->_next;
		p->_next = pClone->_next;
		p = p->_next;
	}
	while (p)//将俩链表解开
	{
		pClone->_next = p->_next;
		pCloneList->_next = pClone;
		pClone = pClone->_next;
		p->_next = pClone->_next;
		p = p->_next;
	}
	return pCloneList;
}
如果有不对的地方,可以评论告诉我,望指导!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值