C/C++ 递归知识摘录

C语言

递归就是在定义函数的同时也使用了该函数本身,我们通过例子来体会:
Example 1: 阶乘

//阶乘
#include<stdio.h>
int factorial(unsigned int i){
	if(i<=1){
		return 1;
	}
	return i*factorial(i-1);
} 
int main(){
	printf("%d",factorial(5));
	return 0;
}

输出:

120

比较好理解吧,像是定义了一个 factorial() 函数,直接调用函数名即可
Example 2:斐波那契数列
在这里插入图片描述
依据我们的数学知识,给出前几项就可以通过递归得到任意一项了

C++

直接调用自己或通过其它函数间接调用自己的函数称为递归函数。
递归函数适合于求解递归问题,所谓递归问题:是指一类比较复杂的问题,其问题的解决又依赖于类似问题的解决,只不过后者的复杂程度或规模较原来的问题更小,而且一旦将问题的复杂程度和规模化简到足够小时,问题的解法其实非常简单。
例如,计算某个自然数 n 的阶乘的公式写为:
n!=n×(n−1)×(n−2)×…×2×1
这种阶乘的计算用如下循环结构来实现:

int factorial = 1;
for (int counter=1; counter <= n; counter ++)
{
    factorial=factorial * counter;
}

也可以从另外一个角度来看待阶乘的计算,n 的阶乘可以通过递归定义为:

n!=(n -1)!    (n>1)
n!=1            (n=1)

例如为了计算5!,要先计算出4!,要计算4!,又要先计算出3!,要计算3!,则要先计算2!,而2!又需要先计算1!。
根据定义,1!为1,有了1!就可以计算2!了,有了2!的结果就可以计算出3!的值,有了3!的值就可以算出4!的值,最后可以得到5!的结果。
从上述递归计算过程可以看到,一个复杂的问题,被一个规模更小、更简单的类似的问题替代了,经过逐步分解,最后得到了一个规模非常小、非常简单的、更容易解决的类似的问题,将该问题解决后,再逐层解决上一级问题,最后解决了较复杂的原始的问题。

递归性质

对于递归函数而言其调用过程与一般函数的调用过程完全一样,同时函数的递归调用具有下面两个性质:

  1. 函数调用时,调用程序在函数调用处暂时挂起,程序控制离开调用程序转入被调用函数执行,只有当被调用函数执行完后,才返回到调用程序的调用处继续向下执行,所以调用函数一定要在被调用函数执行完成后才能继续执行并结束。由于递归调用中调用函数和被调用函数可能是同一个函数,同一个函数的两次调用可以理解为函数的两个不同的副本;
  2. 一个函数被调用,系统会为该函数的这次执行分配存储空间,包括为该函数的形式参数和局部变量分配单元。因此,递归函数执行时,在某一时刻,计算机内可能有该递归函数的多个活动的同时存在,每个活动(即函数的每次调用执行)都有自己对应的存储空间,也就是说,函数的形式参数和局部变量,在函数的每次调用执行中都有不同的存储空间。
    使用递归函数求阶乘的程序为:
#include <iostream>
using namespace std;
int fac(int num)
{
    if (num <= 1) // 递归终止,直接给出结果
        return 1;
    else // 递归调用
        return (num * fac(num - 1));
}
int main()
{
    int i;
    cin >> i;
    cout << i << "! = " << fac(i) << endl;
    return 0;
}

例子:
输入一个正整数,然后把该整数的每一位数字从高位到低位顺序输出,每个数字占一行。
例如:输入:123,程序输出:

1
2
3

递归代码:(用到了构造函数)

#include <iostream>
#include <cstdio>
using namespace std;
void splitNum(unsigned int n)
{
    if(n>=0 && n<=9)
        cout<<n<<endl;//单独考虑一位数
    else{
        if(n/10>=1 && n/10<=9)
            cout<<n/10<<endl;//得到最高位
        else
            splitNum(n/10);
	cout<<n%10<<endl;//除最高位之外其余位数以递归过程中的“个位数”形式输出
    }
}
//调用函数:
int main()
{
    unsigned n;
    while(scanf("%d",&n)){
    	splitNum(n);
	}
    return 0;
}

测试:
在这里插入图片描述

