蓝桥杯 第二章-递归算法
递归在算法程序里面是很重要的一种方法,然后通过递归可以使得一个大的复杂的问题分解成许多个小的简单的子问题,使得易于理解。
1. 经典例题费波拉契数列
直接来代码吧。
#include <stdio.h>
int fib(int n);
int main()
{
int m = 0, total = 0;
printf("请输入一个数字,然后会输出相应的在该年份的费波拉契数列对应的数字:");
printf("\n");
printf("year = ");
scanf("%d",&m);
total = fib(m);
printf("第%d年是%d\n",m,total);
}
int fib(int n)
{
if(n == 1 || n == 0)
return 1;
return fib(n-1)+fib(n-2);
}
2.求最大公约数(利用辗转相除法)
利用欧几里得算法的递归形式求取两个数的最大公约数。
#include <stdio.h>
int maxnum(int m, int n);
int main()
{
int m = 0, n = 0;
int max = 0;
do
{
printf("请输入两个数m和n,然后会输出这两个数的最大公约数\n");
printf("m = ");
scanf("%d",&m);
printf("n = ");
scanf("%d",&n);
max = maxnum(m,n);
printf("%d 和 %d的最大公约数 = %d\n",m,n,max);
}
while(m!=0 && n!=0);
}
int maxnum(int m, int n)
{
if(m % n == 0)
return n;
else
return maxnum(n,m%n);
}
3.递归插入排序
将插入排序法用递归形式改写。
#include <stdio.h>
#include <iostream>
using namespace std;
void insertSort(int a[], int k);
int main()
{
int a[10]={1,2,3,4,5,6};
int k = 10;
insertSort(a,k);
for(int i = 0; i < 10; i++)
cout << a[i] << endl;
return 0;
}
void insertSort(int a[], int k)
{
cout <<"使用了此函数"<< endl;
if( k == 0)
return ;
insertSort(a, k - 1);
int x = a[k];
int index = k - 1;
while( x < a[index])
{
a[index+1] = a[index];
index--;
}
a[index] = x;
}
4.汉诺塔问题
这个还没写出来。
5.二分查找的递归形式
思路都一样只是改写成了递归形式。(注意适用条件仅仅限于有序数组)
#include <iostream>
#include <algorithm>
using namespace std;
int erfen(int a[], int low, int high, int key);
int main()
{
//利用sort排好序然后再用递归二分找出key元素所在位置
int a[10] = {0,1,2,3,4,5,8,7,6,9};
sort(a+0,a+9);
int key = 8;
int low = 0, high = 9;
int location = erfen(a,low,high,key);
cout << "第"<<location+1 <<"个元素是"<<key<< endl;
return 0;
}
//使用二分查找的递归模式
int erfen(int a[], int low, int high, int key)
{
int mid = ( low + high )/2;
if(low > high)
return -1;
if(key < a[mid])
return erfen(a, mid+1, high, key);
else if(key > a[mid])
return erfen(a, mid+1, high, key);
else
return mid;
}
6.递归希尔排序
(即变增量的插入排序法)
#include <iostream>
using namespace std;
int shellsort(int arr[]);
int arr[10] = {4,3,2,1,0,5,6,7,8,9};
int main()
{
int i = 0;
cout << "希尔排序前" << endl;
for(i = 0; i < 10; i++)
cout << arr[i] << " ";
cout << endl;
shellsort(arr);
cout << "希尔排序后" << endl;
for(i = 0; i < 10; i++)
cout << arr[i] <<" ";
return 0;
}
int shellsort(int arr[])
{
int interval = 0;
int len = 10, i = 0, j = 0;
int target = 0;
//使用增量法,间隔增量 - 1个的数字之间进行插入排序。
for(interval = len / 2; interval > 0; interval /= 2)
for(i = interval; i < len; i++)
{
target = arr[i];
j = i - interval;
while(j >-1 && target < arr[j])
{
arr[j + interval] = arr[j];
j -= interval;
}
arr[j + interval] = target;
}
}
7.小白上楼梯
此题即利用小白的最后一种走法有三种来进行递归,求出前面的分别最后剩1、2、3步的方式然后相加即可得到最终的走楼梯的方法。
需要注意的是递归的条件暗中楼梯数目为0的时候也应该递归回1而不是0
#include <stdio.h>
int f(int n);
int main()
{
int k = 1;
int n = 0;
int ans = 0;
while(k != 0)
{
scanf("%d",&k);
ans = f(k);
printf("%d\n",ans);
}
}
int f(int n)
{
if(n == 0)
return 1;
else if(n == 1)
return 1;
else if(n == 2)
return 2;
return f(n - 1)+f(n - 2)+f(n-3);
}
8.旋转数组问题。
即改造二分问题,利用数组一边有序,一边无序的特点每次都划掉一半的元素进行查找,当最后只剩下两个元素的时候就是本程序的终结状态。最小的数是第二个。
例如 原数组为 0 1 2 3 4 5 6 7 旋转两位数过后为 2 3 4 5 6 7 0 1(特点是在旋转开始的数字那隔断,左边有序,右边无序,利用此特点可以算出旋转的数)
再举一个例子 0 0 0 1 1 1 1 1 旋转3位过后为 1 1 1 1 1 0 0 0但是此时从旋转开始的数字开始,在它的左边数字有序,右边也有序但是从这个数字小于前面的数这个特点可以求取这个数字。
还有就是还要考虑一下无旋转情况。
#include <stdio.h>
#include <iostream>
int min(int a[]);
using namespace std;
//利用二分法求解旋转数组的最小数字
int main()
{
int a[]= {3,4,5,6,7,8,9,10,1,2};
//int a[] = {1,0,1,1,1,1,1,1};
int ans = 0;
ans = min(a);
cout << "最小数字是 " << ans << endl;
return 0;
}
int min(int a[])
{
int len = 0;
bool flag = false;
int begin = 0, end = 0;
int mid = 0;
while(a[len] != '\0')
len++;
cout << "len = " << len << endl;
end = len - 1;
//无旋转情况
if(a[begin] < a[end])
return a[begin];
while(begin + 1 < end)
{
mid = ((end + begin)>>1);
if(a[mid] == a[begin] && a[mid] == a[end])
{
flag = true;
break;
}
if(a[mid] > a[begin])
begin = mid;
else
end = mid;
}
if(flag)
{
int ans = a[0];
for(int i = 1; i < len; i++)
if(a[i] < ans)
ans = a[i];
return ans;
}
return a[end];
}
9.查找字符串
不会 hahhh
10.求数组中的最长递增子序列。
设立两个指针i指针从头开始,j指针从i开始,一旦下降就结束,i+1,j指向i。
再和原来设定的最长的序列数量比较,大则交换。
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
int i = 0, j = 0, begin = 0, end = 0;
int maxlen = 0, arrlen = 0, len = 1;
int a[] = {1,9,6,2,8,3,4,5,7,0};
arrlen = sizeof(a)/sizeof(a[0]);
//cout << sizeof(a)/sizeof(a[0]) << endl;
for(i = 0; i < arrlen - 1; i++)
{
len = 1;
for(j = i; j < arrlen - 1 -1; j++)
{
if(a[j+1] >a[j])
len++;
else
break;
}
if(len > maxlen)
{
maxlen = len;
begin = i;
end = j;
}
}
cout <<"最长递增子序列为的长度为" << maxlen
<<"分别是"<< endl;
for(i = begin; i <= end; i++)
cout << "a["<<i<<"] = "<< a[i]<<" ";
cout<<endl;
}
11.高效的次幂算法
还是不会,55555~~~