ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

再谈递归

2021-05-09 23:02:30  阅读:178  来源: 互联网

标签:head return 递归 递归性 再谈 next root


  我们似乎记得有这么一个观点”递归都可以通过迭代(循环)实现,但是迭代不一定能够通过递归实现“。那么我们是否思考过这其中的道理呢?

一、递归概念

  对于什么是递归,众说纷纭。我个人比较认可的一种简单直接的文字描述是:先递进,再回归;还有一种是动图描述:一只兔子拿着一面镜子,镜子里面和镜子的镜子的...镜子里面还是相同的场景,循环不止。当然,递归可不能这么无限下去,容易栈溢出,所以,递归得有出口。

二、什么时候用递归

  第一次接触递归的例子是斐波拉契函数:F(n) = F(n - 1) + F(n - 2), F(1) = F(0) = 1; n >= 2。对该函数进行分析不难发现,如果我们想求解一个大的斐波拉契函数值m,我们必须得先不断递进到我们能够获取到的函数值,例如:F(1) = F(0) = 1。然后再回归,依次求解F(2) = F(1) + F(0); F(3) = F(2) + F(1); ... ....; F(m)  = F(m - 1) + F(m - 2)。

  代码如下:

1 int F(int n)
2 {
3      if(n == 0 || n == 1){
4          return 1; 
5      }
6       return F(n - 1) + F(n - 2);   
7 }

  所以,斐波拉契拥有完美的递归性,非常适合使用递归实现。此时,递归出口:n = 0 或 n = 1的时候返回1,递归条件:F(n - 1) + F(n - 2);当然迭代也能够完美实现该函数。到这里,我们就明白了,能够迭代实现的不一定拥有递归性,比如:递归出口。我们可以这么通俗的理解递归:递归是一种将复杂问题逐步分解为小的相同问题,直到分解到我们能够求解的最小问题为止,每个次小问题的解都给予更小问题的解,最后回归到复杂问题的解的方法。一般能够用数学公式表示的,可通过数学公式知道是否具有递归性;但是有时候我们的问题并不能单纯的通过数学公式表示,也可能具有递归性,比如汉诺塔。

三、哪些数据结构拥有递归性

  拥有完美递归性的数据结构里面想到的是二叉树。例如:

                      A
                   /      \
                  B       C
                /   \    /   
               D    E   F

  从根节点A看,就是一个二叉树;从A的左子节点B或右子节点C向下看都是一颗二叉树。其实,链表也拥有递归性。例如:

-----------    -----------   -----------
| A | next|--> | B | next|-->| C | null|
-----------    ------------  -----------

  当我们继续向尾部插入节点D的时候,我们可以将A --> B -->C这个链表当成一个头节点head,只有找到这个头节点,然后head->D即可。

四、二叉树和链表递归实现

  二叉树数的很多操作都可以直接用递归实现,代码逻辑简单,最典型的就是深度遍历,如下:

 1 // Root-Left-Right
 2 void PrevOrder(Node* root)
 3 {
 4     if(root == nullptr){
 5         return;
 6     }
 7     std::cout  << root->data << ",";
 8     PrevOrder(root->left);
 9     PrevOrder(root->right);
10 }
11 
12 // Left-Root-Right
13 void Inorder(Node* root)
14 {
15     if(root == nullptr){
16         return;
17     }
18     Inorder(root->left);
19     std::cout << root->data << ",";
20     Inorder(left->right);
21 }
22 
23 // Left-Right-Root
24 int PostOrder(Node* root)
25 {
26     if(root == nullptr){
27         return;
28     }
29     PostOrder(root->left);
30     PostOrder(root->right);
31     std::cout << root->data << ",";
32 }

  单链表尾插递归算法:

1 Node* PushBack(Node* head, int data)
2 {
3     // 带头结点的链表
4     if(head->next == nullptr){
5        return new Node(data);
6     }
7     head->next = PushBack(head->next, data);
8     return head;
9 }

  单链表倒置递归算法:

 1 Node* Invert(Node* head)
 2 {
 3     if(head->next == nullptr){
 4         return head;
 5     } 
 6     auto newHead = Invert(head->next); // head--> newHead
 7    
 8     newHead->next = head;  // head <--> newHead
 9     head->next = nullptr;      // head<-- newHead
10     return newHead;
11 }

  上面迭代法的逻辑也相对比较简单,感兴趣的同学可以自行实现。

  上面是我们对递归算法的个人看法,主要是方便个人回顾之用,也希望其他读者能够对递归的认识起到一点理解的作用!

标签:head,return,递归,递归性,再谈,next,root
来源: https://www.cnblogs.com/smartNeo/p/14749208.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有