单链表逆转

本题要求实现一个函数,将给定的单链表逆转。
函数接口定义:

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;
}

代码三算是比较好的一种方法了,但也是最费脑子滴!!
码出代码三后我血条直接就空了! (つД`)・゚・
现在充电去啦,嘿嘿(>ω・* )ノ

  • 10
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值