递归算法就是通过解决同一问题的一个或多个更小的实例来最终解决一个大问题的算法.为了在C语言中实现递归算法,常常使用递归函数,也就是说能调用自身的函数.C语言中的递归函数相当于数学函数的递归定义.我们研究递归就从考察直接求值数学函数的程序开始,并从它的基本机制扩展到一种通用的程序设计范型. 递归关系是递归定义的函数.一个递归关系定义一个函数,该函数的定义域是非负整数,可以赋初始值或以更小整数的递归方式实现.
阶乘函数(递归实现)
int factorial(int n)
{
//1的阶乘和0的阶乘均为1,当n>=1时,阶乘计算到n==1即可,这是递归停止的条件
if(n == 1 || n == 10)
return 1;
//递归下去,继续调用自身
return n*factorial(n-1);
}
欧几里得算法,以下用于找出两个整数的最大公因子.它是基于这样一种观察:两个整数x和y且x>y的最大公因子等同于y与x与xmody(x除以y的余数)的最大公因子.数t整除x 和y 当且仅当t整除y 和x mod y,因为x 等同于x mod y加上一个y的倍数. 令r = x % y, 即x = ky + r, r = x - ky,令t 为x 和y 的公因子,则t 均能整除x 和y ,所以t 也能整除r (即x % y)
//默认m >= n
int gcd(int m, int n)
{
//递归函数的出口,当n整除m的时候
if(n == 0)
return m;
//继续调用递归程序,保持传入参数时m >= n
return gcd(n, m%n);
}
前缀表达式求值的递归程序
为了对前缀表达式求值我们将一个数字的ACSII码转换为二进制值(在最后的while循环中),或者对两个操作数执行表达式中第一个字符指示的操作,并递归求表达式的值.这个函数是递归的,但它使用包含该表达式以及指向表达式的当前字符的索引的全局数组.该指针经过每一个求值的子表达式向前移动.
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <malloc.h>
using namespace std;
#define OK 1
#define ERROR -1
#define TRUE 1
#define FALSE 0
typedef int Status;
char *a;
int i;
int eval()
{
//计算表达式中的数
int x = 0;
//如果读到的是空格,跳过去
while(a[i] == ' ')
{
i++;
}
//读到加号,两个表达式相加
if(a[i] == '+')
{
i++;
return eval() + eval();
}
//读到乘号,两部分相乘
if(a[i] == '*')
{
i++;
return eval() * eval();
}
//计算数字
while((a[i] >= '0') && (a[i] <= '9'))
{
x = 10*x+(a[i]-'0');
i++;
}
//将数字返回
return x;
}
int main(int argc, char *argv[])
{
//这是举的一个例子
a = "* + 7 * * 4 6 + 8 9 5";
printf("%d\n", eval());
return 0;
}
链表递归函数示例
这些用于简单链表处理任务的递归函数容易表达,但可能不能用于大型链表,这是因为递归的深度可能与链表的长度成正比
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <malloc.h>
using namespace std;
#define OK 1
#define ERROR -1
#define TRUE 1
#define FALSE 0
typedef int Status;
typedef struct node *link;
struct node{
int data;//数据域
link next;//指针域
};
//计算链表中节点的个数
int Count(link x)
{
//递归终止条件
if(x == NULL)
return 0;
//递归向节点的下一个点,计算的个数加1
return 1 + Count(x->next);
}
//遍历该节点
int vi(link x)
{
//如果节点不为空,输出该节点的数据并返回TRUE
if(x)
{
printf("%d ", x->data);
return TRUE;
}
//否则返回FALSE
return FALSE;
}
//对链表的每个节点从头到尾调用visit
void Traverse(link h, int (*visit)(link))
{
if(h == NULL)
return;
(*visit)(h);
Traverse(h->next, visit);
}
//对链表的每个函数调用visit,但以相反的顺序进行
void Traverse_r(link h, int (*visit)(link))
{
if(h == NULL)
return;
Traverse_r(h->next, visit);
(*visit)(h);
}
//从链表中删除给定数据项的节点,使链表结构发生变化.它返回一个
//指向结果链表(可能已经改变)的指针,即返回的链接是x;
//在x->data=v时,所返回的链接是x->next(此时递归终止).
link Delete(link x, int v)
{
if(x == NULL)
return NULL;
//找到了要删除的节点,递归终止的条件
if(x->data == v)
{
link t = x->next;
free(x);
return t;
}
//继续递归
x->next = Delete(x->next, v);
return x;
}
int main()
{
//举例说明
link h = NULL;
link head;
int i;
for(i = 0; i <= 4; i++)
{
link p = (link)malloc(sizeof(struct node));
p->data = i;
if(h == NULL)
{
h = (link)malloc(sizeof(struct node));
head = p;
}
else//尾插,正序输出
{
h->next = p;
}
p->next = NULL;
h = p;
}
//举例结束
//下面是验证
Traverse(head, vi);
printf("\n");
Traverse_r(head, vi);
printf("\n");
printf("%d\n", Count(head));
head = Delete(head, 3);
Traverse(head, vi);
printf("\n");
printf("%d\n", Count(head));
return 0;
}