面试题—链表的‘部分’翻转
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结束。
■下面是‘摘节点头插’的简单图示:
■下面是详细的实现:
通过上面的解释,读者应该对链表的逆置应该不会陌生了,下面就还看一下链表的‘部分’翻转的问题:
链表的‘部分’翻转,它和链表的逆置还是不一样的,对于给定的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用来标识翻转的是第几部分。下面是‘部分’翻转的简单图示:
■下面是‘部分’翻转的实现代码:
给出一个单链表(不带头节点)和一个数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; }
相关文章推荐
- C#定义并实现单链表实例解析
- C#数据结构之单链表(LinkList)实例详解
- C语言实现单链表逆序与逆序输出实例
- C语言单链表常见操作汇总
- C数据结构之单链表详细示例分析
- C++中单链表的建立与基本操作
- 深入单链表的快速排序详解
- C语言创建和操作单链表数据结构的实例教程
- C语言单链表的实现
- java实现单链表中是否有环的方法详解
- java实现单链表、双向链表
- Python单链表的简单实现方法
- Python单链表简单实现代码
- Go语言单链表实现方法
- Python单链表简单实现代码
- 结构之美:在单链表指定位置插入数据
- 《编程之美》3.4:没有头结点的单链表如何删除结点
- 结构之美:使用尾插法创建单链表
- 单链表实现
- 单链表的实现及其操作