(九十八)递归(函数与函数自己)

递归的实质,函数自己调用自己。——但C++语言不允许main函数调用自己

 

包含一个递归调用的递归:

例如代码:

#include<iostream>
using namespace std;

int m(int);	//m函数

int main()
{
	int a = 0;
	a = m(a);	//函数参数为a,并将返回值赋值给a
	cout << a << endl;
	system("pause");
	return 0;
}

int m(int a)
{
	a++;	//a+1
	if (a < 10) m(a);	//当a<10的时候,调用函数m,参数为a,注意,ma的返回值不影响if判断语句中的a<10。
	cout << "a = " << a << endl;	//输出本函数的值
	return a;
}

输出:

a = 10
a = 9
a = 8
a = 7
a = 6
a = 5
a = 4
a = 3
a = 2
a = 1
1
请按任意键继续. . .

解释:

①在m函数中(这时候是最外层的m),a++后,a=1;又因为1<10,于是执行m函数(第二层m函数),参数是a=1;

第二层m函数,参数是a=1,a++后a=2,2<10,于是执行m函数(第三层m函数),参数是a=2;

依次类推……

 

第九层m函数,参数是a=9,a++后a=10,if判断语句不通过,于是执行下一行代码,打印a=10;然后第九层函数执行完,跳回第八层函数,返回值是10(但第八层函数并没有接收这个返回值);

第八层函数的if语句执行结束(已经调用完第九层函数),此时a=9,打印a=9,跳回第七层函数;

依次类推……

 

第一层(最外层)m函数,此时a=1,返回值是a(1),于是main函数中a=1;

 

②假如没有a++这行代码,函数就会陷入无限循环之中。

 

另一代码:打印缩进图形的星:

//打印从两边缩进的星
#include<iostream>

using namespace std;
const int kuan = 20;
char zifu[kuan];
void ab(char,int);	//无返回值函数,参数为char

int main()
{
	char x = '*';
	for (int i = 0;i < kuan;i++)
		zifu[i] = ' ';
	ab(x, 20);

	system("pause");
	return 0;
}

void ab(char m,int n)
{
	zifu[kuan - n] = m;
	zifu[n - 1] = m;
	for (int i = 0;i < kuan;i++)
		cout << zifu[i];
	cout << endl;
	n--;
	if (n > kuan / 2)ab(m, n);
}

输出:

*                  *
**                **
***              ***
****            ****
*****          *****
******        ******
*******      *******
********    ********
*********  *********
********************
请按任意键继续. . .

包含多个递归调用的递归:

因为多个递归可以多次调用自己,因此需要一个变量可以控制调用的次数,并且这个变量在每次调用的时候,可以增加或者减少,以满足停止调用的条件。

 

 

如代码:

#include<iostream>

const int kuan = 66;
const int dives = 5;
void shu(char ar[], int low, int high, int level);

int main()
{
	char ruler[kuan];	//字符串宽
	int i;	//初始化i,因为在其他地方也要用i,所以在for外面初始化
	for (i = 1;i < kuan - 2;i++)
		ruler[i] = ' ';	//从第2个字符到倒数第二个字符,都是空格
	ruler[kuan - 1] = '\0';	//最后一个字符为空字符(因为是字符串)
	int max = kuan - 2;	//max是字符宽度-2(这样将指示倒数第二个字符)
	int min = 0;	//min是0,
	ruler[min] = ruler[max] = '|';	//第一个和倒数第二个字符是|,注意,最后一个是空字符
	std::cout << ruler << std::endl;	//输出字符串,这个时候第一个和倒数第二个是|,其他是空格

	for (i = 1;i <= dives;i++)
	{
		shu(ruler, min, max, i);	//调用函数,参数是字符串,min,max,
		std::cout << ruler << std::endl;	//输出字符串
		for (int j = 1;j < kuan - 2;j++)	//重置字符串为空字符,注意,没清楚字符串第一个字符和倒数第二个字符
			ruler[j] = ' ';
	}
	system("Pause");
	return 0;
}

void shu(char ar[], int low, int high, int level)
{
	if (level == 0)	//当level为0时,结束函数,level初始为for循环中的i
		return;
	int mid = (high + low) / 2;	//min是high和low的平均数,即为中间
	ar[mid] = '|';	//中间为|,
	shu(ar, low, mid, level - 1);	//执行函数,level-1,mid替代high为参数,即层次每高1级,即可在low和mid中间的位置插入一个字符|
	shu(ar, mid, high, level - 1);	//在mid和high中间插入一个字符。
}

输出:

|                                                               |
|                               |                               |
|               |               |               |               |
|       |       |       |       |       |       |       |       |
|   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
请按任意键继续. . .

解释:

①控制函数层级的是level,每次函数自己调用自己的时候,level将-1,当level=0时,函数直接返回(即这次调用结束);

 