### C++ 实现文件压缩与解压的方法 C++ 提供多种方式来实现文件的压缩与解压功能,既可以基于标准库编写自定义算法,也可以借助成熟的第三方库完成复杂任务。 #### 方法一:使用哈夫曼编码进行文件压缩与解压 哈夫曼编码是一种经典的无损数据压缩方法。它通过对高频符分配较短的二进制码,而低频符则分配较长的二进制码,从而减少整体存储空间需求[^1]。下面是一个简单的哈夫曼编码压缩和解压流程: 1. **统计符频率**:遍历输入文件中的所有符并记录其出现次数。 2. **构建哈夫曼树**:利用优先队列构造一棵最小堆形式的二叉树,其中叶子节点表示原始符及其权重。 3. **生成编码表**:从根节点出发递归访问子节点,左分支标记为`0`,右分支标记为`1`,最终得到每个符对应的唯一编码序列。 4. **编码过程**:依据生成的编码表将原文转换成由`0`和`1`组成的比特流保存至目标文件中。 5. **解码恢复**:加载已有的哈夫曼树结构以及待处理的数据流逐位匹配直至找到对应叶结点即还原出原符串。 以下是简化版伪代码展示如何手动实现这一机制的部分片段: ```cpp #include <iostream> #include <queue> #include <unordered_map> struct HuffmanNode { char ch; int freq; HuffmanNode* left; HuffmanNode* right; bool operator<(const HuffmanNode& other) const { return this->freq > other.freq; // 小顶堆比较函数 } }; // 构建哈夫曼树... std::priority_queue<HuffmanNode> buildHuffmanTree(std::unordered_map<char, int>& frequencyMap); void encodeFile(const std::string& inputFilename, const std::string& outputFilename); void decodeFile(const std::string& compressedFilename, const std::string& decompressedFilename); ``` 这种方法虽然教育意义重大,但在实际应用场合下可能效率较低且不够灵活,因此推荐考虑引入专门设计用于高效操作的外部工具包。 --- #### 方法二:采用 `bundle` 库快速集成压缩能力 对于希望迅速获得可靠解决方案而不愿深入研究底层原理的应用开发者来说,选用经过验证过的开源组件无疑是最优策略之一。例如,在给定材料里提到过的一个名为 "Bundle" 的轻量级头文件式解决办法就非常适合此类场景[^2]。只需包含相应声明即可调用核心API执行基本动作——比如上面例子所示那样短短几行就能搞定整个工作链条! 具体而言,这里的关键之处在于正确设置好源端口位置参数(`ifilename`)指向欲打开的目标档案实体;同时也要指定清楚目的地址变量(`ofilename`)用来指示输出结果应该放置何方。另外值得注意的是,为了保证跨平台兼容性和稳定性,务必确认所选编译环境满足最低版本号要求(C++11+)并且已经成功安装关联依赖项。 下面是完整示范程序清单的一部分摘录: ```cpp #include <iostream> #include <fstream> #include <string> #include "bundle.h" void unzip(const std::string& ifilename, const std::string& ofilename){ /* ... */ } int main(int argc, char* argv[]){ /* ... */ unzip(argv[1], argv[2]); return 0; } ``` 此方案特别适合那些追求简洁易懂又不失强大性能表现的小型项目或者原型开发阶段测试用途。 --- #### 方法三:依托 Qt 框架下的 JlCompress 工具类封装高级特性 如果当前工程本身已经是围绕着 Qt 技术栈展开的话,则可以直接利用内置资源管理模块所提供的便利接口轻松达成预期效果[^3]。通过继承自 QObject 类别的辅助对象实例化之后便可以无缝衔接既有业务逻辑链路之中去操控 ZIP 归档文档等相关事务了。 举个栗子吧~假设我们现在想要把某个目录打包起来形成单独一份 .zip 文件存盘下来,那么只需要像这样写几句命令就行啦~ ```cpp #include <QCoreApplication> #include <QDebug> #include "JlCompress.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 执行压缩操作 JlCompress::compressDir("output/archive.zip", "/path/to/source/folder"); qDebug() << u8"Compression completed."; return 0; } ``` 同理可得当面临相反方向的任务时亦然如此简单明快哦~ 当然咯,记得提前调整好 qmake 脚本里的附加选项以确保链接器能够识别新增加进来的新成员哟~比如说添加类似这样的语句进去就好啦~ ```plaintext QT += core gui widgets network concurrent xml LIBS += -ljzlib INCLUDEPATH += /usr/include/jziplib/ DEPENDPATH += /usr/include/jziplib/ ``` 以上三种途径各有千秋,究竟挑选哪一种完全取决于个人喜好或者是特定约束条件限制等因素综合考量决定呢😊
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值