单链表的几道经典面试题(1)

时间:2021-06-13 14:20:17

1. 从尾到头打印单链表
2.约瑟夫环问题
3. 单链表的逆置
4. 单链表的排序(冒泡法)
5. 合并两个有序单链表之后使新的单链表依旧有序
6. 查找单链表的中间节点,且只能遍历一次链表
7.查找单链表的倒数第K个节点
8. 删除倒数第k个节点

从尾到头打印单链表

这道题的思路是要运用递归来实现
 
   407 //逆置打印链表
   408 #include <stdio.h>
   409 void LinkListPrintReverse(LinkNode* head)
   410 {
   411     if(head == NULL)
   412     {
   413         //空链表                                                                                       
   414         return ;
   415     }
   416     //运用递归
   417     LinkListPrintReverse(head->next);
   418     printf("%c",head->data);
   419 }
 

约瑟夫环问题

约瑟夫环问题是指:已知n个人(以编号1,2,3,...,n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的人出列;他的下一个人又开始从1开始报数,数到m的人出列;依次规律重复下去,直至圆桌周围的人全部出列,只剩下一个人。
   421 //约瑟夫环
   422 LinkNode* JosphCricle(LinkNode* head,int M)    
   423 {
   424     if(head == NULL)
   425     {                                                                                                    
   426         //空链表
   427         return NULL;
   428     }
   429     LinkNode* cur=head;
   430     while(cur->next!=cur)
   431     {
   432         int i=1;
   433         for(;i<M;++i)
   434         {
   435             cur=cur->next;
   436         }
   437         //cur指向的元素就是要被吃掉的元素
   438         printf("%c\n",cur->data);
   439         cur->data=cur->next->data;
   440         LinkNode* to_delete=cur->next;
   441         cur->next=to_delete->next;
   442         DestroyNode(to_delete);
   443     }                                                                                                  
   444     return cur;
   445 }


单链表的逆置

方法一:(推荐使用)

单链表的几道经典面试题(1)


  447 //链表逆置
   448 void LinkListReverse(LinkNode** phead)
   449 {
   450     if(phead == NULL)                                                                                  
   451     {
   452         //非法输入
   453         return;
   454     }
   455     if(*phead == NULL)
   456     {
   457         //空链表
   458         return ;
   459     }
   460     if((*phead)->next == NULL)
   461     {
   462         //只有一个元素                                                                                 
   463         return ;
   464     }
   465     LinkNode* cur=*phead;
   466     while(cur->next!=NULL)
   467     {
   468         LinkNode* to_delete=cur->next;
   469         //把这个节点删除掉
   470         cur->next=to_delete->next;
   471         //把删除掉的元素插入到链表头部
   472         to_delete->next=*phead;
   473         *phead=to_delete;
   474     }
   475     return ;                                                                                           
   476 }

方法二:
单链表的几道经典面试题(1)
   479 void LinkListReverse2(LinkNode** phead)
   480 {
   481     if(phead == NULL)
   482     {
   483         //非法输入                                                                                     
   484         return ;
   485     }
   486     if(*phead == NULL)
   487     {
   488         //空链表
   489         return ;
   490     }
   491     if((*phead)->next==NULL)
   492     {
   493         //只有一个元素                                                                                 
   494         return ;
   495     }
   496     LinkNode* cur=(*phead)->next;
   497     LinkNode* pre=(*phead);
   498     while(cur!=NULL)
   499     {
   500         LinkNode* next=cur->next;
   501         //修改cur->next指针的指向
   502         cur->next=pre;
   503         //交换pre cur指针                                                                              
   504         pre=cur;
   505         cur=cur->next;
   506     }
   507     //修改头指针指向
   508     *phead=pre;
   509 }

单链表的排序(冒泡法)
   511 //交换两个值
   512 void Swap(LinkNodeType* a,LinkNodeType* b)
   513 {
   514     LinkNodeType tmp=*a;
   515     *a=*b;                                                                                             
   516     *b=tmp;
   517 }

   518 //对单链表进行排序(冒泡法)
   519 void LinkListBubbleSort(LinkNode* head)
   520 {
   521     if(head == NULL)
   522     {
   523         //空链表
   524         return ;                                                                                       
   525     }
   526     if(head->next = NULL)
   527     {
   528         //只有一个节点
   529         return;
  530     }
   531     LinkNode* count=head;
   532     LinkNode* tail=NULL;//结束标记
   533     //第一重循环表示排序的趟数
   534     for(;count!=NULL;count=count->next)
   535     {                                                                                                  
   536         LinkNode* cur=head;
   537         //第二重循环表示保证将当前最大值冒到最后
   538         for(;cur->next!=tail;cur=cur->next)
   539         {
   540             if(cur->data>cur->next->data)
   541             {
   542                 Swap(&cur->data,&cur->next->data);
   543             }
   544         }
   545         tail=cur;
   546     }                                                                                                  
   547     return ;
   548 }

合并两个有序单链表之后使新的单链表依旧有序
比较cur1和cur2的大小,将较小的放入新链表的new_head中

单链表的几道经典面试题(1)
   550 //合并两个有序链表并且之后依旧有序
   551 LinkNode* LinkListMerge(LinkNode* head1,LinkNode* head2)
   552 {
   553     if(head1 == NULL)                                                                                  
   554     {
   555         return head2;
   556     }
   557     if(head2 == NULL)
   558     {
   559         return head1;
   560     }
   561     LinkNode* cur1=head1;
   562     LinkNode* cur2=head2;
   563     //用来指向新链表的头结点和尾节点
   564     LinkNode* new_head=NULL;
   565     LinkNode* new_tail=NULL;
   566     while(cur1=NULL&&cur2!=NULL)                                                                       
   567     {
   568         if(cur1->data<cur2->data)
   569         {
   570             if(new_tail == NULL)
   571             {
   572                 new_tail=new_tail=cur1;
   573             }
   574             else
   575             {
   576                 new_tail->next=cur1;                                                                   
   577                 new_tail=new_tail->next;
   578             }
   579             cur1=cur1->next;
   580         }
   581         else if(cur1->data>cur1->data)
   582         {
   583             if(new_tail == NULL)
   584             {
   585                 new_tail=new_tail=cur2;
   586             }
   587             else                                                                                       
   588             {
   589                 new_tail->next=cur2;
   590                 new_tail-new_tail->next;
   591             }
   592         }
   593     }
   594     //有一方已经先到达结尾,要将剩余部分接到新的链表之后
   595     if(cur1=NULL)
   596     {
   597         new_tail->next=cur1;
   598     }                                                                                                  
   599     else
   600     {
   601         new_tail->next=cur2;
   602     }
   603     return new_head;
   604 }

查找单链表的中间节点,且只能遍历一次链表
定义两个指针分别是fast和slow,开始都指向链表头部,让fast指针一次走两步,slow指针一次走一步,这样当fast指针走到链表结尾时,slow指针刚好走到链表中间节点的位置。

单链表的几道经典面试题(1)

   606 //查找单链表的中间节点,只能遍历一次链表
   607 LinkNode* LinkListFindMidNode(LinkNode* head)
   608 {
   609     if(head == NULL)
   610     {
   611         //空链表
   612         return ;                                                                                       
   613     }
   614     LinkNode* slow=head;
   615     LinkNode* fast=head;
   616     while(fast!=NULL&&fast->next!=NULL)
   617     {
   618         slow=slow->next;
   619         fast=fast->next->next;
   620     }
   621     return slow;
   622 }

查找链表的倒数第k个节点
方法同上一个问题,定义两个指针,fast和slow,让fast指针先走k步,然后再一起出发,都一次走一步,当fast指针走到结尾,则slow指针指向的就是倒数第k个节点。
   624 //查找链表的倒数第k个节点
   625 LinkNode* LinkListFindLastKNode(LinkNode* head,int k)
   626 {
   627     if(head == NULL)
   628     {
   629         //空链表                                                                                       
   630         return ;
   631     }
   632     LinkNode* fast=head;
   633     LinkNode* slow=head;
   634     //让fast先走k步
   635     int i=0;
   636     for(;i<k;++i)
   637     {
   638         if(fast==NULL)
   639         {
   640             break;                                                                                     
   641         }
   642         fast=fast->next;
   643     }
   644     if(i!=NULL)
   645     {
   646         //没走完,k的数值超过链表长度
   647         return NULL;
   648     }
   649     while(fast!=NULL)
   650     {
   651         fast=fast->next;                                                                               
   652         slow=slow->next;
   653     }
   654     return slow;
   655 }

删除倒数第k个节点
   657 //删除倒数第k个节点
   658 void LinkListEraseLastKNode(LinkNode** phead,int k)                                                    
   659 {
   660     if(phead == NULL)
   661     {
   662         //非法输入
   663         return ;
   664     }
   665     if(*phead == NULL)
   666     {
   667         //空链表
   668         return ;
   669     }
   670     int len=LinkListSize(*phead);                                                                      
   671     if(k>len)
   672     {
   673         return ;
   674     }
   675     if(k == len)
   676     {
   677         //要删除的元素为第一个
   678         LinkNode* to_delete=*phead;
   679         *phead=(*phead)->next;
   680         DestroyNode(to_delete);
   681         return ;
   682     }                                                                                                  
   683     LinkNode* pre=*phead;
   684     int i=0;
   685     for(;i<len-(k+1);++i)
   686     {
   687         pre=pre->next;
   688     }
   689     //循环结束后意味着pre已指向要删除元素的前一个节点
   690     LinkNode* to_delete=pre->next;
   691     pre->next=to_delete->next;
   692     DestroyNode(to_delete);
   693     return ;                                                                                           
   694 }