写在前面
继上篇博文里介绍的C语言常见基础算法,本篇在于算法的思路的整理和常见的算法编程实现。
递归的含义和常见应用
【定義】递归具体用法其实就是让你把一个问题分解成很多个类似的情况,虽然你要解决这个问题非常难,莫名其妙,要你想几年,但是把他一直递归分解,就变成很好理解的单种情况,而你整个问题又是跟这个单种情况类似,把整个问题通过递归调用一层一层分解到最低级简单的那种情况,就是你所需要理解的了。
一个函数在它的函数体内调用它自身称为递归调用。这种函数称为递归函数。C语言允许函数的递归调用。在递归调用中,主调函数又是被调函数。执行递归函数将反复调用其自身,每调用一次就进入新的一层。
常见的用法:1、斐波那契数列
// 计算fibonaci数列---2
int fibonaci_2(int n)
{
if(n<=2)
{
return 1;
}
else
{
return fibonacci_2(n-1)+fibonacci_2(n-2);
}
}
0 1 1 2 3 5 8....
或者定义一个公有的temp,返回该值。边界条件可以是n=0\n=1
2、阶乘
n!=1 (n=0,1)
n!=n*(n-1)! (n>1)
(n-1)!=(n-1)*(n-2)!
具体如下
long ff(int n)
{
long f;
if(n<0) printf("n<0,input error");
else if(n==0||n==1) f=1;
else f=ff(n-1)*n;
return(f);
}
经过n次入栈后,剩下n=1的已知值,后续全部相乘,直接得到答案,返回结果,出栈一次
3、倒序输出字符串、数字转字符等
void alpha_exchange_2(void)
{
char temp;
scanf("%c",&temp);
if(temp != '\n') // 给出正确的退出条件
{
alpha_exchange_2();
printf("%c",temp);
}
}
void alpha_exchange_3(void)
{
char temp;
scanf("%c",&temp);//temp的值必须要先由输入获得
if(temp == '\n') // 给出正确的退出条件
{
// printf("%c\n",temp);
return temp;
}
alpha_exchange_3();
printf("%c",temp);
}
void binary_to_ascii(unsigned int value)
{
unsigned int quotient;
quotient = value / 10;
//將數據按照高位到地位逐漸變小
if(quotient != 0)
binary_to_ascii(quotient);
//按照順序輸出每一位值
putchar(value%10+'0');
}
该函数出栈了n次,将每一次传入参数出栈计算,都是结果的一部分
4、翻转链表,翻转队列
struct ListNode* reverseList(struct ListNode* head){
if (head == NULL || head->next == NULL)
return head;
else
{
struct ListNode *newhead = reverseList(head->next);
head->next->next = head;
head->next = NULL;
return newhead;
}
}
//递归实现
struct node * reverse(struct node *pHead)
{
if (pHead == NULL || pHead -> pNext == NULL)
{
return pHead;
}
struct node *p = pHead -> pNext;
struct node *pNewHead = reverse(p);
p -> pNext = pHead;
pHead ->pNext = NULL;
return pNewHead;
}
【优化方法介绍(尾递归)】
从我给出的第一算法可以看出,先进栈再出栈,递归的效率是很低的。速度上完全比不上迭代(循环)。但是尾递归引入了一个新的函数参数,用这个新的函数参数来记录中间值。普通递归阶乘fac(x),就1个x而已,尾递归用2个参数fac(x,y),y存放阶乘值。
int fac(int x, int y) {
if (x == 1)
return y;
else return fac(x-1, y*x);
}
int ff(int x)
{
if (x == 0)
return 1;
else return fac(x,1);
}
int fac(int x, int y)
{
if(x == 0)
return 1;
if(x == 1)
{
return y;
}
else
{
return fac(x, x*y);
}
}
对于这个程序我们先看函数ff,函数ff其实是对fac的一个封装函数,
纯粹是为了输入方便设计的,通过调用ff(x)来调用fac(x,1),
这里常数1就是当x=1的时候阶乘值了,我通过走一遍当x=3时的值即为3!来说明一下。首先ff(3),x!=0,执行fac(3,1).第一次调用fac,x=3,y=1,x!=1,调用fac(x-1,yx),新的x=2,y=3*1=3,这里可以看到,y已经累计了一次阶乘值了,你会发现这个递归更类似于迭代了。事实上我们用了y记录了普通递归时候,出栈的乘积,所以减少了出栈后的步骤。
【推荐文章】
本博文详细介绍了递归的入栈和出栈的过程,需要特别强调的是递归的结束条件以及选用递归的传入参数。
在调用函数之后的代码是在函数返回后执行的,因此会层次的调用出栈的变量。