递归实现不带头结点的单链表逆置

第一次写文章,为了大三算法课挣平时分哈哈哈

以后会不定时更新每一次的算法作业或者平时的一些学习心得~

这是第一个作业的第一题:

对于一个不带头结点的单链表L,设计一个递归算法逆置所有结点。编写完整的程序并进行测试,分析其时间复杂度。

但是看到这道题,王道书的课后题写过类似的题,但是忘得精光,在网上看了一些代码,终于又会了。不得不说,一辈子痛恨递归!!!对于我这种强迫症来说很不友好。暂时立个小flag,下面一段时间,每天练一道递归算法题,而且都要算时间复杂度和空间复杂度,进行“刻意训练”,重复重复再重复(希望这个小flag不要打水漂呜呜呜)

回到正题~~~

思路:

递归函数f(L)返回值p:指向逆置函数的首结点的指针,也就是指向原单链表的尾结点的指针;

递归主体:将f(L)中L所指向的元素链接到逆置链表的末尾。这里会发现每次L所指向的元素本身在原链表中指向了逆置链表的尾元素,所以递归主体的操作只需要对L和L->next进行操作。

每一步都画出来了(递归真的对强迫星人不太友好~~)

    L->next->next = L;//这里的L从指向倒数第二个元素开始,每一次出递归,L就往前指一个 
    L->next = NULL;

同时要注意到,函数的返回值p应该是不变的。这一点会在后面的单步调试中体现。

下面是代码,代码细节部分见注释:

#include<iostream> 
#include <stdlib.h>
using namespace std;
typedef struct LNode
{
    int data;
    struct LNode* next;
}LNode,*Linklist;

//递归函数作用:找到尾结点作为逆置链表的首结点,并将L所指向的结点链接到逆置链表的尾部 
LNode * reverse(LNode *L)
{
    LNode * p;//P是逆置后单链表的首结点(永远指向原单链表的最后一个结点) 
    
    if (L == NULL || L->next == NULL)//若整个单链表为空(没有递归) 或者 递归到最后一个元素(递归出口) 
        return L;//只在L->next为空时,将指向最后一个元素的指针L返回去 (只执行一次) 
        
    p = reverse(L->next);//递归来源:L->next,作为下一次Reverse()的参数 
    
    //以下两步:将L所指向的元素链接到逆置链表的表尾 
    L->next->next = L;//这里的L从指向倒数第二个元素开始,每一次出递归,L就往前指一个 
    L->next = NULL;
    
    return p;//把指向最后一个元素的指针传递出去(作为逆置链表的首指针) 
}


int main()
{
    Linklist L;
    LNode* q;
    L = (LNode*)malloc(sizeof(LNode));
    L->next = NULL;
    q = L;
    int n;
    cout << "请输入链表结点数:";
    cin >> n;
    cout << "请输入链表:" ;
    //不带头结点的单链表创建方法:先创建一个带头结点的单链表,再让头指针指向首结点 
    for (int i = 0;i < n;i++)
    {
        LNode* p;
        p = (LNode*)malloc(sizeof(LNode));
        cin >> p->data;
        q->next = p;
        q = p;
        q->next = NULL;
    }
    L = L->next;
    
    L = reverse(L);
    cout << "链表逆置后:";
    while (L != NULL)
    {
        cout << L->data << " ";
        L = L->next;
    }
    cout << endl;
    return 0;
}

下面是Debug步骤:

首先,在递归函数Reverse()上打上断点(今晚刚学会的打断点Debug...哎~之前我在干嘛。。。),添加查看L和p变量。

在运行窗口输入如下:

刚开始,原链表的首结点的地址为0x1718b0,p是系统赋的随机值

接着,第二次进入递归函数,指向第二个元素的指针地址为0x174070,p依旧是系统赋的随机值

最后一次,由于L->next==NULL了,满足递归终止条件,最后一个元素的指针地址为0z1740b0,返回给p指针,并一直传递到最后。

下面,你会发现L指针的值从最后一个元素的指针地址往回变,同时p指针的值一直都是最后一个元素的指针地址。

最后递归结束,继续下面的输出:

运行结果:

时间复杂度分析:(不确定对不对)

由于逆置函数中的递归主体的基本操作为“L->next->next = L;L->next = NULL;”,递归来源是L->next,由单链表中的结点个数n决定,所以整个算法的时间复杂度为O(n)

第一次写博客文章,可能排版、语言组织不是很好,以后一定会多加锻炼~~多多包函~~有不同的想法可以在评论区留言交流~

(写于2023-3-12 晚9:16)

  • 22
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值