[原创] 算法之递归(2)- 链表遍历

算法之递归(2)- 链表遍历

在递归(1)中,简单的介绍了递归的思想,并且通过一个例子简单阐述了递归是如何工作的,并且递归的实现是以线性结构来表示的。之所以用线性的,是因为其易于理解;如果使用树结构,将加大对问题的难度,不利于初学者理解递归的思想。

为什么用递归

关 于为什么用递归,我个人的理解是递归不要违背算法的初衷,即期待传入xxx值,加工后返回xxx值。不要为了递归而递归,容易造成对函数语义的奇异。另 外,通过递归,可以让代码更加整洁,短小,精湛,优美。当然,还会存在一定程度的性能损耗;不过,合理的使用,对于那部分的损耗可以忽略不计。

让我们以单链表为例,理解一下递归是如何工作的。

1. 遍历单链表


循环


递归

private void TraveserL(LNode head)
 {
     if (head == null)
         return;

     while (head != null)
     {
         Console.WriteLine(p.data);
         p = p.next;
     }
 }


private void TraveserR(LNode head)
{
    if (head == null)
        return;

    Console.WriteLine(head.data);
    TraveserR(head.next);
}

对于循环遍历我想不用多说了吧。不过,值得注意的是递归的遍历,先对数据进行打印,然后遍历下一个节点。有趣的是,如果将打印语句放在递归调用的后面,将是一个逆序的打印。

分析

假设链表的结构是这样的

A->B->C->D->E->F

递归调用时将发生如下情形

1.在递归调用之前打印(意味着进入函数体的时候打印)

(1)进入函数 (从左到右读)


A->


B->


C->


D->


E->


F->


打印A


打印B


打印C


打印D


打印E


打印F

输出:A, B, C, D, E, F.

(2)当函数退出 (从右到左度)


<-A


<-B


<-C


<-D


<-E


<-F







2. 在递归调用之后 (意味着只有退出函数体的时候,才进行打印)

(1)    进入函数体(从左到右读)


A->


B->


C->


D->


E->


F->







(2)    退出出函数体(从右到左读)


<-A


<-B


<-C


<-D


<-E


<-F


打印A


打印B


打印C


打印D


打印E


打印F

输出:F, E, D, C, B, A

结论,当操作在递归调用之后进行,那么是从后向前对链表执行操作。这也是栈的特性之一。当然,具体何时决定,取决与程序员自己,是想从头开始顺序操作,还是后到前逆序操作,具体问题具体分析。

时间: 2024-09-29 04:41:46

[原创] 算法之递归(2)- 链表遍历的相关文章

[原创] 算法之递归(3)- 链表操作

算法之递归(3)- 链表操作 递归(2)尝试了一个单链表的遍历,同时又分析了如何添加自己的操作,是在递归调用之前,还是在递归调用之后. 今天,打算将问题深入一下,即添加相应的操作在递归的过程中. (免责声明:下面的解法纯属娱乐 ,另外,示例代码未经编译和调试,许多想法未经实践验证.) 查找链表当中倒数第N个节点. 解法一 逐层递归,遍历到最后一个节点,并从返回的节点一次向后递归,遍历N次,找到倒数第N个节点. private LNode targetNode = null; private LN

[原创] 算法之递归(1)

算法之递归(1) 最近事情太多了,很少有时间可以完全静下来认真研究一些东西:每当专注的写代码的时候,总是被其他事情打断.还好,礼拜天来了,总算可以抽出一些时间了J <代码之美>第一章有一个关于模式匹配的问题,即根据正则表达式在相应的文本中找到匹配的值,找到返回1,没找到返回0.撇开具体的实现,里面优美的递归调用倒是深深地吸引了我.于是,我开始重新思考递归,毕竟有些细节之前的思考还不够到位. 什么是递归 我的印象中的递归是函数调用自身来完成预先定义的操作.当然,实际涉及的内容更多,比如退出递归的

[原创] 算法之递归(4)- 应用

最近带着几个在做一个项目,UI层面用的是WPF.之前很少深入的接触WPF,不过接触后,发现WPF的却是很强大. 至少在界面设计上的用户体验较WinForm有了大幅提升. 项目中需要通用化几个样式,并将样式赋值给相应的控件.控件是根据配置文件动态生成的,配置文件是xml格式的层次化较多的结构.所以在动态生成的过程中采用了递归的方式来实现. 下面是一个模拟实例. 目标: 将程序集“PresentationFramework"的所有类型添加到TreeView里面,如果一个类型存在基类行,那么先加入基类

【LeetCode-面试算法经典-Java实现】【145-Binary Tree Postorder Traversal(二叉树非递归后序遍历)】

[145-Binary Tree Postorder Traversal(二叉树非递归后序遍历)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 原题 Given a binary tree, return the postorder traversal of its nodes' values. For example: Given binary tree {1,#,2,3}, 1 2 / 3 return [3,2,1]. Note: Recursive soluti

链表创建和链表遍历算法的演示_C语言

今天搞了一个多小时,头是疼的,应该是没休息好吧,学习了数据结构这一节,感觉收益良多,下面贴上代码和心得: 1 /*24_链表创建和链表遍历算法的演示*/ 2 # include <stdio.h> 3 # include <malloc.h> 4 # include <stdlib.h> 5 6 typedef struct Node 7 { 8 int data;//数据域 9 struct Node * pNext;//指针域 10 }NODE, *PNODE;//

二叉树遍历算法——包含递归前、中、后序和层次,非递归前、中、后序和层次遍历共八种

首先,要感谢网上的参考资料. http://mengliao.blog.51cto.com/876134/1178079(作者:BlackAlpha) http://blog.csdn.net/fzh1900/article/details/14056735(作者:_云淡风轻) http://blog.csdn.net/stpeace/article/details/8138458(作者:stpeace) 二叉树是使用的比较广泛的一种数据结构,这里我写了二叉树的相关操作,包括初始化.新建.以及遍

二叉树三种遍历算法的递归和非递归实现(C++)

struct BinaryTreeNode { int m_nValue; BinaryTreeNode* m_pLeft; BinaryTreeNode* m_pRight; }; //递归前序遍历 void PreOrder(BinaryTreeNode* pNode) { if(pNode!=NULL) { cout<<pNode->m_nValue<<endl; PreOrder(pNode->m_pLeft); PreOrder(pNode->m_pRi

java数据结构与算法之递归思维(让我们更通俗地理解递归)

[版权申明]转载请注明出处(请尊重原创,博主保留追究权) http://blog.csdn.net/javazejian/article/details/53452971 出自[zejian的博客] 关联文章: java数据结构与算法之顺序表与链表设计与实现分析 java数据结构与算法之双链表设计与实现 java数据结构与算法之改良顺序表与双链表类似ArrayList和LinkedList(带Iterator迭代器与fast-fail机制) java数据结构与算法之栈(Stack)设计与实现 j

算法题:求链表倒数第K个结点

说明:本文仅供学习交流,转载请标明出处,欢迎转载!  题目:给出一个单链表,返回倒数第K个结点,最后一个结点为倒数第1个. <剑指offer>上面给的解法是设置两个指针,这里记为p1.p2,先让p2走(k-1)步,然后p1.p2同时走,当p2走到最后一个结点时,p1所指向的结点就是倒数第k个结点. 我觉得按照这样的逻辑写代码反而更容易出错,因为我们需要把我两件重要的问题:(1).p2先走(k-1)步:(2)循环结束的条件是p2到达最后一个结点,即p2->next==NULL.显然这样不太