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

来源:互联网 发布:js获取选择文件的路径 编辑:程序博客网 时间:2024/06/06 00:29


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