问题
链表翻转。给出一个链表和一个数k,比如,链表为1→2→3→4→5→6,k=2,则翻转后2→1→6→5→4→3,若k=3,翻转后3→2→1→6→5→4,若k=4,翻转后4→3→2→1→6→5,用程序实现。
在之前我们肯定都写过链表的翻转程序:
NodePtr ReverseList(NodePtr head){
cout << "reverse list" << endl;
//若只有头或者只有一个节点,则不用翻转
if(head->next == NULL || head->next->next == NULL)
return head;
NodePtr p, q, r;
p = head->next;
q = p->next;
//翻转过程
while(q){
r = q->next;
q->next = p;
p = q;
q = r;
}
//翻转过后改变头指针
head->next = p;
return head;
}
本题与全翻转链表有很大的相似之处,当然也有很大的不同之处。相似之处在于翻转的过程同事相同的,而不同之处则在于本题中包含两个部分的翻转,并且在头指针的指向以及第一个翻转过后还有一些操作需要处理。大致过程如下草图所示
该图中黑色表示链表的最初始状态,红色表示翻转的第一部分,绿色表示第二部分的翻转。
该实例表示的是k=2时的翻转,第一部分的翻转我们需要注意的问题是:
1.准确的定位。在链表中有时候会把人弄糊涂,因此一定要准确的定位到第二个节点,然后再开始翻转。
2.翻转过后头结点的指向。在本例中第一部分翻转过后一定要将head节点指向第一部分翻转的起始节点,即第二个节点。
3.第一部分翻转过后的最后一个节点的指向也一定要搞清楚。在本例中翻转过后第一个节点的下一个指向一定要指向节点3.
第一部分翻转完成过后我们开始第二部分的翻转。第二部分的翻转相对而言要简单很多,只需要注意翻转过后,一定要将第一部分翻转过后的最后一个节点的next指向最后一个节点。程序代码如下所示(这个程序还是有一点问题的,如果是全翻转的话会有问题,但是这只是增加判断的问题,主要思路都是对的)
bool ReverseLink(LinkList link, int k){
//若只有头或者只有一个节点,则不用翻转
if(link->next == NULL || link->next->next == NULL)
return false;
LinkList p, q, r, firstNode;
int count = 1;
firstNode = link->next;
p = link->next; //头结点
q = p->next; //第二个节点
//前k个节点的翻转
while(count<k && q){
r = q->next;
q->next= p;
p = q;
q = r;
count++;
}
firstNode->next = r;
link->next = p;
//后面节点的翻转
p = firstNode->next;
q = p->next;
while(q){
r = q->next;
q->next = p;
p = q;
q = r;
}
firstNode->next->next = NULL;
firstNode->next = p;
return true;
}
下面是整体的代码,可以直接运行,已经在机器上测试过:
#include<iostream>
using namespace std;
typedef int ElemType;
struct Link{
ElemType data;
struct Link *next;
};
typedef Link *LinkList;
bool InitLink(LinkList *link){
*link = (LinkList)malloc(sizeof(Link));
if(!(*link))
return false;
(*link)->next = NULL;
return true;
}
bool InsertList(LinkList *link, ElemType elem){
if(NULL == *link)
return false;
LinkList p, q;
p = *link;
q = (LinkList)malloc(sizeof(Link));
q->data = elem;
q->next = NULL;
while(NULL != p->next)
p = p->next;
p->next = q;
return true;
}
bool ReverseLink(LinkList link, int k){
//若只有头或者只有一个节点,则不用翻转
if(link->next == NULL || link->next->next == NULL)
return false;
LinkList p, q, r, firstNode;
int count = 1;
firstNode = link->next;
p = link->next; //头结点
q = p->next; //第二个节点
//前k个节点的翻转
while(count<k && q){
r = q->next;
q->next= p;
p = q;
q = r;
count++;
}
firstNode->next = r;
link->next = p;
//后面节点的翻转
p = firstNode->next;
q = p->next;
while(q){
r = q->next;
q->next = p;
p = q;
q = r;
}
firstNode->next->next = NULL;
firstNode->next = p;
return true;
}
void printLink(LinkList link){
LinkList p;
p = link;
while(NULL != p->next ){
cout << p->next->data << "---> " ;
p = p->next;
}
cout << endl;
}
int main(){
LinkList link;
InitLink(&link);
InsertList(&link, 1);
InsertList(&link, 2);
InsertList(&link, 3);
InsertList(&link, 4);
InsertList(&link, 5);
InsertList(&link, 6);
printLink(link);
ReverseLink(link, 5);
printLink(link);
return 0;
}