C# 迭代,递归,回调--13

news2025/1/16 3:05:35

目录

一.迭代

迭代器示例:

关键点:

优势:

二.递归

递归示例:

关键点:

优势:

注意:

三.回调

回调示例:

关键点:

优势:

应用场景:

4.三种模式的特点对比:

迭代:

递归:

回调:


一.迭代

在C#中迭代通常指重复执行一系列指令

在C#中,迭代器是一种特殊的结构,允许我们自定义遍历集合的方式,主要使用yield return关键字

yield return关键字的主要优点包括:

  • 简化了迭代器的实现:不需要手动维护状态或创建临时集合
  • 提高了代码的可读性和可维护性:使用 yield return 的方法显得更加直观
  • 延迟执行:元素在需要时才生成,适合处理大量数据或计算密集型操作

除了 yield return,还有一个相关的关键字 yield break,用于终止迭代器并退出迭代

迭代器示例:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("迭代器示例:\n");

        // 1. 使用迭代器方法
        Console.WriteLine("1. 斐波那契数列(前10个数):");
        foreach (var num in Fibonacci(10))
        {
            Console.Write($"{num} ");
        }
        Console.WriteLine("\n");

        // 2. 自定义集合迭代
        var customCollection = new CustomCollection(5);
        Console.WriteLine("2. 自定义集合迭代:");
        foreach (var item in customCollection)
        {
            Console.Write($"{item} ");
        }
        Console.WriteLine("\n");

        // 3. yield return 示例
        Console.WriteLine("3. 生成偶数序列(0-10):");
        foreach (var even in GetEvenNumbers(10))
        {
            Console.Write($"{even} ");
        }
        Console.WriteLine("\n");

        // 4. 带条件的迭代器
        Console.WriteLine("4. 按条件过滤的数字(1-20中能被3整除的数):");
        foreach (var num in GetNumbersDivisibleBy3(20))
        {
            Console.Write($"{num} ");
        }
        Console.WriteLine("\n");

        Console.ReadKey();
    }

    // 斐波那契数列迭代器
    static IEnumerable<int> Fibonacci(int count)
    {
        int current = 0, next = 1;
        for (int i = 0; i < count; i++)
        {
            yield return current;
            int temp = current + next;
            current = next;
            next = temp;
        }
    }

    // 生成偶数的迭代器
    static IEnumerable<int> GetEvenNumbers(int max)
    {
        for (int i = 0; i <= max; i++)
        {
            if (i % 2 == 0)
                yield return i;
        }
    }

    // 能被3整除的数的迭代器
    static IEnumerable<int> GetNumbersDivisibleBy3(int max)
    {
        for (int i = 1; i <= max; i++)
        {
            if (i % 3 == 0)
                yield return i;
        }
    }
}

// 自定义可迭代集合
class CustomCollection : IEnumerable<int>
{
    private int[] array;

    public CustomCollection(int size)
    {
        array = new int[size];
        for (int i = 0; i < size; i++)
        {
            array[i] = i * i; // 存储数字的平方
        }
    }

    public IEnumerator<int> GetEnumerator()
    {
        for (int i = 0; i < array.Length; i++)
        {
            yield return array[i];
        }
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

关键点:

  • 循环结构: 在C#中,迭代通常通过forwhiledo...whileforeach等循环结构实现

  • 用途: 用于在数量已知或者条件可判定的情况下重复执行某段代码,例如遍历数组、执行固定次数的计算等

  • 控制条件: 迭代需要有明确的开始条件、结束条件,以及每次迭代时的状态更新,避免出现无限循环

优势:

  • 可控性强: 通过明确的控制条件,可以精确地控制迭代次数
  • 效率高: 迭代通常比递归占用更少的内存,因为不涉及函数调用的堆栈开销

二.递归

递归是指函数在其定义中直接或间接调用自身的编程技巧

递归通常用于解决可以分解为相同子问题的问题,如阶乘,斐波那契数列等

递归示例:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("递归示例演示:\n");

        // 1. 阶乘计算
        int n = 5;
        Console.WriteLine($"1. {n}的阶乘是: {CalculateFactorial(n)}");

        // 2. 斐波那契数列
        int position = 8;
        Console.WriteLine($"\n2. 斐波那契数列第{position}个数是: {Fibonacci(position)}");

        // 3. 数组求和
        int[] numbers = { 1, 2, 3, 4, 5 };
        Console.WriteLine($"\n3. 数组求和结果: {ArraySum(numbers, numbers.Length - 1)}");

        // 4. 字符串反转
        string text = "Hello, World!";
        Console.WriteLine($"\n4. 字符串 \"{text}\" 反转后: {ReverseString(text)}");

        // 5. 最大公约数
        int a = 48, b = 36;
        Console.WriteLine($"\n5. {a}和{b}的最大公约数是: {GCD(a, b)}");

        // 6. 汉诺塔问题
        Console.WriteLine("\n6. 汉诺塔移动步骤(3个盘子):");
        HanoiTower(3, 'A', 'B', 'C');

        // 7. 目录结构显示
        Console.WriteLine("\n7. 显示目录结构:");
        string path = @"C:\Example"; // 替换为实际路径
        try
        {
            ShowDirectoryStructure(path, 0);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"读取目录时出错: {ex.Message}");
        }

