链表常见题总结一

     链表可以说是笔试面试的重点,因为写一个链表相关的题可以在短时间写出来,并且考验测试人的水平。特别将平时经常做的链表的题拿上来,做个小结。

   1. 求单链表中结点的个数
   2. 将单链表反转
   3. 查找单链表中的倒数第K个结点(k > 0)
   4. 查找单链表的中间结点
   5. 已知两个单链表pHead1 和pHead2 各自有序,把它们合并成一个链表依然有序
   6. 判断一个单链表中是否有环
   7. 判断两个单链表是否相交
  8. 求两个单链表相交的第一个节点
  9. 已知一个单链表中存在环,求进入环中的第一个节点
  10. 给出一单链表头指针pHead和一节点指针pToBeDeleted,O(1)时间复杂度删除节点pToBeDeleted

  1.求单链表节点的个数

//求单链表中结点的个数
int Length(ListNode *phead)
{
	int len = 0;
	while (phead != NULL)
	{
		len++;
		phead = phead->pnext;
	}
	return len;
}

   2.单链表反转

     我是按照递归和非递归做的
     
//单链表反转
ListNode* Reverse(ListNode *phead)
{
	if (phead == NULL||phead->pnext==NULL)
		return phead;
	ListNode *pre = new ListNode(0);
	ListNode *temp = pre;
	pre->pnext = phead;
	ListNode* cur = phead;
	ListNode* next = phead->pnext;
	while (next != NULL)
	{
		cur->pnext = pre;
		pre = cur;
		cur = next;
		next = next->pnext;
	}
	cur->pnext = pre;
	phead->pnext = NULL;
	delete temp;
	return cur;
}

//单链表反转,递归
ListNode* ReverseRecursion(ListNode* phead)
{
	if (phead == NULL || phead->pnext == NULL)
		return phead;
	ListNode *temp = phead->pnext;
	ListNode *newhead=ReverseRecursion(temp);   //先反转链表结点的后一个结点
	temp->pnext = phead;            //将该结点放在其原来后面结点的后一个结点
	phead->pnext = NULL;
	return newhead;
}

    3.倒数第K个节点

//查找单链表中的倒数第K个结点(K>0),采用双指针法
ListNode* TheKthListNode(ListNode* phead,int k)
{
	ListNode *fast = phead;
	int i = 0;
	while (i < k-1 && fast != NULL)
	{
		fast = fast->pnext;
		i++;
	}
	if (fast == NULL)
		return NULL;
	ListNode *slow = phead;
	while (fast->pnext != NULL)
	{
		slow = slow->pnext;
		fast = fast->pnext;
	}
	slow->pnext = NULL;
	return slow;
}

    4.查找单链表的中间节点

//找出单链表的中间结点,采用快慢指针
ListNode* MiddleNode(ListNode* phead)
{
	ListNode *slow = phead;
	ListNode *fast = phead;
	if (phead == NULL)
		return phead;
	while (fast->pnext != NULL)
	{
		fast = fast->pnext;
		slow = slow->pnext;
		if (fast->pnext != NULL)
			fast = fast->pnext;
	}
	return slow;
}

     5.合并两个有序的链表,使得结果仍然有序

//两链表各自有序,合并成一个链表依然有序
ListNode* Merge(ListNode *phead1, ListNode *phead2)
{
	if (phead1 == NULL)
		return phead1;
	if (phead2 == NULL)
		return phead2;
	ListNode *pre=new ListNode(0);
	ListNode *cur = pre;
	ListNode *temp = NULL;
	while (phead1 && phead2)
	{
		temp = phead1->val < phead2->val ? phead1 : phead2;
		cur->pnext = temp;
		cur = temp;
		if (temp == phead1)
			phead1 = phead1->pnext;
		else
			phead2 = phead2->pnext;
	}
	while (phead1)
	{
		cur->pnext = phead1;
		cur = cur->pnext;
		phead1 = phead1->pnext;
	}
	while (phead2)
	{
		cur->pnext = phead2;
		cur = cur->pnext;
		phead2 = phead2->pnext;
	}
	cur->pnext = NULL;
	temp = pre->pnext;
	delete pre;
	return temp;
}

     6.判断单链表是否有环

