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

算法之递归(3)- 链表操作

递归(2)尝试了一个单链表的遍历,同时又分析了如何添加自己的操作,是在递归调用之前,还是在递归调用之后。

今天,打算将问题深入一下,即添加相应的操作在递归的过程中。

(免责声明:下面的解法纯属娱乐 ,另外,示例代码未经编译和调试,许多想法未经实践验证。)

查找链表当中倒数第N个节点。

解法一

逐层递归,遍历到最后一个节点,并从返回的节点一次向后递归,遍历N次,找到倒数第N个节点。

        private LNode targetNode = null;

        private LNode FindLastNthNode(LNode head, int index)
        {
            if (head.Next == null)
            {
                return head;
            }

            FindLastNthNode(head.Next, index);

            LNode tmpNode = head;

            while ((head.Next != null) && (index > 0))
            {
                head = head.Next;
                index--;
            }

            if (head.Next == null && index == 0)
            {
                targetNode = tmpNode;
                return targetNode;
            }

            return targetNode;

        }

分析

1. 额外的全局性的辅助变量。

2. 时间复杂度为O(index * n),n为链表的长度。

3. 性能开销较大。

解法二(解法一的变形)

每当遍历到当前节点,即再循环向后遍历n个,如果节点遍历到最后,并且index自减等于0,说明当前节点即为要找的倒数第n个。也就是说解法一是从后向前找,而解法二是从前向后找。

        private LNode targetNode2 = null;

        private LNode FindLastNthNode2(LNode head, int index)
        {
            if (head.Next == null)
                return head;

            LNode tmpNode = head;

            while (head != null && index >= 0)
            {
                head = head.Next;
                index--;
            }

            if (head == null && index == 0)
            {
                targetNode2 = tmpNode;
                return targetNode2;
            }

            return targetNode2;
        }

分析:与解法一一样。

解法三

定义一个全局变量,用来计数,当递归从最后一个节点返回时,计数器减减,当等于0时,这个节点即是要找的倒数第N个节点。

        private int counter = 0;
        private LNode targetNode2;

        private LNode FindLastNthNode2(LNode head, int index)
        {
            if (head.Next == null)
            {
                counter = index;
                return head;
            }

            FindLastNthNode2(head.Next, index);

            counter--;

            if (counter == 0)
            {
                targetNode2 = head;
                return targetNode2;
            }

            return targetNode2;
        }

分析

1. 两个辅助变量。

2. 时间复杂度为O(n)。

3. 多余的index,累赘的counter。

======= 后记 =======

其实以上几个解决方案个人觉得都不够perfect。

像类似于链表这样的操作,基本就是两指针。

于是我重新给了一个方案如下。

(该段代码已经编译、运行及测试通过)

解法四:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication17
{
    class Program
    {
        static void Main(string[] args)
        {
            Node head = new Node()
            {
                Data = "Head"
            };

            Node lucas = new Node()
            {
                Data = "Lucas"
            };

            Node bill = new Node()
            {
                Data = "Bill"
            };

            Node steve = new Node()
            {
                Data = "Steve"
            };

            Node anders = new Node()
            {
                Data = "Anders"
            };

            Node jordan = new Node()
            {
                Data = "Jordan"
            };

            head.Next = lucas;
            lucas.Next = bill;
            bill.Next = steve;
            steve.Next = anders;
            anders.Next = jordan;

            Program p = new Program();
            Node resultNode = p.FindLastNthNode(head, 2);

            Console.WriteLine(resultNode.Data);
            Console.ReadLine();
        }

        private Node FindLastNthNode(Node node, int n)
        {
            if(node == null)
            {
                return node;
            }

            if(n <= 0)
            {
                throw new ArgumentException("n");
            }

            Node node1 = node;
            Node node2 = node;

            return this.InternalFindLastNthNode(node1, node2, n);
        }

        private Node InternalFindLastNthNode(Node node1, Node node2, int n)
        {
            if(node1 == null)
            {
                return node2;
            }

            if(n == 0)
            {
                return this.InternalFindLastNthNode(node1.Next, node2.Next, 0);
            }

            return this.InternalFindLastNthNode(node1.Next, node2, --n);
        }
    }

    public class Node
    {
        public string Data { get; set; }
        public Node Next { get; set; }
    }
}

Best Regards,

Lucas Luo

时间: 2024-10-27 08:02:17

[原创] 算法之递归(3)- 链表操作的相关文章

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

算法之递归(2)- 链表遍历 在递归(1)中,简单的介绍了递归的思想,并且通过一个例子简单阐述了递归是如何工作的,并且递归的实现是以线性结构来表示的.之所以用线性的,是因为其易于理解:如果使用树结构,将加大对问题的难度,不利于初学者理解递归的思想. 为什么用递归 关 于为什么用递归,我个人的理解是递归不要违背算法的初衷,即期待传入xxx值,加工后返回xxx值.不要为了递归而递归,容易造成对函数语义的奇异.另 外,通过递归,可以让代码更加整洁,短小,精湛,优美.当然,还会存在一定程度的性能损耗:不

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

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

算法刷题-1-单链表操作

1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 //练习单链表操作:给出单链表 head 和 n,要求删除单链表倒数第n个结点,并连接剩余结点 5 //例子:1-2-3-4-5,n=2,删除后应该是:1-2-3-5 6 typedef struct ListNode{ 7 int data; 8 ListNode *next; 9 }ListNode; 10 11 int create

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

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

【数据结构与算法】java链表操作

链表操作代码量少但是比较容易出错,是比较适合面试的地方. 代码实现 /** * 源码名称:MyLinkList.java * 日期:2014-09-05 * 程序功能:java链表操作 * 版权:[email protected] * 作者:A2BGeek */ import java.util.Stack; public class MyLinkList { class LinkNode<T> { private T mValue; private LinkNode<T> mNe

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

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

算法之递归思想

树的遍历的实现就是典型的递归思想. /* * description:树的遍历示例,递归 * 访问顺序: * 前序: 当前节点 - 左子树 - 右子树 * 中序: 左子树 - 当前节点 - 右子树 * 后序: 左子树 - 右子树 - 当前节点 * * writeby: nick * date: 2012-10-22 23:56 */ #include <iostream> using namespace std; struct node { int item; node *l, *r; nod

数据结构与算法5: 递归(Recursion)

数据结构与算法5: 递归(Recursion) 写在前面 <软件随想录:程序员部落酋长Joel谈软件>一书中<学校只教java的危险性>一章提到,大学计算机系专业课有两个传统的知识点,但许多人从来都没搞懂过,那就是指针和递归.我也很遗憾没能早点熟练掌握这两个知识点.本节一些关键知识点和部分例子,都整理自教材或者网络,参考资料列在末尾.如果错误请纠正我. 思考列表: 1)什么程序具有递归解决的潜质? 2)递归还是非递归算法,怎么选择? 3)递归程序构造的一般模式 1.递归定义 首要引

10、单链表操作

单链表操作 单链表操作1 /*单链表的类型定义*/ typedef int DataType; typedef struct node { DataType data; struct node * next; }LinkNode, *LinkList; /*单链表的定位运算*/ LinkNode *Locate(LinkNode *L, int k)//????为什么此处是LinkNode *Locate()类型,表示什么意思 { LinkNode *p; int i; i= 1; p = L-