        Console.ReadKey();
    }

    // 1. 计算阶乘
    static int CalculateFactorial(int n)
    {
        if (n <= 1) return 1;
        return n * CalculateFactorial(n - 1);
    }

    // 2. 斐波那契数列
    static int Fibonacci(int n)
    {
        if (n <= 1) return n;
        return Fibonacci(n - 1) + Fibonacci(n - 2);
    }

    // 3. 数组求和
    static int ArraySum(int[] array, int index)
    {
        if (index < 0) return 0;
        return array[index] + ArraySum(array, index - 1);
    }

    // 4. 字符串反转
    static string ReverseString(string str)
    {
        if (string.IsNullOrEmpty(str) || str.Length <= 1)
            return str;
        return ReverseString(str.Substring(1)) + str[0];
    }

    // 5. 最大公约数(欧几里得算法)
    static int GCD(int a, int b)
    {
        if (b == 0) return a;
        return GCD(b, a % b);
    }

    // 6. 汉诺塔问题
    static void HanoiTower(int n, char from, char auxiliary, char to)
    {
        if (n == 1)
        {
            Console.WriteLine($"将盘子 1 从 {from} 移动到 {to}");
            return;
        }
        
        HanoiTower(n - 1, from, to, auxiliary);
        Console.WriteLine($"将盘子 {n} 从 {from} 移动到 {to}");
        HanoiTower(n - 1, auxiliary, from, to);
    }

    // 7. 显示目录结构
    static void ShowDirectoryStructure(string path, int level)
    {
        // 添加缩进
        string indent = new string(' ', level * 2);
        
        try
        {
            // 显示当前目录
            DirectoryInfo dir = new DirectoryInfo(path);
            Console.WriteLine($"{indent}[{dir.Name}]");

            // 显示文件
            foreach (FileInfo file in dir.GetFiles())
            {
                Console.WriteLine($"{indent}  {file.Name}");
            }

            // 递归显示子目录
            foreach (DirectoryInfo subDir in dir.GetDirectories())
            {
                ShowDirectoryStructure(subDir.FullName, level + 1);
            }
        }
        catch (UnauthorizedAccessException)
        {
            Console.WriteLine($"{indent}访问被拒绝");
        }
    }
}

关键点:

  • 基例(终止条件): 递归必须要有一个明确的终止条件,即基例,否则会导致无限递归

  • 递归关系: 问题的解可以表示为其子问题的解的组合

  • 堆栈开销: 每一次递归调用都会在调用栈中存储当前函数的状态,深入太深可能导致栈溢出

优势:

  • 代码简洁: 对于某些问题,递归能使代码更易读、更简洁
  • 自然适应某些算法: 如树的遍历、分治算法等,递归实现更符合逻辑

注意:

  • 效率问题: 递归可能导致大量的函数调用,增加开销。
  • 栈溢出风险: 如果递归深度太大,可能导致栈溢出错误。

三.回调

回调是指将一个函数作为参数传递给另一个函数,当特定事件发生或条件满足时调用该函数

在C#中,回调通常通过委托事件来实现

回调示例:

