C语言实现单链表面试题-------进阶篇


在基础篇中,简单的描述了C语言单链表面试中的常见简单题型,这里将在上一篇的基础上进行描述


  1.求两个已排序单链表中相同的元素(交集、差集)

   分析:题目条件为两个已排序的单链表

        eg.

          List1: 1  3   5  7  9

          List2: 2  2   3  5  7  9  10

        首先定义两个指针依次指向List1和List2,

       (交集) 判断两者大小,若相等,则为交集,若不相等,让较小者先走

       (差集) 若不相等为差集,让小者先走

     代码:

Node* GetUnion(Node* head1,Node* head2)
{
	Node* Result = NULL;
	Node* List1 = head1;
	Node* List2 = head2;

	while(List1 && List2)
	{
		 if(List1->data == List2->data )
		 {
			PushBack (&Result,List1->data);
			List1 = List1->next ;
			List2 = List2->next ;
		 }
		 else if(List1->data < List2->data)
		 {
			 List1 = List1->next ;
		 }
		 else
		 {
			 List2 = List2->next ;
		 }
	}
	return Result;

}

Node* GetIntersection(Node* head1,Node* head2)
{
	Node* Result = NULL;
	Node* List1 = head1;
	Node* List2 = head2;

	while(List1 && List2)
	{
		 if(List1->data == List2->data )
		 {
			List1 = List1->next ;
			List2 = List2->next ;
		 }
		 else if(List1->data < List2->data)
		 {
			 PushBack (&Result,List1->data);
			 List1 = List1->next ;
		 }
		 else
		 {
			 PushBack (&Result,List2->data);
			 List2 = List2->next ;
		 }
	}
        //注:这里应该判断List1和List2是否已完,否则将其插入Result后
	if(List1 != NULL)
	{
		while(List1)
		{
			PushBack (&Result,List1->data);
			List1 = List1->next ;
		}
	}
	if(List2 != NULL)
	{
		while(List2)
		{
			PushBack (&Result,List2->data);
			List2 = List2->next ;
		}
	}

	return Result;
}
 


 接下来将讨论链表是否带环与两链表是否相交问题

 

      1. 判断单链表是否带环?若带环,求环的长度?(??)求环的入口点?并计算每个算法的时间复杂度&空间复杂度。

   分析:

       1.判断是否带环

      

    

       

       2.求环的长度

       

       3.求入口结点

       

       

        代码:

        

//判断链表是否带环
Node* IsCycle(Node* phead)
{
	Node* slow = phead;
	Node* fast = phead;
	while(fast && fast->next )//防止fast->next == NULL时,fast = fast ->next->next程序崩溃
	{
		fast = fast ->next ->next ;
		slow = slow->next;
		if(fast == slow)
		{
			return fast;//返回相遇点
		}
	}
	return NULL;
}

//求环的长度
int GetCycleLen(Node* meetNode)
{
	Node* slow = meetNode ;
	int count = 0;
	assert(slow);
	slow =slow->next ;
	count++;
	while(slow != meetNode)
	{
		count++;
		slow = slow->next ;
	}
	return count;
}

//求环的入口结点
Node* GetEntry(Node* phead, Node* meetNode)
{
	Node* start = phead;
	Node* meet = meetNode;
	assert(start && meet);
	while(start != meet)
	{
		start = start->next ;
		meet = meet->next ;
		if(start == meet)
		{
			return meet;
		}
	}
	return NULL;
}

   

     2.判断两个链表是否相交,若相交,求交点。(假设链表不带环)

     分析:

   

      代码:

           
//判断不带环两链表是否相交
int IsCross(Node* list1, Node* list2)
{
	Node* tail1 = list1;
	Node* tail2 = list2;
	while(tail1->next )
	{
		tail1 = tail1->next;
	}

	while(tail2 ->next )
	{
		tail2 = tail2 ->next ;
	}

	if(tail1 == tail2)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

//求交点 (1.暴力查找  2.先求出两链表长度之差,再一起走)
Node* GetCrossNode(Node* list1, Node* list2)
{
	int len1 = 0 ,len2 = 0;
	int gap = 0;
	Node* cur1 = list1, *cur2 = list2;
	Node* shortlist = NULL, *longlist = NULL;
	while(cur1)
	{
		len1++;
		cur1 = cur1->next ;
	}

	while(cur2)
	{
		len2++;
		cur2 = cur2->next;
	}

	if(len1<len2)
	{
		shortlist = list1;
		longlist = list2;
	}
	else
	{
		shortlist = list2;
		longlist = list1;
	}
	gap = abs(len1-len2);
	while (gap--)
	{
		longlist = longlist->next;
	}

	while (shortlist != longlist)
	{
		shortlist = shortlist->next;
		longlist = longlist->next;
	}

	return shortlist;
}

     3.判断两个链表是否相交,若相交,求交点。(假设链表可能带环)【升级版】

             分析:

        


       



      算法:

           同上一题求交点的算法相同,

           1.首先获取到2个链表的长度,获得长度差L(因为环是共用的,所以这个差其实就是环外的差),

          获得2个链表的各个环入口点
           2.先让一个长的链表从头开始走过L个节点。
           3.再让短的链表从头与之同步后移,再保证2者不走到环入口的同时判断节点地址信息是否相同
           4.若相同并未到环入口点,则相交于环外,返回相交点。
           5.否则直接返回任意一个链表的环入口作为相交点即可。


最后讨论复杂链表的复制


     问题:

     一个链表的每个节点,有一个指向next指针指向下一个节点,还有一个random指针指向这个链表中的一个随机节点或者NULL,现在要求实现复制这个链表,返回复制后的新链表。

     分析:

      

      

           代码:

    

Node* CopyList(Node* phead)
{
	//1.插入拷贝结点
	Node* ourhead = phead;//合并链表的头结点
	Node* cur = NULL;
	while(ourhead)
	{
		Node* next = ourhead->_next ;//应该记住原链表的next结点,
		//(插入一个结点时找到后续结点、ourhead直接找的下一个结点)
		Node* copy = BuyNode(ourhead->_data );
		ourhead->_next = copy;
		copy->_next = next;
		ourhead = next;
	}
	print(phead);

	//2.置rondom
	cur = phead;
	while(cur)//判断条件的设计
	{
		Node* copy = cur->_next ;
		if(cur->_random )
		{
			copy->_random = (cur->_random)->_next;
		}
		cur = copy->_next;//注 :这里需要移动两步
	}
	print(phead);
	//3.拆解 CopyList(拆除copy结点,采用为尾插法插入(注:需要记住尾结点))
	Node* copyhead = NULL;
	Node* copytail = NULL;
	cur = phead;
	while(cur)
	{
		Node* copy = cur->_next ;
		Node* next = copy->_next;
		cur ->_next = next;//链起原链表
		if(copyhead == NULL)
		{
			copyhead = copytail = copy;
		}
		else
		{
			copytail->_next = copy;
			copytail = copy;
		}
		cur = next;
	}
	return copyhead ;
	
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值