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

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

2016-05-24 11:13 337 查看
问题:
给出一个单链表(不带头节点)和一个数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结束。

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





■下面是详细的实现:

//链表节点的结构
struct Node
{
int data;
Node* _next;
};

void Reverse(Node* list)
{
if (list == NULL)
{
return;
}
Node* cur = list;
Node* newHead = NULL;
while (cur)
{
Node* tmp = cur;
cur = cur->_next;
tmp->_next = newHead;
newHead = tmp;
}
}

通过上面的解释,读者应该对链表的逆置应该不会陌生了,下面就还看一下链表的‘部分’翻转的问题:
链表的‘部分’翻转,它和链表的逆置还是不一样的,对于给定的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用来标识翻转的是第几部分。下面是‘部分’翻转的简单图示:





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

Node* RolloverList(Node* list, int k)
{
if (k <= 1 || list == NULL)
{
return list;
}

Node* cur = list;      //指向链表的头节点
Node* newHead = NULL;      //指向逆置后的链表
Node* sectionHead = NULL;     //指向需要逆置部分的头节点
Node* sectionTail = NULL;      //指向需要逆置部分的尾节点
Node* prevsectionTail = NULL;    //指向部分尾节点的指针
int sectionNum = 0;   //用来标记链表翻转到第几部分

while (cur)
{
int count = k;     //记录部分逆置的节点数
prevsectionTail = sectionTail;
sectionTail = cur;

while (count-- && cur != NULL)     //使用的方法还是摘节点头插(进行部分逆置)
{
Node* tmp = cur;
cur = cur->_next;
tmp->_next = sectionHead;     //sectionHead相当于链表逆置中的newHead(先将部分进行逆置)
sectionHead = tmp;
}

++sectionNum;   //统计逆置了几部分
//如果sectionNum为1时,逆置的部分为第一部分,就应该确定逆置后的链表的头节点
if (sectionNum == 1)
{
newHead = sectionHead;
}
else    //证明逆置的为链表后面的部分,需要将后面的部分和前面的部分进行连接起来
{
prevsectionTail->_next = sectionHead;
}
}

//出循环cur == NULL
sectionTail->_next = NULL;
return newHead;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  单链表 逆置