②初始level为for循环中的i,第一次是i=0,因此函数直接返回;

当for循环进入i=1时,函数执行第一次,并且在函数自己调用自己的时候,level-1的值为0,调用后,函数直接返回;

当for循环进入i=2时,函数执行第一次,然后函数在自己调用自己的时候,level-1的值为1,因此函数执行第一次的时候,可以调用自己两次,加上函数第一次,共执行三次(即多出三个“|”);

当for循环进入i=3时,同i=2,但此时是三层函数,执行1+2+4=7次,即多出7个“|”。

依次类推。

 

③函数的特点是,定出左边的字符和最右边字符的位置,然后给中间字符赋值字符“|”。

并且以中间位置,为下一次调用函数时的最左边或者最右边位置。

 

即第一轮是1#(ar[0])和64#(ar[63])位置有字符;(调用0次函数)

第二轮时1#,64#以及他们中间的位置32#(ar[31])位置有字符;(调用1次函数)

第三轮,除了第二轮的三个,还在1#和32#、32#和64#中间有字符,即16#和48#;(调用1+2次函数)

第四轮,除了第三轮的5个,还分别在1和16,16和32,32和48,48和64中间有字符;(调用1+2+4次函数)

 

即每次都在上一次有字符的位置中间,有字符。

而level是用来控制轮数的。

 

方向向右的树形图,多重递归的代码:

//思路:
//创建二维字符串,即string[y][x],描述坐标上的点,然后给坐标上的点赋值(“—”或者空字符)
//用多重递归,使得图形为向右的树形图;
//赋值完毕后,打印二维字符串

#include<iostream>
#include<string>
using namespace std;

void shuxingtu(string a[][32], int x, int y);

int main()
{
	//首先是给树形图赋值,预计树形图为
	string a[32][32];
	int x ,y;
	x = y = 0;
	for (int i = 0;i < 32;i++)	//使得32x32的坐标都是空字符
		for (int j = 0;j < 32;j++)
			a[i][j] = ' ';
	y = 16;
	a[y][x] = "*";

	x = 1;
	shuxingtu(a, x, y);	//给二维string字符串赋值

	//打印字符串
	for (int i = 0;i < 32;i++)	//使得32x32的坐标都是空字符
	{
		for (int j = 0;j < 32;j++)
			cout << a[i][j];
		cout << endl;
	}

	system("pause");
	return 0;
}

void shuxingtu(string a[][32], int x, int y)	//导入二维string字符串数组,导入x,y坐标
{
	if (x == 16)return;	//当层级为0时,结束循环
	//注意,导入坐标的点,不赋值——即保持为空字符,导入坐标上下方的点赋值*
	a[y + 1][x] = "*";	//上一个y更高一个位置
	a[y - 1][x] = "*";	//上一个y更低一个位置
	shuxingtu(a, x + 1, y + 1);	//再次调用的时候,x坐标+1,y坐标+1(即是调用本函数赋值的两个点往右边一位)
	shuxingtu(a, x + 1, y - 1);	//再次调用的时候,x坐标+1,y坐标-1(注意,当前函数所赋值*的点为x,y-1与x,y+1
}

输出:

               *
              *
             * *
            * *
           * * *
          * * *
         * * * *
        * * * *
       * * * * *
      * * * * *
     * * * * * *
    * * * * * *
   * * * * * * *
  * * * * * * *
 * * * * * * * *
* * * * * * * *
 * * * * * * * *
  * * * * * * *
   * * * * * * *
    * * * * * *
     * * * * * *
      * * * * *
       * * * * *
        * * * *
         * * * *
          * * *
           * * *
            * *
             * *
              *
               *
请按任意键继续. . .

解释:

①如果看以上图标排列不整齐,可能是因为字体问题。

 

②从左边中间开始,赋值“*”,然后x坐标+1,y+1和y-1位置上的点赋值“*”。并以此类推。

时间: 2024-09-23 12:30:26

(九十八)递归(函数与函数自己)的相关文章

x264代码剖析(八):encode()函数之x264_encoder_close()函数

x264代码剖析(八):encode()函数之x264_encoder_close()函数           encode()函数是x264的主干函数,主要包括x264_encoder_open()函数.x264_encoder_headers()函数.x264_encoder_encode()函数与x264_encoder_close()函数四大部分,其中x264_encoder_encode()函数是其核心部分,具体的H.264视频编码算法均在此模块.上三篇博文主要分析了x264_enco

javascript高级编程之函数表达式 递归和闭包函数_javascript技巧

