本题要求实现一个函数,将给定的单链表逆转。
函数接口定义:
List Reverse( List L );
其中List结构定义如下:
typedef struct Node PtrToNode;
struct Node {
ElementType Data; / 存储结点数据 /
PtrToNode Next; / 指向下一个结点的指针 /
};
typedef PtrToNode List; / 定义单链表类型 */
L是给定单链表,函数Reverse要返回被逆转后的链表。
裁判测试程序样例:
#include <stdio.h>
#include <stdlib.h>typedef int ElementType; typedef struct Node *PtrToNode; struct Node {
ElementType Data;
PtrToNode Next; }; typedef PtrToNode List;List Read(); /* 细节在此不表 / void Print( List L ); / 细节在此不表 */
List Reverse( List L );
int main() {
List L1, L2;
L1 = Read();
L2 = Reverse(L1);
Print(L1);
Print(L2);
return 0; }/* 你的代码将被嵌在这里 */
输入样例:
5
1 3 4 5 2
输出样例:
1
2 5 4 3 1
刚开始我有两个疑问的地方:
第一,还不确定样例中那一串数字上的5是什么意思,而且到了输出时它是怎么变成1的。
第二,不知道这里的链表有没有头结点。
经过我的思考和多次调试后才知道:
此题中的链表是没有头结点的。
而那个5是输入时的数字长度,后面输出的1只是输出的操作后的链表中的元素(即原本链表只保存第一个元素(如果该表不为空的话))。
解决这两个疑问后就好办多了,刚开始我用的是“数数”的方式,从链尾开始将数据按顺序放入新的链表中,特笨的一方法,现在看来很憨!!!⊙﹏⊙
代码一如下:
List Reverse( List L )
{
int n=0;
List pev,pri,tra,head=L;
pev=L;
/*数该链表的长度找到表尾的位置*/
for(;pev!=NULL;n++)
pev=pev->Next;
pri=NULL;
/*开始挪窝*/
while(n!=0)
{
tra=L;
for(int i=0;i<n;i++)
{
if(i==n-1)
{
pev=(List)malloc(sizeof(struct Node));
pev->Data=tra->Data;
pev->Next=NULL;
if(pri!=NULL)
pri->Next=pev;
else
head=pev; //如果是第一次循环的话我们得用head指针记录表头的位置
pri=pev;
n--;
break;
}
tra=tra->Next;
}
}
if(L!=NULL)//这里将表头后面的节点掐掉!!
L->Next=NULL;
return head;
}
代码一太笨了!!它长达三十多行!!而且效率极低,我就想找找能不能有一种从表头开始遍历放入新链表的方法,这样子就可以省掉一大部分用来数数的时间。额。。。。头插法貌似是个特别符合该要求的方法!!我居然没有第一时间想到它~~
于是十分钟后,有了较好一点的头插法的代码二。
代码二:
List Reverse( List L )
{
List pri=NULL,P,pre;
for(P=L;P!=NULL;P=P->Next)
{
pre=(List)malloc(sizeof(struct Node));
pre->Data=P->Data;
if(pri==NULL) //如果是第一个节点的话,则让它变成表尾
pre->Next=NULL;
else
pre->Next=pri;
pri=pre;
}
if(L!=NULL) L->Next=NULL;
return pri;
}
代码二在我眼中算是较好的一种解法了,但是感觉在空间上有浪费之处,若是咱直接将原来的链表L直接倒置过来会不会更好点,这样子原本的头结点L变成了尾结点后面指的也是NULL,第一第二点都符合,说干就干,于是二十分钟后有了终极版本
代码三:
List Reverse( List L )
{
List pre=L,pri=L;
while(pre!=NULL&&L->Next!=NULL)//这里的pre!=NULL防止L是空表而发生段错误
{
pre=L->Next;//先让pre指向L的下一个节点
L->Next=pre->Next;//再让L中的Next指针指向pre的下一个节点
pre->Next=pri;//把pre所指的节点移到最前面去
pri=pre;//记录下最前面的位置
}
return pre;
}
代码三算是比较好的一种方法了,但也是最费脑子滴!!
码出代码三后我血条直接就空了! (つД`)・゚・
现在充电去啦,嘿嘿(>ω・* )ノ