/*
这题早就做过了,但是当时看的书上的代码真的很差,比其这本书差的不少。。剑指offer真是我大学看过的最好的书之一了
反转链表 需要对链表进行遍历 每次对于遍历到的节点,先记录next,再next指向前一个,然后继续遍历 注意不要把链表弄段
还有注意输入 最主要的是输入头节点NULL 的处理 测试数据要想到 只有一个节点怎么办 两个,多个怎么办 输入NULL 怎么办
只要自己想到测试数据都过了 代码才可以提交
*/
#include<iostream>
#include<cstdio>
using namespace std;
struct Node
{
int data;
Node * next;
};
void PrintList(Node * head)
{
if(head==NULL)
printf("empty List\n");
Node * p=head;
while(p!=NULL)
{
printf("%d ",p->data);
p=p->next;
}
cout<<endl;
}
Node * ReverseList(Node * head)
{
Node * pre=NULL;//因为头节点的前一个是空的
Node * p=head;
Node * newhead=NULL;//如果输入空指针 不进入循环 返回newhead 所以赋初值NULL
while(p!=NULL)
{
Node * p_next=p->next;//先记录下一个
if(!p_next)
newhead=p;
p->next=pre;//再把next指向前一个
pre=p;
p=p_next;
}
return newhead;
}
// 单链表反序的递归算法,这个相对好理解 想起以前看那本CC++程序员面试宝典,也是在那看的
//递归算法,太尼馬坑了 那本书我还通透的看完了。那个代码本来就有错 还不好理解,看来选经典好书真的太重要了
//这个算法就相对好理解了 一直递归执行这个函数 知道最后一个节点的时候 因为head->next是空了 返回了head
//因为是最后一个节点 这个head就是反转后的头节点 在倒数第二个里面newhead就是新的头节点
//接下来两句很经典 head->next->next=head 这句话把链表的指针到过来了
//这个时候 这个head就是目前链表的末尾 所以next赋值NULL 太经典了 这个算法真好
Node * ReverseListRecursively(Node * head)//递归方法 相对好理解
{
if(head==NULL || head->next==NULL) return head;
Node * newhead=ReverseListRecursively(head->next);
head->next->next=head;
head->next=NULL;
return newhead;
}
int main()
{
//freopen("/home/gl/in","r",stdin);
int n;
while(scanf("%d",&n)!=EOF)
{
Node * head;
if(!n)
head=NULL;
else
head=new Node();
Node * p=head;
for(int i=0;i<n;++i)
{
scanf("%d",&p->data);
if(i==n-1)
{
p->next=NULL;
break;
}
p->next=new Node();
p=p->next;
}
PrintList(head);
// Node * newhead = ReverseList(head);
Node * newhead=ReverseListRecursively(head);
PrintList(newhead);
}
return 0;
}