//判断一个单链表是否有环,同样采用快慢指针,要是他们重合就有环
bool IsCircle(ListNode *phead)
{

	ListNode *fast = phead;
	ListNode *slow = phead;
	while (fast!=NULL && fast->pnext!=NULL)
	{
		fast = fast->pnext->pnext;
		slow = slow->pnext;
		if (fast == slow)
			return true;
	}
	return false;
}

     7.判断两个单链表是否相交

//判断两个单链表是否相交,若相交,则两个链表的最后一个节点必定相同,否则不相交
bool IsConnect(ListNode *phead1, ListNode *phead2)
{
	if (phead1 == NULL || phead2 == NULL)
	{
		return false;
	}
	while (phead1->pnext != NULL)
	{
		phead1 = phead1->pnext;
	}
	while (phead2->pnext != NULL)
	{
		phead2 = phead2->pnext;
	}
	if (phead1 == phead2)
		return true;
	else
		return false;
}

     8.求两个链表相交的第一个节点

//求两个单链表相交的第一个节点,先分别计算两个链表的长度,再让长的链表先走超出的那部分,然后两个链表步调相同
ListNode* TheFirstConnectNode(ListNode *phead1, ListNode *phead2)
{
	if (phead1 == NULL || phead2 == NULL)
	{
		return NULL;
	}
	ListNode *temp1 = phead1;
	ListNode *temp2 = phead2;
	int len1 = 0, len2 = 0;
	while (temp1->pnext != NULL)
	{
		len1++;
		temp1 = temp1->pnext;
	}
	while (temp2->pnext != NULL)
	{
		len2++;
		temp2 = temp2->pnext;
	}
	if (temp1 != temp2)
		return NULL;
	else
	{
		if (len1 > len2)
		{
			temp1 = phead1;
			for (int i = 0; i < len1 - len2;i++)
			{
				temp1 = temp1->pnext;
			}
			temp2 = phead2;
		}
		else
		{
			temp2 = phead2;
			for (int i = 0; i < len2 - len1; i++)
			{
				temp2 = temp2->pnext;
			}
			temp1 = phead1;
		}
		while (temp1 != temp2)
		{
			temp1 = temp1->pnext;
			temp2 = temp2->pnext;
		}
		return temp1;
	}
}

     9.已知单链表有环,求进入环中的第一个节点

//已知单链表有环,求进入环中的第一个节点
ListNode *TheFirstCircleNode(ListNode *phead)
{
	//先找一个在环中的节点,采用快慢指针
	ListNode *fast = phead->pnext->pnext;
	ListNode *slow = phead->pnext;
	while (fast != slow)
	{
		slow = slow->pnext;
		fast = fast->pnext->pnext;
	}
	//计算环的长度
	int len = 1;
	fast = fast->pnext;
	while (fast!=slow)
	{
		len++;
		fast = fast->pnext;
	}
	//让一个快指针先走len,然后慢指针开始走,当两个第一次相遇点就是环的第一个节点
	fast = phead;
	slow = phead;
	for (int i = 0; i < len; i++)
	{
		fast = fast->pnext;
	}
	while (fast != slow)
	{
		fast = fast->pnext;
		slow = slow->pnext;
	}
	slow->pnext = NULL; //此处只是为了提炼一个节点出来,免得打印的时候因为是循环,打印循环输出一满屏
	return slow;
}

    10.删除一个指定节点,时间复杂度为O(1)

//给出一单链表头指针和一节点指针toBeDel,O(1)时间复杂度删除节点toBeDel
void DelOneNode(ListNode *phead, ListNode *toBeDel)
{
	if (toBeDel->pnext == NULL)
	{
		toBeDel = NULL;
	}
	toBeDel->val = toBeDel->pnext->val;      //O(1)时间复杂度的话只能将后面节点的值赋给该结点,在将
	toBeDel->pnext = toBeDel->pnext->pnext;  //要删除的节点的后一个节点删除;
}
文中均为自己写的代码,均通过自己写的简单的测试,但是肯定还有些测试不能通过,希望有人找出错误给我纠正一下,不胜感谢。待更新ing..

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值