class Program
{
    // 定义委托类型
    public delegate void ProcessCompleted(string result);
    public delegate int CalculateDelegate(int x, int y);

    static void Main(string[] args)
    {
        Console.WriteLine("回调示例:\n");

        // 1. 使用委托回调
        Console.WriteLine("1. 委托回调示例:");
        ProcessCompleted callback = ShowResult;
        ProcessWithCallback("任务1", callback);

        // 2. 使用Action/Func
        Console.WriteLine("\n2. Action/Func回调示例:");
        ProcessWithAction("任务2", (result) => 
        {
            Console.WriteLine($"Lambda回调结果: {result}");
        });

        // 3. 事件回调
        var processor = new TaskProcessor();
        processor.OnCompleted += (sender, result) => 
        {
            Console.WriteLine($"事件回调结果: {result}");
        };
        processor.StartProcess("任务3");

        // 4. 异步回调
        Console.WriteLine("\n4. 异步回调示例:");
        AsyncProcessDemo().Wait();

        // 5. 计算器回调示例
        Console.WriteLine("\n5. 计算器回调示例:");
        CalculateWithCallback(10, 5, Add);
        CalculateWithCallback(10, 5, Subtract);

        Console.ReadKey();
    }

    // 基本回调方法
    static void ShowResult(string result)
    {
        Console.WriteLine($"普通回调结果: {result}");
    }

    // 使用委托的处理方法
    static void ProcessWithCallback(string input, ProcessCompleted callback)
    {
        // 模拟处理过程
        Thread.Sleep(100);
        string result = $"处理完成: {input}";
        callback(result);
    }

    // 使用Action的处理方法
    static void ProcessWithAction(string input, Action<string> callback)
    {
        Thread.Sleep(100);
        string result = $"处理完成: {input}";
        callback(result);
    }

    // 异步回调示例
    static async Task AsyncProcessDemo()
    {
        await ProcessAsync("异步任务", (result) =>
        {
            Console.WriteLine($"异步回调结果: {result}");
        });
    }

    static Task ProcessAsync(string input, Action<string> callback)
    {
        return Task.Run(() =>
        {
            Thread.Sleep(100);
            string result = $"处理完成: {input}";
            callback(result);
        });
    }

    // 计算器回调方法
    static int Add(int x, int y) => x + y;
    static int Subtract(int x, int y) => x - y;

    static void CalculateWithCallback(int x, int y, CalculateDelegate callback)
    {
        int result = callback(x, y);
        Console.WriteLine($"计算结果: {result}");
    }
}

// 使用事件的处理器类
class TaskProcessor
{
    public event EventHandler<string> OnCompleted;

    public void StartProcess(string input)
    {
        // 模拟处理过程
        Thread.Sleep(100);
        string result = $"处理完成: {input}";
        
        // 触发事件
        OnCompleted?.Invoke(this, result);
    }
}

关键点:

  • 委托(Delegate): 在C#中,回调通常通过委托实现,委托是对函数的引用,可以作为参数传递

  • 事件(Event): 事件是委托的特殊形式,用于发布和订阅机制,常用于GUI编程、异步操作等

  • 异步编程: 回调在异步编程中非常重要,可以在异步操作完成后执行后续处理

优势:

  • 解耦: 回调机制使得调用者和被调用者之间的依赖减少,代码更加灵活
  • 灵活性: 可以在运行时决定调用哪个函数,增强了代码的可扩展性

应用场景:

  • 事件处理: 例如按钮点击事件,网络请求完成事件等
  • 异步操作: 在异步编程中,回调函数用于在任务完成后继续执行后续逻辑

4.三种模式的特点对比:

迭代:

        特点:

  • 逐个处理元素
  • 内存效率高
  • 代码直观

        适用场景:

  • 集合遍历
  • 简单重复操作
  • 需要延迟计算

递归:

        特点:

  • 自调用
  • 代码简洁
  • 需要注意栈溢出

        适用场景:

  • 树形结构处理
  • 分治算法
  • 自然递归问题

回调:

        特点:

  • 灵活可配置
  • 解耦操作
  • 支持异步

        适用场景:

  • 事件处理
  • 异步操作
  • 策略模式

