当前位置:   article > 正文

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

递归逆置

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

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

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

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

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

回到正题~~~

思路:

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

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

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

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

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

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

  1. #include<iostream>
  2. #include <stdlib.h>
  3. using namespace std;
  4. typedef struct LNode
  5. {
  6. int data;
  7. struct LNode* next;
  8. }LNode,*Linklist;
  9. //递归函数作用:找到尾结点作为逆置链表的首结点,并将L所指向的结点链接到逆置链表的尾部
  10. LNode * reverse(LNode *L)
  11. {
  12. LNode * p;//P是逆置后单链表的首结点(永远指向原单链表的最后一个结点)
  13. if (L == NULL || L->next == NULL)//若整个单链表为空(没有递归) 或者 递归到最后一个元素(递归出口)
  14. return L;//只在L->next为空时,将指向最后一个元素的指针L返回去 (只执行一次)
  15. p = reverse(L->next);//递归来源:L->next,作为下一次Reverse()的参数
  16. //以下两步:将L所指向的元素链接到逆置链表的表尾
  17. L->next->next = L;//这里的L从指向倒数第二个元素开始,每一次出递归,L就往前指一个
  18. L->next = NULL;
  19. return p;//把指向最后一个元素的指针传递出去(作为逆置链表的首指针)
  20. }
  21. int main()
  22. {
  23. Linklist L;
  24. LNode* q;
  25. L = (LNode*)malloc(sizeof(LNode));
  26. L->next = NULL;
  27. q = L;
  28. int n;
  29. cout << "请输入链表结点数:";
  30. cin >> n;
  31. cout << "请输入链表:" ;
  32. //不带头结点的单链表创建方法:先创建一个带头结点的单链表,再让头指针指向首结点
  33. for (int i = 0;i < n;i++)
  34. {
  35. LNode* p;
  36. p = (LNode*)malloc(sizeof(LNode));
  37. cin >> p->data;
  38. q->next = p;
  39. q = p;
  40. q->next = NULL;
  41. }
  42. L = L->next;
  43. L = reverse(L);
  44. cout << "链表逆置后:";
  45. while (L != NULL)
  46. {
  47. cout << L->data << " ";
  48. L = L->next;
  49. }
  50. cout << endl;
  51. return 0;
  52. }

下面是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)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/357340
推荐阅读
相关标签
  

闽ICP备14008679号