C++ Using recursion to process linked list, 深入理解递归的过程(part1)

在这里我们介绍使用递归的方法去处理链表。

关于递归, 可参考以前的博客。 链表之所以可以采用递归的方式处理, 是因为链表有递归的数据结构(recursive data structure)(大问题化解为基本case 和由基本的case和生成规则生成其他部分)。

 

 上图是一个三个节点(Node)的linked list.。 我们可以将其想想成i一个3个节点的linked list含有一个两个节点的linked list(Mark and Tom), 这两个节点的linked list 又含有一个节点(Tom)的linked list, 所以这就是递归的数据结构。(large stucture 由smaller structure of the same form组成)。

对于递归的数据结构, 我们就可以写一个function来处理这个数据结构(例如linked list)。

下面写一个函数将linked list的各个节点的数据打印出来。

 

注意此时curr指针视为函数的参数了。

接下来, 对于这个函数体, 我们需要考虑base case, 和recursive case, 以便递归实现这个函数。

不难看出base case 是我们的指针curr 指向NULL, 这种情况下, 我们不需要做任何处理(例如打印的动作), 我们只需要从函数printList 中return 回来。所以base case 我们是不关心的

对于recursive case, 我们可以如下写:

void printList(node* curr) {

   if(curr != 0) {

      cout << *curr << endl;

      printList(curr->next); // 这就是recursive call, 没有recursive call, 就不是递归的函数。

   }

}

 

 

 

使用递归的does not buy us anything, 相反, 坏处是占用太多的资源。 因为每一次递归调用的时候都会分配一个新stack frame(重新分配局部变量)在旧的stack frame(保存了上次递归调用的所有局部变量等等) 之上, 非常耗费内存。

在给主程序分配的的stackframe之上, 第一次调用printList, 打印出April, 执行到printList(curr -> next), 也就是完成第二次递归调用, 重新分配stack frame以保存当前执行的状态。:

 

在分配的stack frame之上, 执行当前递归调用的printList函数, 打印出Mark, 再次递归调用, 分配一个新的stack frame给当前的调用 进入下一轮的递归调用, curr此时指向下一个节点:

 

 

 

 

打印出Mark后, 执行第三次递归调用, 在刚才分配stack frame之上, 打印出Tom, 再一次调用printList函数, 在之前的Tom分配一个stack frame 之上执行程序。,

 

在Tom的stack frame 之上执行新的调用。

由于此时curr 指向了NULL, 所以直接pop out, 返回到Tom的stack frame 之上, 置信Tom的stack frame。 不难看出, 由于在此递归函数中的递归调用的后面没有别的语句, 直接返回void, 将此stack frame 释放掉, 到Mark的stack frame中执行。下面的依次类推, 直至返回到主程序。

 

 

释放掉了Tom的stack frame, 按照保存的断点执行Mark 的stack frame:

 

返回void, 释放掉了Mark的stack frame, 到April的stack frame执行。

返回void, 释放掉April 的stack frame, 返回到主程序调用发生的下一条语句(也就是断点所在位置恢复) 执行。

开始执行主程序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值