在基础篇中,简单的描述了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 ;
}