策略模式(Strategy Pattern)是一种行为设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以互相替换。策略模式使得算法可以在不影响客户端的情况下发生变化。它通过定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换,从而让算法的变化不会影响到使用算法的客户。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2277308.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

欧拉路径算法

欧拉图&#xff1a; 对于应该连通图G&#xff0c;有&#xff1a; 1欧拉路径&#xff1a;一条路径&#xff0c;它能够不重复地遍历完所有的边&#xff0c;这个性质很像不重复地一笔画完所有边&#xff0c;所以有些涉及到欧拉路径的问题叫做一笔画问题。 2欧拉回路&#xff1a…

【进程与线程】程序和进程在内存中的表现

在计算机系统中&#xff0c;程序和进程是两个密切相关但又有本质区别的概念&#xff0c;尤其在内存中的表现上有显著不同&#xff1a; 在这张图中可以直观地看出程序和进程在内存中的结构区别。 基本定义 程序 程序 是一个 静态实体&#xff0c;表示一组写好的指令和数据的…

“多维像素”多模态雷视融合技术构建自动驾驶超级感知能力|上海昱感微电子创始人蒋宏GADS演讲预告

2025年1月14日&#xff0c;第四届全球自动驾驶峰会将在北京中关村国家自主创新示范区展示交易中心-会议中心举行。经过三年的发展&#xff0c;全球自动驾驶峰会已经成长为国内自动驾驶领域最具影响力、规模最大的产业峰会之一。昱感微电子创始人&CEO受到主办方邀请&#xf…

Linux创建server服务器实现多方信息收发

一&#xff0c;服务端 1.创建socket套接字&#xff0c;用于网络通信&#xff0c;同一台机器上的进程也可以通过本地套接字进行通信 //1.socket s_fd socket(AF_INET,SOCK_STREAM,0); if(s_fd -1){ perror("socket"); exit(-1); } //server address s_addr.sin_fami…

UML系列之Rational Rose笔记七:状态图

一、新建状态图 依旧是新建statechart diagram&#xff1b; 二、工作台介绍 接着就是一个状态的开始&#xff1a;开始黑点依旧可以从左边进行拖动放置&#xff1a; 这就是状态的开始&#xff0c;和活动图泳道图是一样的&#xff1b;只能有一个开始&#xff0c;但是可以有多个…

jsx语法中el-table-v2中cellRender如何使用动态绑定

答案&#xff1a;:attribute"xx"改为attribute{xx} 改写&#xff1a; const columns ref([{ key: index, dataKey: index, title: t(setting.index), width: 100 },{ key: no, dataKey: no, title: t(setting.key), width: 100 },{ key: name, dataKey: name, tit…

【初识扫盲】厚尾分布

厚尾分布&#xff08;Fat-tailed distribution&#xff09;是一种概率分布&#xff0c;其尾部比正态分布更“厚”&#xff0c;即尾部的概率密度更大&#xff0c;极端值出现的概率更高。 一、厚尾分布的特征 尾部概率大 在正态分布中&#xff0c;极端值&#xff08;如距离均值很…

EFK采集k8s日志

在 Kubernetes 集群中&#xff0c;需要全面了解各个 pod 应用运行状态、故障排查和性能分析。但由于 Pod 是动态创建和销毁的&#xff0c;其日志分散且存储不持久&#xff0c;因此需要通过集中式日志采集方案&#xff0c;将日志收集到统一的平台并配置日志可视化分析和监控告警…

HTML5教程(中)

HTML5 浏览器支持 HTML5 浏览器支持 目前市面上的浏览器有很多版本&#xff0c;你可以让一些较早的浏览器&#xff08;不支持HTML5&#xff09;支持 HTML5。 HTML5 浏览器支持 现代的浏览器都支持 HTML5。 此外&#xff0c;所有浏览器&#xff0c;包括旧的和最新的&#xff…

OpenCV实现彩色图像的直方图均衡化

1、直方图均衡化 在OpenCV中&#xff0c;equalizeHist函数用于直方图均衡化&#xff08;Histogram Equalization&#xff09;。这是一种图像处理技术&#xff0c;旨在增强图像的对比度&#xff0c;特别是在图像的灰度值集中于某个范围时非常有用。通过调整图像的灰度分布&…

