C语言 递归算法练习(阶乘,斐波那契,字符串逆序)

C语言递归算法练习


   递归是一种算法设计中常用的一种方法,其实就是一个过程或者函数直接或间接调用自己的一种方法。

函数调用在栈上开辟空间(形成栈帧),函数 return 时栈帧释放。

递归有两个必要条件
(1):存在限制条件,即递归出口;当越来越满足这个条件时,递归便不再继续。
(2):每次递归调用之后越来越接近限制条件。 即子问题规模缩小

 C 语言的函数可以调用函数也可以被调用,所以C语言支持递归,即一个函数可以调用其自身。但在使用递归时,也要注意递归出口和递归规模,否则会进入死循环。 (与C语言内存有关详见链接: link-C语言内存.)

练习代码

N的阶乘

源代码

#include<stdio.h>
#include<Windows.h>
#pragma warning(disable:4996)

//递归方法
int Factorial(int n)
{
	if (n<=1){
		return 1;
	}
	else {
		return n*Factorial(n - 1);
	}
}

//迭代方法
//int Factorial(int n)
//{
//	int i,s=1;
//	for (i = n; i >1; i--)
//	{
//		s *= i;
//	}
//	return s;
//}
int main()
{
	int num;
	scanf("%d", &num);
	printf("%d! = %d\n", num, Factorial(num));
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述

斐波那契数

 斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……(我们这里不考虑0的情况直接计算从1开始的斐波那契数)

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <windows.h>
//   //迭代方法
//int Fib(int n)
//{
//	int num1 = 1, num2 = 1;
//	int fib;
//	while (n>2){
//		n--;
//		fib = num1 + num2;
//		num1 = num2;
//		num2 = fib;
//	}
//}

//  //递归方法
int Fib(int n)
{
	if (n <= 2){
		return 1;
	}
	else{
		return Fib(n - 1) + Fib(n - 2);
	}
}

int main()
{
	int number;
	printf("你想知道第几个斐波那契数。\n");
	scanf("%d", &number);
	printf("%d\n", Fib(number));
	system("pause");
	return 0;
}

在这里插入图片描述
这里推荐使用优化的递归(后期补上代码)或者使用迭代时间按复杂度为O(n)。

有问题!!!

●用斐波那契数函数求第50个时,Fib(50)会耗费非常多的时间。
●用阶乘函数求10000的阶乘时,程序会出现崩溃。(stack overflow栈溢出)

原因:在进行递归调用时许多数据会重复计算,导致大量冗余;在使用递归时如果需要多次调用函数,那样就会引起效率低下,空间复杂度时间复杂度大大提高,甚至出现栈溢出。
例如:调试 factorial 函数时,如果你的参数过大,那就会报错:`stack overflow(栈溢 出)这样的信息。 系统分配给程序的栈空间是有限的,但是如果出现了死循环,或者(死递归),这样有可能导致一直开辟栈空间,最终产生栈空间耗尽的情况,这样的现象我们称为栈溢出。(栈相关知识详见浅谈C语言内存(栈)
所以在进行coding的时候一定要考虑清楚

解决方法

  1. 将递归改成迭代,使用循环降低时间和空间复杂度。
  2. 使用 static对象代替 nonstatic(非静态)局部变量。这可以减少每次递归调用和返回时产生和释放nonstatic变量的成本, 而且static对象还可以保存递归调用的中间状态,并且可为各个调用层所访问。


打印每位数字

接受一个无符号整数并用递归的方式打印每一位。

//接受一个无符号整数并打印每一位。
#include<stdio.h>
#include<windows.h>
#pragma warning(disable:4996)     //vs(vs2013)使用scanf时需要加 _s 否则会报错,用这种是解决方法之一

int Print(int num)
{
	if (num > 9){
		Print(num / 10);           
	}
	printf(" %d ", num % 10);
}

int main()
{
	int n;
	printf("请输入一个整数\n");
	scanf("%d", &n);
	printf("%d的每一位是:", n);
	Print(n);
	printf("\n");
	system("pause");       //vs运行会直接结束运行窗口自动关闭,可以用<window.h>中的syetem函数使运行窗口保留。 
	return 0;
}

在这里插入图片描述

strlen模拟(测量字符串长度)

strlen是一种操作函数,用来获取字符串有效长度(不包括字符串结尾的’\0’)。包含在<string.h>头文件内,具体如下(可以到 C语言.查询)
在这里插入图片描述
示例:
在这里插入图片描述

#include<stdio.h>
#include<Windows.h>
#pragma warning(disable:4996)

//   //非递归实现
//int Strlen(char *str)
//{
//	int len = 0;
//	while (*str){
//		str ++;
//		len++;
//	}
//	return len;
//}
    //递归实现
int Strlen(char *str)
{
	if (*str == '\0'){
		return 0;
	}
	else {
		return 1+Strlen(str+1);
	}
}

int main()
{
	char s[100];
	scanf("%s",&s);
	int len = Strlen(s);
	printf("len = %d\n",len);
	system("pause");
	return 0;
}

在这里插入图片描述

N的K次方

#include<stdio.h>
#include<windows.h>
#pragma warning(disable :4996)

int Square(int n,int k)
{
	if (k<=1){
		return n;
	}
	else{
		return n*Square(n,k - 1);
	}
}
int main()
{
	int num,k;
	scanf("%d %d", &num,&k);
	printf("%d的%d次方是%d\n",num,k, Square(num,k));
	system("pause");
	return 0;
}

在这里插入图片描述

字符串逆序

利用递归方法对输入字符串进行逆序并输出

//递归
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<windows.h>

void swap(char *p, char *q)
{
	*p ^= *q;
	*q ^= *p;
	*p ^= *q;
}

void ReverseStringHelper(char string[], int start, int end)
{
	if (start >= end){
		return;
	}
	else{
		swap(&string[start++], &string[end--]);
		ReverseStringHelper(string, start, end);
	}
}

void ReverseString(char str[]) //NULL ""
{
	if (NULL == str || strcmp(str, "") == 0){
		return;
	}
	ReverseStringHelper(str, 0, strlen(str) - 1);
}

int main()
{
	char str[10] = "0";
	scanf("%s", str);
	//printf("%s\n", str);
	ReverseString(str);
	printf("%s\n", str);
	system("pause");
	return 0;
}

//非递归方法:

//    非递归
#include <stdio.h>
#include <string.h>

void Swap(char *p, char *q)
{
	*p = *p ^ *q;
	*q = *p ^ *q;
	*p = *p ^ *q;
}
int  main()
{
	char str[100], temp;
	gets(str);
	int sz = strlen(str);
	for (int i = 0; i < sz / 2; i++)
	{
		Swap(&str[i], &str[sz - i - 1]);
	}
	puts(str);
	return 0;
}

运行结果:
在这里插入图片描述

相关文章:算法之算法的时间复杂度
浅谈C语言内存(栈)

  • 16
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值