您的位置:首页 > 职场人生

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

2018-03-29 20:17 351 查看
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 }


单链表的逆置方法一:(推荐使用)



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 }


方法二:

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中


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指针刚好走到链表中间节点的位置。

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 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: