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 }
方法一:(推荐使用)
![](https://i-blog.csdnimg.cn/blog_migrate/9ff9997d4ccd5293e03122f1c83397b9.png)
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 }
方法二:
![](https://i-blog.csdnimg.cn/blog_migrate/e32e0d8e5c76f5a0209fc05ade35254e.png)
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中
![](https://i-blog.csdnimg.cn/blog_migrate/07a60589ca188074c7a5c2cde671bd4e.png)
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 }