【C语言】常见递归题,看完递归不再怕

这篇具有很好参考价值的文章主要介绍了【C语言】常见递归题,看完递归不再怕。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文主要归纳了一些常见的递归题,若有不对,望请斧正

什么是递归

程序调用自身的编程技巧称为递归( recursion)。

递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接 调用自身的 。一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。 递归策略 :只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。 递归的主要思考方式在于:把大事化小

简单来说递归就是函数自己调用自己,为了便于理解我们看一下最简单的递归

int main()
{
    printf("hehe");
    main();
    return 0;
}

ok,按理来说,我们这个屏幕上会一直死循环打印hehe,但当我们实现代码的时候,我们会发现屏幕上打印一会后,就弹出报错,如下图

递归算法经典题目c语言,c语言,数据结构,动态规划,开发语言,算法,Powered by 金山文档

此报错中主要是Stack overflow(栈溢出的问题),俗话说得好,从错误中发现问题。这是因为我们的每一次函数调用都是在栈区上开辟空间,一直死循环地申请空间,导致栈区被耗干

所以我们得出:在函数的递归中,必须要有我们的限制条件。

递归的二个必要条件:
1.存在限制条件,当满足这个限制条件的时候,递归便不再继续。 2.每次递归调用之后越来越接近这个限制条件

ok,当我们简单了解了什么是递归的时候,接下来就是我们的一些递归题目

按照顺序打印数的每一位。


#include <stdio.h>

void print(int n)
{
     if (n > 9)        //终止条件
     {
         print(n/10);        
     }
    else
     printf("%d ", n % 10);
}

int main()
{
     int num = 1234;
     print(num);
     return 0;
}

解题思路:题目要我们打印一个数的每一位,如1234,这简单,我们给1234%10不就得到4了么,下一步就是要得到我们的3,我们可以得到4后将1234/10得到123,再给123%10.......大体思路我们了解了,递归就是2大关键:算法与终止条件。现在我们算法解决了,我们再来思考终止条件:当我们把1234变成了1的时候,我们还需要将1/10么?答案是不需要的,所以你的终止条件就是n>9

求字符串的长度

方法一(递归)

int whatlength(char* p)
{
    if (*p != '\0')
        return 1 + whatlength(p + 1);  //这里不能是*p+1,因为如果你p是地址,*p是解引用传过去不是你的地址了
    else
        return 0;    
}

int main()
{
    char arr[] = "abcdef";
    int ret=whatlength(arr);
    printf("%d", ret);
    return 0;
}

方法二(计数)

int whatlength(char* p)
{
    int count = 0;
    while (*p != '\0')
    {
        count++;
        p++;
    }
    return count;
}

int main()
{
    char arr[] = "abcdef";
    int ret=whatlength(arr);
    printf("%d", ret);
    return 0;
}

解题思路:这里我们主要将我们的递归,我们是传过去一个数组名,是首元素的地址,已知我们的字符串数组是个连续的空间,而且末尾存的是\0。利用这些便可实现我们的递归。

为什么不将p+1改成*p+1:*p+1是解引用操作符,改的是你首元素里存的值
为什么不将p+1改成p++:后置++是先使用后++,你传下一个的还是p本身,导致死循环
为什么不将p+1改成++p:前置++可以达到题目要求,但会改变本次函数里形参的值,不好观察

求n的阶乘。(不考虑溢出)


int factoria(int n)
{
    if (n > 1)
    {
        return n * factoria(n - 1);
    }
    else
    {
        return 1;
    }
}

解题思路:我们随便来一个数n=10。我们再建立一个求n阶乘的函数factoria()。当我们n=10进去的时候。是不是要先算我们的10*后面的一大堆,即10*factoria(10-1).这就是我们的算法。

求第n个斐波那契数。(不考虑溢出)

什么是斐波那契数列

