【链表篇】链表面试题集

1. 给定单链表,检测是否有环。如果有环,则求出进入环的第一个节点。

         判断单向链表是否有环,可以采用快指针与慢指针的方式来解决。即定义一个快指针fast和一个慢指针slow,使得fast每次跳跃两个节点,slow每次跳跃一个节点。如果链表没有环的话,则slow与fast永远不会相遇(这里链表至少有两个节点);如果有环,则fast与slow将会在环中相遇。判断出链表有环以后,则需要算出进入环的第一个节点。在fast与slow第一次相遇后,设置一个节点pNode从链表的头部开始遍历,每次只遍历一个节点。这样,当fast与slow再次相遇时,pNode所处的位置便是环的首部。以下该问题的实现源码(C语言描述):

LNode* GetLoopNode(LNode* head)
{
	//前置条件的判断
	if (!head)
	{
		return NULL;
	}

	//定义一个快指针和一个慢指针
	LNode* fast = head;
	LNode* slow = head;
	while (fast && (fast->next))
	{
		fast = fast->next->next;
		slow = slow->next;

		if (fast == slow)
		{
			//如果有环,则返回环的第一个节点
			slow = head;
			while (1)
			{
				fast = fast->next;
				slow = slow->next;

				if (fast == slow)
				{
					break;
				}
			}

			return slow;
		}
	}

	return NULL;
}

 

2. 给定两个单链表,检测两个链表是否有交点,如果有返回第一个交点。

        检测两个单链表是否有交点是很容易的,因为如果两个链表有交点,那么这两个链表的最后一个节点必须相同,所以只需比较最后一个节点即可。但是这种方案是无法求出第一个交点的,所以需要另辟蹊径。另外,判断是否有交点可以转换成链表是否有环的问题。让一个链表的最后一个节点指向第二个链表的头结点,这样的话,如果相交,则新的链表是存在环的,并且交点便是环的入口点。

3. 只给定单链表中某个结点p(并非最后一个结点,即p->next!=NULL)指针,删除该结点。

        由于没有给定链表的头结点,所以无法获取需要删除节点的前驱结点,这样就无法使用常规的方法去解决。在《编程之美》这本书里面给出一个非常精妙的解法,也就是采用了狸猫换太子的思想。以下是实现源码:

void DeleteNode(LNode* pNode)
{
	//如果pNode是最后一个节点,则该问题误解
	if (!pNode || !(pNode->next))
	{
		return;
	}

	//获取pNode的后驱节点
	LNode* qNode = pNode->next;

	//将qNode的值赋给pNode,并删除qNode
	pNode->data = qNode->data;
	pNode->next = qNode->next;
	free(qNode);
}

 

4. 给定单链表头结点,删除链表中倒数第k个结点

        这个问题的关键是需要获取倒数第k个节点。如何获取呢?这里,需要两个指针p和q,p指向头结点,q指向距离头结点为k的节点。这样p和q每次遍历一个节点,当q遍历到末尾的时候,p指向的节点即为倒数第k个节点。然后删除即可。以下是实现源码(这里获取的是倒数第k+1个节点,因为需要删除的是倒数第k个节点):

void DelLastKNode(unsigned int k, LNode* head)
{
	//前置条件判断
	if (!head || k <= 0)
	{
		return;
	}

	LNode* pNode = head;
	LNode* qNode = head;

	//将qNode遍历到正数第k + 1个节点
	unsigned int i; 
	for (i = 0; i < k; i++)
	{
		qNode = qNode->next;
	}

	//获取倒数第k + 1个节点
	while (qNode->next)
	{
		pNode = pNode->next;
		qNode = qNode->next;
	}

	//删除倒数第k个节点
	LNode* temp = pNode->next;
	pNode->next = temp->next;
	free(temp);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值