C中幾個遞迴問題
1. 計算累和 1+2+3+……+n
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int add_up(int n){
if(n==1){
return 1;
}
return n+add_up(n-1);
}
void main()
{
int n=5;
printf("%d\n",add_up(n));
return;
}
2. 計算累乘 N!
遞迴方法:
int funN(int N) { if (1>=N) { return 1; } else { return N*funN(N-1); } }
非遞迴方法:
int funN(int N)
{
int i,val = 1;
if (N<=0)
{
return 0;
}
for(i=1;i<=N;i++)
{
val*=i;
}
return val;
}
3. 素數判斷
質數又稱素數。一個大於1的自然數,除了1和它自身外,不能整除其他自然數的數叫做質數;
定義判別法:
#include<stdio.h> #include<stdlib.h> int isprime(int val) { int n = 2; for(n; n<val;n++){ if(val%n==0){ return 0; } } return 1; } int main() { for(int i = 2;i<=100;i++){ if(isprime(i)==1){ printf("%d\n",i); } } return 0; }
4. 遞迴實現十進位制數轉換成二進位制數
#include <stdio.h> #include <stdlib.h> #include <string.h> void to_binary(int num){ int bin=num%2; if(num>=2){ to_binary(num/2); } printf("%c",bin+'0'); } int main(){ int num = 10; to_binary(num); system("pause"); return 0; }
C中單個數字到字元的轉換,加‘0’。
5. 順序和逆序輸出正整數的每一位
順序輸出:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void print_num(int num){
if(num<10){
printf("%d\n",num);
}
else{
print_num(num/10);
printf("%d\n",num%10);
}
}
int main()
{
int num=1234560;
print_num(num);
system("pause");
}
逆序輸出:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void print_num(int num){
if(num<10){
printf("%d\n",num);
}
else{
printf("%d\n",num%10);
print_num(num/10);
}
}
int main()
{
int num=1234560;
print_num(num);
system("pause");
}
6. 求組成一個正整數的所有數字之和
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int sum_up(int n){
if(n/10==0){
return n;
}
return sum_up(n%10)+sum_up(n/10);
}
void main()
{
int n=123456;
printf("%d\n",sum_up(n));
return;
}
7. 遞迴實現n^k
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int pow_fun(int n, int k){
if(k==1){
return n;
}
return n*pow_fun(n,k-1);
}
void main()
{
int n=3,k=3;
printf("%d\n",pow_fun(n,k));
return;
}
8. 求兩個正整數的最大公約數
也稱最大公因子,指兩個或多個整數共有約數中最大的一個。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int Max_common_divisor(int m, int n){
if(m<=1||n<=1){
return 1;
}
if(m>n){
return Max_common_divisor(m-n,n);
}
if(m<n){
return Max_common_divisor(n-m,m);
}
if(m=n){
return n;
}
}
void main()
{
int m=64,n=76;
printf("%d\n",Max_common_divisor(m,n));
return;
}
另一種實現:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int gbs(int n,int m)
{
if(n%m){
return gbs(m,n%m);
}
else{
return m;
}
}
void main()
{
int m=8,n=12;
printf("%d\n",gbs(m,n));
return;
}
9. 求兩個正整數的最小公倍數
兩個或多個整數公有的倍數叫做它們的公倍數,其中除0以外最小的一個公倍數就叫做這幾個整數的最小公倍數。
a,b的最小公倍數 = a×b/(a,b的最大公約數)
10. 遞迴實現將字串反向輸出
void funN(char *s)
{
if (*s != NULL)
{
funN(s+1);
printf("%c",*s);
}
}
11. 統計字串中第一個空字元(或特定字元)前的字元長度
例如對於{'a','b','c','\0','d','e'},N=2、3時,長度是2、3,N=5、6時,長度是3。 思路: 字串折半遞迴。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int strlen_length(char* str,int N){
int length; //C中變數定義要放在最前
if(*str=='\0' || N==0){
return 0;
}
if(N==1)
{
return 1;
}
length = strlen_length(str,N/2);
if(length<N/2) //這種情況表示length==N,說明前半段中沒有空字元
{
return length;
}
else
{
return (length+strlen_length(str+N/2,(N+1)/2));
}
}
int main()
{
char str[] = {'a','b','\0','c'};
printf("%d",strlen_length(str,2));
system("pause");
}
12. 不建立任何臨時變數,實現strlen功能
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int strlen(char* str){
if(*str=='\0'){
return 0;
}
return(1+strlen(str+1));
}
int main()
{
char *str="1234560";
printf("%d",strlen(str));
system("pause");
}
13. 迴文判斷,如“abcdedbca”是迴文
0和單個字元也認為是迴文。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int huiwen(char *str, int length){
if(length<=1){
return 1;
}
if(*str==*(str+length-1)){
return huiwen(str+1,length-2);
}
else{
return 0;
}
}
int main(){
char str[]="aaabcde66edcbaaa";
printf("%d\n",huiwen(str,strlen(str)));
system("pause");
return 0;
}
14. 斐波那契數列
又稱黃金分割數列、因數學家列昂納多·斐波那契(Leonardoda Fibonacci)以兔子繁殖為例子而引入,故又稱為“兔子數列”。 斐波那契數列中F(n)=F(n-1)+F(n-2)(n>=3)。
遞迴實現,判斷斐波那契數列中第n位的值。
#include<stdio.h>
#include<stdlib.h>
long bofei(int val)
{
if(0>=val){
return 0;
}
if(1==val){
return 1;
}
if(2==val){
return 2;
}
return bofei(val-1)+bofei(val-2);
}
int main()
{
int ss = 10;
printf("%ld",bofei(ss));
return 0;
}
非遞迴實現,判斷斐波那契數列中第n位的值:
#include<stdio.h>
#include<stdlib.h>
long bofei(int val)
{
long arr[100];
arr[0]=0;
arr[1]=1;
arr[2]=2;
for(int i=3; i<=val;i++){
arr[i]=arr[i-1]+arr[i-2];
}
return arr[val];
}
int main()
{
int ss = 50;
printf("%ld",bofei(ss));
return 0;
}
15. 漢諾塔問題
A(from)、B(helper)、C(to)
1. n個盤從A移動到C,需要藉助B,先把n-1個盤移動到B(這個最終呈現出來的效果,至於過程怎麼實現的不管),再把第n的盤移動到C;
2. 再把B上的n-2個盤藉助A,移動到A上,把第n-1的盤移動到C; 如此反覆;
void hannoi(int n, char from, char helper, char to){
if(n>1){
hannoi(n-1,from,to,helper);
print_line("take"+n+"from"+from+"to"+to);
hannoi(n-1,helper,from,to)
}
else{
print_line("take"+n+"from"+from+"to"+to);)
}
}
16. 長度為n的、沒有重複字元的字串全排列,求全排列種類的數目。
思路:1. 先確定首位,首位有n種情況; 2. 確定首位之後,剩下的n-1位再全排列; 3. 全排列次數f(n)=n*f(n-1);
遞迴求法:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int permutation_num(int n){
static int num=1;
if(1>=n){
return 1;
}
num=n*permutation_num(n-1);
return num;
}
void main()
{
int n=6;
printf("%d\n",permutation_num(n));
return;
}
非遞迴求法:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int permutation_num(int n){
int list_[n]; //list_[0]~list_[n-1]對應1~n位字元全排列的排列數
list_[0] = 1;
for(int i=1;i<n;i++){
list_[i] = (i+1)*list_[i-1];
}
return list_[n-1];
}
void main()
{
int n=6;
printf("%d\n",permutation_num(n));
return;
}
17. 打印出一個字串所有的全排列
如abc,全排列為abc、acb、bac、bca、cab和cba。
思路: 第一步是確定第一個位置的字元,就是第一個位置與後邊的所有字元進行交換。這一共有n中情況,所以遞迴函式裡涉及一個n次迴圈。
第二步,就是對除了第一個位置的後邊所有位置的字元進行相同處理;直至剩下一個字元,列印;這裡是遞迴函式裡迴圈體。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void permutation_num(char* start, char* move){
if(*move=='\0')
{
printf("%s\n",start);
return;
}
else
{
for(char* begin=move;*begin!='\0';begin++)
{
char temp = *begin;
*begin = *move;
*move = temp;
permutation_num(start,move+1);
temp = *begin;
*begin = *move;
*move = temp;
}
}
}
void main()
{
char str[] = "abc";
permutation_num(str,str);
return;
}
以上遞迴沒有考慮去重,去重版本:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int swap_(char * begin, char* end){
for(char * start=begin; start!=end;start++){
if(*start==*end){
return 0;
}
}
return 1;
}
void permutation_num(char* start, char* move){
if(*move=='\0')
{
printf("%s\n",start);
return;
}
else
{
for(char* begin=move;*begin!='\0';begin++)
{
if(swap_(move,begin)){
char temp = *begin;
*begin = *move;
*move = temp;
permutation_num(start,move+1);
temp = *begin;
*begin = *move;
*move = temp;
}
}
}
}
void main()
{
char str[] = "acc";
permutation_num(str,str);
return;
}
18. 判斷一系列字串中是否有重複字串
C中沒有string字串指標,需要使用二級指標實現。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int repetition(char** start){
if(*(start+1)=='\0'||*(start)=='\0') //如果只有一個元素或為空
{
return 0;
}
else
{
for(char** begin=start+1;*begin!='\0';begin++) //逐個比對
{
if(*start == *begin){
return 1;
}
}
repetition(start+1);
}
}
void main()
{
char *str[]= {"aa","bb","cc","aa"};
printf("%d\n",repetition(str));
return;
}
19. 遞迴實現字元反轉
1. 原地反轉
2. 自己實現strlen功能
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int strlen_(char *str){
if(*str=='\0'){
return 0;
}
return 1+strlen_(str+1);
}
void reverse(char* p){
if(strlen_(p)<=1||*p=='\0'){
return;
}
else{
int length = strlen_(p);
char temp = *p;
*p = *(p+length-1);
*(p+length-1) = '\0';
reverse(p+1);
*(p+length-1) = temp;
}
}
void main()
{
char str[]="abcedfgd";
reverse(str);
printf("%s\n",str);
return;
}
20. 將一個正整數按字元格式輸出,實現itoa功能
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char* reverse(char* p){
char* str=(char*)malloc(10);
int length = strlen(p);
for(int i=0;i<length;i++){
str[i]=p[length-i-1];
}
str[length]='\0';
return str;
}
char* itoa(int num)
{
char* str = (char*)malloc(10);
char* p = str;
for(num;num>0;num = num/10){
*p = (num%10)+'0';
p=p+1;
}
*p='\0';
return reverse(str); //字元反轉
}
void main()
{
int num=123456;
printf("%s\n",itoa(num));
return;
}
21. 將一個正整數按“千分位”格式化形式輸出,從個位起,每三位加逗號,如1234567,變成1,234,567
相關:
1. 自己實現strlen
2. 正整數轉字串
3. 字串反轉
4. 字串插入
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int strlen_(char *str){
if(*str=='\0'){
return 0;
}
return 1+strlen_(str+1);
}
void reverse(char* p){
if(strlen_(p)<=1||*p=='\0'){
return;
}
else{
int length = strlen_(p);
char temp = *p;
*p = *(p+length-1);
*(p+length-1) = '\0';
reverse(p+1);
*(p+length-1) = temp;
}
}
char* itoa(int num)
{
char* str = (char*)malloc(10);
char* p = str;
for(num;num>0;num = num/10){
*p = (num%10)+'0';
p=p+1;
}
*p='\0';
reverse(str); //字元反轉
return str;
}
char * insert_douhao(char* str){
int length = strlen_(str);
char* p =(char*)malloc(length+abs(length-1)/3);
for(int i=0;i<length+abs(length-1)/3;i++){
if((i-length%3)%4==0){
*(p+i)=',';
}
else{
*(p+i)=*(str++);
}
}
return p;
}
char* int_to_qianfenwei(int num){
char* p = itoa(num);
printf("%s\n",p);
return insert_douhao(p);
}
void main()
{
int num = 1234567012;
printf("%s\n",int_to_qianfenwei(num));
return;
}
在遞迴裡,對於指標p,一般忌諱使用 p++, 通常使用p+1 。 p++之後指標p的值已經變了,不再指向初始地址,而p+1只是傳入指標p之後的那個地址,指標p本身並沒有改變。
NULL、'\0'、0
NULL用於指標或者物件的置空,表示一個不指向任何物件的空指標。
'\0'用於字串的結束標誌。
0也可以作為字串的結尾標誌,如下表述也是沒有問題的:
char str[4] = { '1', '2', '3', 0 }; //這裡strlen(str)的值是3
C中單個數字到字元的轉換,加‘0’。