int fib(int n)
{
    if (n <= 2)
    {
        return 1;
    }
    else
    {
        return GetNum(n - 1) + GetNum(n - 2);
    }
}

这题只要知道了斐波那契数是怎么取得的就就行

值得注意的是:在使用 fib 这个函数的时候如果我们要计算第50个斐波那契数字的时候特别耗费时间。 使用 factorial 函数求10000的阶乘(不考虑结果的正确性),程序会崩溃。 (上面2个函数)。这是因为我们每次求下一次数的时候,会发生很多的重复运算,导致栈溢出

系统分配给程序的栈空间是有限的,但是如果出现了死循环,或者(死递归),这样有可能导致一 直开辟栈空间,最终产生栈空间耗尽的情况,这样的现象我们称为栈溢出。
如何解决上面问题
1. 将递归改写成非递归。 2. 使用static对象替代 nonstatic 局部对象。在递归函数设计中,可以使用 static 对象替代 nonstatic 局部对象(即栈对象),这不仅可以减少每次递归调用和返回时产生和释放 nonstatic 对象的开销,而且 static 对象还可以保 存递归调用的中间状态,并且可为 各个调用层所访问

实现n的k次方,使用递归实现。

double Pow(int n, int k)
{
    if (k > 0)
    {
        return n * Pow(n, k - 1);
    }
    else if (0 == k)
    {
        return 1.0;
    }
    else
    {
        return 1.0 / Pow(n, -k);
    }
}

解题思路:重点在于我们的k次方上,当我们的k--到0的时候递归结束。而当我们的k为负数的时候,其实就是原来的正数被1.0除

计算一个数的每位之和(递归实现)

int GetNum(int n)
{
    if (n > 9)
    {
        return GetNum(n / 10) + n % 10;
    }
    else
    {
        return n;
    }
}

你在看了前面的时候你会发现这题就是打印数的每一位的变种

字符串逆序(递归实现)

int get_strlen(char* p)
{
    int count = 0;
    while (*p != '\0')
    {
        count++;
        p++;
    }
    return count;
}

void reverse_string(char* p)
{    
    int sz = get_strlen(p);
    char temp = *p;            //1    
    *p = *(p + sz - 1);        //2
    *(p + sz - 1) = '\0';      //3
    if (get_strlen(p + 1) >= 2)
    {
        reverse_string(p + 1); //4
    }
    *(p + sz - 1) = temp;      //5
}

值得注意的是,函数先声明再定义。如果你的get_strlen在reverse_string后面,编译器会给出c28278的警告。切记函数先声明再定义(使用),编译器扫描函数顺序是从上往下的。

解题思路:实现字符串的逆序其实不用递归很简单,无非就是左右2个指针依次靠近来写。在写递归的时候我们应该先从非递归怎么写找灵感,也是最2端的字符交换

递归算法经典题目c语言,c语言,数据结构,动态规划,开发语言,算法,Powered by 金山文档

如图,我们先把a取出来放到局部变量temp里,再把g放到我们a的位置上。而我们要实现递归的话,我们就不能把a从temp放到g上去,倘若如此你下一次递归的时候,就要再去算bcdefa了,因为你递归是靠判断后面字符的长度来的,你的末尾始终不会变,为了解决这问题,我们可以先把g的位置放上\0

递归算法经典题目c语言,c语言,数据结构,动态规划,开发语言,算法,Powered by 金山文档

前3步,就相当固定了2端的位置。第4步就是交换其他的。而交换的终止条件就是你的字符串长度>=2(只剩下1个不用交换)。第5步就是把temp的值放到该放的位置上

更多题目练习

这些都是我们的最基础的递归题目,下面这些题目其实都是我们基础题目的变种,感兴趣用递归可以做一做

变种水仙花

小乐乐走台阶文章来源地址https://www.toymoban.com/news/detail-742346.html