定义函数表达式有两种方式:函数声明和函数表达式. 函数声明如下: function functionName(arg0,arg1,arg2){ //函数体 } 首先是function关键字,然后是函数的名字. FF,Safrai,Chrome和Opera都给函数定义了一个非标准的name属性,通过这个属性可以访问到函数指定的名字.这个函数的值永远等于跟在function关键字后面的标识符. //只在FF,Safari,Chrome和Opera有效 alert(functionName.name)

函数声明和函数表达式——函数声明的声明提前

定义函数的方法 定义函数的方法主要有三种:     函数声明(Function Declaration)     函数表达式Function Expression)     new Function构造函数 其中,经常使用的是函数声明和函数表达式的函数定义方法,这两种方法有着很微妙的区别和联系,而且这两种方法的使用也容易混淆,所以这篇文章主要总结下这两种函数定义方法的相关知识点,当然本文的主题依然是关于函数提前的. 函数声明的典型格式: function functionName(arg1, a

浅析函数声明和函数表达式——函数声明的声明提前_基础知识

前两天班级聚会,除了吃喝玩乐就是睡觉扯淡,甚是喜悦,真是独乐乐不如众乐乐啊. PS:毕业的或即将毕业的有时间能聚就聚吧,毕了业以后属于自己的时间能聚到一块儿可就少太多了. 现在有点时间来看点东西总结些东西了,又因为前段时间片片断断地看了看JavaScript的函数部分,所以抽时间总结下函数的相关部分,当然,里面有些部分都是自己的理解,如果有理解的不对的地方还请小伙伴们不吝指出. 这一节我结合自己的理解和小伙伴们聊一下函数声明的声明提前. 注:有的地方也叫函数声明提升.翻译的不一样,意思一样,大家

谈函数指针(全局/类成员函数)和函数对象

函数指针(全局函数/类成员函数).函数对象(Function object) 一. 函数指针类型为全局函数. #include "stdafx.h"#include <iostream>using namespace std;class TestAction;typedef void (*fp)(int); void Drink(int i){ cout<<"No. "<<i<<" drink..."

wps表格函数及函数简单使用

  今天小编为大家介绍一下wps表格中常用的函数及函数简单使用方法. 一.函数应用基础 (一)函数和公式 1.什么是函数 WPS表格 函数即是预先定义,执行计算.分析等处理数据任务的特殊公式.以常用的求和函数SUM 为例,它的语法是"SUM( 数值 1, 数值 2,......)".其中"SUM"称为函数名称,一个函数只有唯一的一个名称,它决定了函数的功能和用途.函数名称后紧跟左括号,接着是用逗号分隔的称为参数的内容,最后用一个右括号表示函数结束.参数是函数中最复杂

(转载)JavaScript中匿名函数,函数直接量和闭包_javascript技巧

原文出处: http://www.dnew.cn/post/196.htm 先看下下面几种写法 1.function f(x){return x*x;};f(x); 2.(function(x){return x*x;})(x); 3.(function(x){return x*x;}(x)); 第一种我们应该都很熟悉了,这是我们经常使用的写法.第二第三种都是匿名函数的写法. ------------------------------------------------------------

PHP利用func_get_args和func_num_args函数实现函数重载实例_php技巧

本文实例讲述了PHP利用func_get_args和func_num_args函数实现函数重载的方法.分享给大家供大家参考.具体方法分析如下: 学习php的朋友都知道php本身是没有函数重载这一说的,更没说像java,c那样使用方法,但如果我们深入了解一下会发现可以在php中使用func_get_args()和func_num_args()函数实现函数重载,下面来举两个函数重载例子.这两个函数实现函数的重载. 1.默认参数,如果一个函数里面,这不是必须参数,而添加相应的默认值,就可以完成相应的功

DockOne微信分享(九十八):Insta360容器化&amp;DevOps之路

本文讲的是DockOne微信分享(九十八):Insta360容器化&DevOps之路[编者的话]作为一个全景/VR创业公司,随着公司人员增加以及全球化方向转变,刀耕火种的CI/CD方式已经不能满足当前的需求.综合考虑当前的人员状况与技术架构的拓展性后,我们采用一套以阿里云为基础,Docker为核心,第三方服务为工具的开发.测试.部署流程,以及内部的代码提交,版本管理规范. 背景 我司是一家集硬件研发与软件开发为一体的互联网创业公司.2016被称为全景/VR元年,预示了机遇到来的同时,也注定了我们

指针函数与函数指针

一. 在学习arm过程中发现这"指针函数"与"函数指针"容易搞错,所以今天,我自己想一次把它搞清楚,找了一些资料,首先它们之间的定义: 1.指针函数是指带指针的函数,即本质是一个函数.函数返回类型是某一类型的指针      类型标识符    *函数名(参数表)       int *f(x,y);   首先它是一个函数,只不过这个函数的返回值是一个地址值.函数返回值必须用同类型的指针变量来接受,也就是说,指针函数一定有函数返回值,而且,在主调函数中,函数返回值必须赋