速通nvm安装配置全程无废话

速通nvm安装配置全程无废话 1、安装包 通过网盘分享的文件&#xff1a;nvm-setup-1.1.11.zip等2个文件 链接: https://pan.baidu.com/s/1nk7pAFhhnHXDIIYRJLFqNw 提取码: niw8 --来自百度网盘超级会员v3的分享2、下载安装 nvm安装路径&#xff1a;D:\dev\nvm nodejs路径&am…

JUC Java并发编程 高级 学习大纲 动员

目录 口诀 锁 阿里巴巴开发规范 字节面试题 面试题 1 面试题 2 鼓舞 口诀 高内聚低耦合前提下 封装思想 线程 -- 操作 -- 资源类 判断、干活、通知防止虚假唤醒 &#xff0c;wait 方法要注意注意标志位 flag 可能是 volatile 的 锁 阿里巴巴开发规范 参考书 并发编程…

Unity 3D游戏开发从入门进阶到高级

本文精心整理了Unity3D游戏开发相关的学习资料&#xff0c;涵盖入门、进阶、性能优化、面试和书籍等多个维度&#xff0c;旨在为Unity开发者提供全方位、高含金量的学习指南.欢迎收藏。 学习社区 Unity3D开发者 这是一个专注于Unity引擎的开发者社区&#xff0c;汇聚了众多Un…

国内源快速在线安装qt5.15以上版本。(10min安装好)(图文教程)

参考文章&#xff1a;Qt6安装教程——国内源-CSDN博客 1、在国内源上下载qt在线安装工具 NJU Mirror 2、 将下载好的在线安装工具&#xff0c;放到C盘根目录&#xff0c; 2.1 打开windows Powershell&#xff08;WinX&#xff09;&#xff0c;下边那个最好。 输入两条指令&a…

[0405].第05节:搭建Redis主从架构

Redis学习大纲 一、3主3从的集群配置&#xff1a; 1.1.集群规划 1.分片集群需要的节点数量较多&#xff0c;这里我们搭建一个最小的分片集群&#xff0c;包含3个master节点&#xff0c;每个master包含一个slave节点&#xff0c;结构如下&#xff1a; 2.每组是一主一从&#x…

数据结构(Java版)第八期:LinkedList与链表(三)

专栏&#xff1a;数据结构(Java版) 个人主页&#xff1a;手握风云 目录 一、链表中的经典面试题 1.1. 链表分割 1.2. 链表的回文结构 1.3. 相交链表 1.4. 环形链表 一、链表中的经典面试题 1.1. 链表分割 题目中要求不能改变原来的数据顺序&#xff0c;也就是如上图所示。…

flutter R库对图片资源进行自动管理

项目中对资源的使用是开发过程中再常见不过的一环。 一般我们在将资源导入到项目中后&#xff0c;会通过资源名称来访问。 但在很多情况下由于我们疏忽输入错了资源名称&#xff0c;从而导致资源无法访问。 所以&#xff0c;急需解决两个问题&#xff1a; 资源编译期可检查可方…

doc、pdf转markdown

国外的一个网站可以&#xff1a; Convert A File Word, PDF, JPG Online 这个网站免费的&#xff0c;算是非常厚道了&#xff0c;但是大文件上传多了之后会扛不住 国内的一个网站也不错&#xff1a; TextIn-AI智能文档处理-图像处理技术-大模型加速器-在线免费体验 https://…

计算机网络 (41)文件传送协议

前言 一、文件传送协议&#xff08;FTP&#xff09; 概述&#xff1a; FTP&#xff08;File Transfer Protocol&#xff09;是互联网上使用得最广泛的文件传送协议。FTP提供交互式的访问&#xff0c;允许客户指明文件的类型与格式&#xff08;如指明是否使用ASCII码&#xff0…

软件测试 —— 自动化测试(Selenium)

软件测试 —— 自动化测试&#xff08;Selenium&#xff09; 什么是SeleniumPython安装Selenium1.安装webdirver-manager2.安装Selenium 写一个简单用例CSS_SELECTOR和XPATH浏览器快速定位页面元素浏览器的前进&#xff08;forward&#xff09;&#xff0c;后退&#xff08;bac…