1. 程式人生 > >C中幾個遞迴問題

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’。