面试题—链表的‘部分’翻转

面试题—链表的‘部分’翻转

2016年08月09日 21:43:37

阅读数:1536

问题:

         给出一个单链表(不带头节点)和一个数K,请翻转此单链表?

例如:1->2->3->4->5       k = 0;   翻转过后:1->2->3->4->5

          1->2->3->4->5       K = 2;   翻转过后:2->1->4->3->5

          1->2->3->4->5       K = 10; 翻转过后:5->4->3->2->1

        在讨论链表的‘部分’翻转问题之前,先回顾一下链表的逆置问题,如何将一个链表进行逆置?我们以前采用的方式是‘摘节点头插’的方法。假设右链表1->2->3->4->5,新建一个节点指针newHead=NULL,用cur指针指向链表的头节点,将摘下的节点用tmp进行保存,然后将tmp和newHead进行连接,将newHead指向tmp的位置上,如此循环直到cur为NULL结束。

扫描二维码关注公众号,回复: 2859305 查看本文章

■下面是‘摘节点头插’的简单图示:

wKiom1dDu22j--UMAAAOqK4yEFE776.png

■下面是详细的实现:

 
  1. //链表节点的结构

  2. struct Node

  3. {

  4.      int data;

  5.      Node* _next;

  6. };

  7.  
  8. void Reverse(Node* list)

  9. {

  10.      if (list == NULL)

  11.      {

  12.           return;

  13.      }

  14.      Node* cur = list;

  15.      Node* newHead = NULL;

  16.      while (cur)

  17.      {

  18.           Node* tmp = cur;

  19.           cur = cur->_next;

  20.           tmp->_next = newHead;

  21.           newHead = tmp;

  22.      }

  23. }

       

        通过上面的解释,读者应该对链表的逆置应该不会陌生了,下面就还看一下链表的‘部分’翻转的问题:

        链表的‘部分’翻转,它和链表的逆置还是不一样的,对于给定的K,其实就是没此逆置K个节点,然后连接上后面翻转过后的K个节点,若最后剩余的不足K个节点,同样也对其进行翻转,然后进行连接。所以我们可以借助一下‘摘节点头插’的方式,分部分进行‘摘节点头插’。

        假设1->2->3->4->5,k = 2; 即就是将1和2进行翻转,3和4进行翻转,5进行翻转,然后将1和2翻转后的结果与3和4翻转后的结果和5翻转后的结果进行连接,得到2->1->4->3->5.

        在完成代码之前,先考虑链表若为空的情况,针对这个问题,如果k =0/1时的情况,k若大于链表节点的总个数又是什么情况?当链表为空时,可以直接返回,或者k=0/1时,就不需要对其进行翻转,也可以直接进行返回。若K大于链表节点的总个数,即就是相当于对链表进行逆置。

        在完成链表‘部分’的翻转,需要sectionHead(指向‘部分’的头节点)、sectionTail(指向‘部分’的尾节点)、cur(指向整个链表)、newHead(指向翻转完成的链表头节点)、prevsectionTail(指向这一部分之前部分的尾节点)、tmp(用来做中间保存节点的指针)这几个节点指针,sectionNum用来标识翻转的是第几部分。下面是‘部分’翻转的简单图示:

wKiom1dDxTWTny68AAAksTjP87k777.png

■下面是‘部分’翻转的实现代码:

 
  1. Node* RolloverList(Node* list, int k)

  2. {

  3.      if (k <= 1 || list == NULL)

  4.      {

  5.           return list;

  6.      }

  7.      

  8.      Node* cur = list;      //指向链表的头节点

  9.      Node* newHead = NULL;      //指向逆置后的链表

  10.      Node* sectionHead = NULL;     //指向需要逆置部分的头节点

  11.      Node* sectionTail = NULL;      //指向需要逆置部分的尾节点

  12.      Node* prevsectionTail = NULL;    //指向部分尾节点的指针

  13.      int sectionNum = 0;   //用来标记链表翻转到第几部分

  14.      

  15.      while (cur)

  16.      {

  17.           int count = k;     //记录部分逆置的节点数

  18.           prevsectionTail = sectionTail;

  19.           sectionTail = cur;

  20.           

  21.           while (count-- && cur != NULL)     //使用的方法还是摘节点头插(进行部分逆置)

  22.           {

  23.                Node* tmp = cur;

  24.                cur = cur->_next;

  25.                tmp->_next = sectionHead;     //sectionHead相当于链表逆置中的newHead(先将部分进行逆置)

  26.                sectionHead = tmp;

  27.           }

  28.           

  29.           ++sectionNum;   //统计逆置了几部分

  30.           //如果sectionNum为1时,逆置的部分为第一部分,就应该确定逆置后的链表的头节点

  31.           if (sectionNum == 1)    

  32.           {

  33.                newHead = sectionHead;        

  34.           }

  35.           else    //证明逆置的为链表后面的部分,需要将后面的部分和前面的部分进行连接起来

  36.           {

  37.                prevsectionTail->_next = sectionHead;

  38.           }

  39.      }

  40.      

  41.      //出循环cur == NULL

  42.      sectionTail->_next = NULL;

  43.      return newHead;

  44. }

本文出自 “无心的执着” 博客,请务必保留此出处http://10740590.blog.51cto.com/10730590/1782421

猜你喜欢

转载自blog.csdn.net/u012602304/article/details/81809549