到了这里,关于【C语言】常见递归题,看完递归不再怕的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构(C语言):递归算法删除链表中所有值为x的结点

           这个标题为什么要叫“一个递归算法的诞生过程”呢?因为我在写这个算法的时候可谓一波三折,冲破重重Bug最终才得到了正确的算法。        所以在这里我和大家分享一下我写这段代码的整个过程。其中提到的一些问题大家可能写代码的时候也会遇到,所以建议

    2024年02月04日
    浏览(42)
  • 【数据结构】二叉树经典题目

    相信大部分人看了题目描述之后,都会和我一样一脸的懵逼。直到我看到了一个描述才恍然大悟 分为3种情况: 左右都为空 --省略 右为空,左不为空 – 省略 左为空,右不为空–不省略 这里复习一下二叉树的前序遍历、中序遍历、和后序遍历 前序的结果是:ABDEGCF 中序的结

    2024年02月10日
    浏览(53)
  • 【数据结构和算法初阶(C语言)】复杂链表(随机指针,随机链表的复制)题目详解+链表顺序表结尾

    目录  1.随机链表的复制 1.2题目描述  1.3题目分析 1.4解题: 2.顺序表和链表对比 2.1cpu高速缓存利用率 3.结语 一个长度为  n  的链表,每个节点包含一个额外增加的随机指针  random   该指针可以指向链表中的任何节点或空节点。        构造这个链表的  深拷贝 。 深拷贝

    2024年03月10日
    浏览(83)
  • 【数据结构经典题目】—两个队列实现栈与两个栈实现队列

    ​                                           食用指南:本文在有C基础的情况下食用更佳                                            🔥 这就不得不推荐此专栏了: C语言                                         🍀

    2024年02月13日
    浏览(44)
  • 【C语言】经典题目(二)

    C站的小伙伴们,大家好呀^^! 这一篇文章是C语言之经典题目,快来跟我一起进入C语言的世界吧!💞 C语言其他刷题篇在这里哦: 【C】语言经典题目(一) 【C语言】字符串—刷题篇 给出三角形的边长,求三角形的面积。 利用海伦公式求三角形面积 area=根号下 s*(s-a)*(s-b

    2024年02月07日
    浏览(42)
  • C语言经典面试题目(十八)

    1、如何在C语言中实现堆排序算法? 堆排序是一种利用堆数据结构进行排序的算法。它的基本思想是首先将待排序的数组构建成一个最大堆(或最小堆),然后逐步将堆顶元素与堆中最后一个元素交换,并重新调整堆,使得剩余元素继续满足堆的性质,最终得到有序序列。

    2024年03月18日
    浏览(52)
  • 二叉树经典算法题目

    省略 输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。 例如: 给定二叉树 [3,9,20,null,null,15,7] , 返回它的最大深度 3 。 思路:递归,当前数的深度等于左子数和右子树其中最大深

    2024年02月09日
    浏览(55)
  • 【数据结构】二叉树常见题目

    此乃本人自用版本,用于复习回顾! 所以部分题目不会有过大详细的解析,不懂的可以评论!笔者将竭力为你解答 满⼆叉树:如果⼀棵⼆叉树只有度为0的结点和度为2的结点,并且度为0的结点在同⼀层上,则这棵⼆叉树为满⼆叉树 高度为h的满二叉树,共有 2^h -1 个节点 完全

    2024年02月13日
    浏览(38)
  • 【数据结构】栈和队列常见题目

    队列:先进先出 栈:后进先出 队列:先进先出 栈:后进先出 https://leetcode.cn/problems/valid-parentheses/ 做法:遍历字符串 1.当前字符是左括号:进栈 2.当前字符是右括号:出栈顶元素和当前字符比较是否匹配 特殊情况:如果此时栈为空,那么说明不匹配 3.最后如果栈为空,说明

    2024年02月12日
    浏览(37)
  • 经典递归算法——汉诺塔问题

             相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘(如图1)。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动

    2024年02月06日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包