数据结构和算法(七):栈的应用:递归、RPN、进制转换、分治思想

递归

分治思想: 折半查找算法的递归实现

汉诺塔问题

八皇后

逆波兰(Reverse Polish Notation, RPN)表示

中缀表达式转后缀表达式

二进制转为十进制

递归

1.斐波那契数列的实现

递归的思想:

/***************************************
*  数据结构和算法--小甲鱼
*  递归print
****************************************/
/*
#include <stdio.h>

//递归打印print
void print ()
{
    char inputChar;
    scanf("%c" ,&inputChar);

    if(inputChar != '#') print();
    if(inputChar != '#') printf("%c",inputChar);
}
int main()
{
    while(1){
        printf("请输入一串字符串,以\"#\" 结束:\n ");
        print();
    }
    return 0;
}

分治思想: 折半查找算法的递归实现

/***************************************
*  数据结构和算法--小甲鱼
*  分治思想 :二分查找法
****************************************/

#include <stdio.h>

int bin_search(int key[] , int low , int high , int k)
{
    int mid;
    if( low > high )
    {
        return -1;
    }
    else
    {

        mid = (low + high) / 2;

        if(key[mid] == k)
        {
            return mid;
        }
        if( k >key[mid])
        {
          return  bin_search(key, mid + 1 , high , k);
        }
        else {
          return  bin_search(key , low ,mid - 1, k);
        }
    }
}

int main()
{
    int str[11] = {1,2,3,3,4,5,5,5,5,6,7};
    int n , addr;
    printf("请输入待查找的关键字: ");
    scanf("%d", &n);

    addr = bin_search(str, 0, 10, n);
    if( -1 != addr )
    {
         printf("查找成功,可喜可贺,可口可乐! 关键字 %d 所在的位置是: %d\n", n, addr);
    }
    else
    {
         printf("查找失败!\n");
    }

    return 0;
}

汉诺塔问题:

/***************************************
*  数据结构和算法--小甲鱼
*  分治思想 :汉诺塔
****************************************/
/*
#include <stdio.h>

// 将 n 个盘子从 x 借助 y 移动到 z
void move(int n, char x, char y, char z)
{
	if( 1 == n )
	{
		printf("%c-->%c\n", x, z);
	}
	else
	{
		move(n-1, x, z, y);				// 将 n-1 个盘子从 x 借助 z 移到 y 上
		printf("%c-->%c\n", x, z);		// 将 第 n 个盘子从 x 移到 z 上
		move(n-1, y, x, z);				// 将 n-1 个盘子从 y 借助 x 移到 z 上
	}
}

int main()
{
	int n;

	printf("请输入汉诺塔的层数: ");
	scanf("%d", &n);
	printf("移动的步骤如下: \n");
	move(n, 'X', 'Y', 'Z');

	return 0;
}

八皇后: //趣学算法 有讲解 回溯法

#include <stdio.h>

int count = 0;

int notDanger( int row, int j, int (*chess)[8] )
{
	int i, k, flag1=0, flag2=0, flag3=0, flag4=0, flag5=0;

	// 判断列方向
	for( i=0; i < 8; i++ )
	{
		if( *(*(chess+i)+j) != 0 )
		{
			flag1 = 1;
			break;
		}
	}

	// 判断左上方
	for( i=row, k=j; i>=0 && k>=0; i--, k-- )
	{
		if( *(*(chess+i)+k) != 0 )
		{
			flag2 = 1;
			break;
		}
	}

	// 判断右下方
	for( i=row, k=j; i<8 && k<8; i++, k++ )
	{
		if( *(*(chess+i)+k) != 0 )
		{
			flag3 = 1;
			break;
		}
	}

	// 判断右上方
	for( i=row, k=j; i>=0 && k<8; i--, k++ )
	{
		if( *(*(chess+i)+k) != 0 )
		{
			flag4 = 1;
			break;
		}
	}

	// 判断左下方
	for( i=row, k=j; i<8 && k>=0; i++, k-- )
	{
		if( *(*(chess+i)+k) != 0 )
		{
			flag5 = 1;
			break;
		}
	}

	if( flag1 || flag2 || flag3 || flag4 || flag5 )
	{
		return 0;
	}
	else
	{
		return 1;
	}
}

// 参数row: 表示起始行
// 参数n: 表示列数
// 参数(*chess)[8]: 表示指向棋盘每一行的指针
void EightQueen( int row, int n, int (*chess)[8] )
{
	int chess2[8][8], i, j;

	for( i=0; i < 8; i++ )
	{
		for( j=0; j < 8; j++ )
		{
			chess2[i][j] = chess[i][j];
		}
	}

	if( 8 == row )
	{
		printf("第 %d 种\n", count+1);
		for( i=0; i < 8; i++ )
		{
			for( j=0; j < 8; j++ )
			{
				printf("%d ", *(*(chess2+i)+j));
			}
			printf("\n");
		}
		printf("\n");
		count++;
	}
	else
	{
		for( j=0; j < n; j++ )
		{
			if( notDanger( row, j, chess ) ) // 判断是否危险
			{
				for( i=0; i < 8; i++ )
				{
					*(*(chess2+row)+i) = 0;
				}
				
				*(*(chess2+row)+j) = 1;

				EightQueen( row+1, n, chess2 );
			}
		}
	}
}

int main()
{
	int chess[8][8], i, j;

	for( i=0; i < 8; i++ )
	{
		for( j=0; j < 8; j++ )
		{
			chess[i][j] = 0;
		}
	}

	EightQueen( 0, 8, chess );

	printf("总共有 %d 种解决方法!\n\n", count);

	return 0;
}

 

后缀表达法   ,逆波兰(Reverse Polish NotationRPN)表示。

“9+(3-1)×3+10÷2”,如果要后缀表示法应该是什么样子:“9 3 1-3*+10 2/+”这样的表达式称为后缀表达式,叫后缀的原因在于所有的符号都是在要运算数字的后面出现。

后缀表达式:9 3 1-3*+10 2/+

规则:从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果。

//自己写的

#include "DaHuaShuJuJieGou.h"
//后缀表达式的运算

int main()
{
    //从左到右遍历 ,如果是数字就进栈
    //遇到符号,就将两个栈顶的数字出栈
    //然后将结果再入栈
    char c , res ,e;
    SqStack s;
     InitStack(&s);
    printf("请输入后缀的表达式:\n");

    scanf("%c",&c);
    while(c != '#')
    {

        if(c>='0' && c<='9')
       {
           printf("%d\n",c);
           Push(&s,c);
       }
         else if(c == '*'|| c=='/'||c=='+'||c=='-')
       {
         Pop(&s , &e);
         res += e;
         Pop(&s , &e);
         res += e;

         Push(&s , res);
       }

       scanf("%c",&c);
    }

    printf("%c\n", res);

   return 0;
}

中缀表达式转后缀表达式

“9+(3-1)×3+10÷2”叫做中缀表达式。因为所有的运算符号都在两数字的中间,现在我们的问题就是中缀到后缀的转化。

中缀表达式“9+(3-1)×3+10÷2”转化为后缀表达式“9 3 1-3*+10 2/+”

规则:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或优先级不高于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。

1+(2-3)*4+10/5    :步骤:  

 1.直接输出数字   1 

2.   + 入栈   

3.(入栈

4.  直接输出 数字 2

5 .  - 入栈

6.  直接输出数字3 

7.   紧跟着是“)”,此时,我们需要去匹配栈里的“(”,然后再匹配前将栈顶数据依次出栈

8.那么就输出 - 

9. 就  剩  下

10.   *入栈 

11.  直接输出数字  4

12.符号“+”,此时栈顶元素是符号“*”,按照先乘除后加减原理,此时栈顶的乘号优先级比即将入栈的加好要大,所以出栈。

即  输出 *

13. 接着就是 + 号, 但是和里面的 + 号 相同,那么按照先来先出的原则,把里面的 + 号也输出,把新的 + 号,放入。

14.接着输出 10 

15.接着放 / 号

16.输出 数字 5 

17.将栈中的元素 依次出栈

int main()
{
    sqStack s;
    char c, e;

    InitStack( &s );

    printf("请输入中缀表达式,以#作为结束标志:");
    scanf("%c", &c);

    while( c != '#' )
    {
        while( c>='0' && c<='9' )
        {
            printf("%c", c);
            scanf("%c", &c);
            if( c<'0' || c>'9' )
            {
                printf(" ");
            }
        }

        if( ')' == c )
        {
            Pop(&s, &e);
            while( '(' != e )
            {
                printf("%c ", e);
                Pop(&s, &e);
            }
        }
        else if( '+'==c || '-'==c )
        {
            if( !StackLen(s) )
            {
                Push(&s, c);
            }
            else
            {
                do
                {
                    Pop(&s, &e);
                    if( '(' == e )
                    {
                        Push(&s, e);
                    }
                    else
                    {
                        printf("%c ", e);
                    }
                }while( StackLen(s) && '('!=e );
                Push(&s, c);
            }
        }
        else if( '*'==c || '/'==c || '('==c )
        {
            Push(&s, c);
        }
        else if( '#'== c )
        {
            break;
        }
        else
        {
            printf("\n出错:输入格式错误!\n");
            return -1;
        }

        scanf("%c", &c);
    }

    while( StackLen(s) )
    {
        Pop(&s, &e);
        printf("%c ", e);
    }

    return 0;
}

二进制转为十进制

int main()
{
    ElemType c;
    sqStack s;
    int len, i, sum = 0;

    InitStack(&s);

    printf("请输入二进制数,输入#符号表示结束!\n");
    scanf("%c", &c);
    while( c != '#' )
    {
        Push(&s, c);
        scanf("%c", &c);
    }

    getchar();  // 把'\n'从缓冲区去掉

    len = StackLen(s);
    printf("栈的当前容量是: %d\n", len);

    for( i=0; i < len; i++ )
    {
        Pop(&s, &c);
        sum = sum + (c-48) * pow(2, i);
    }

    printf("转化为十进制数是: %d\n", sum);

    return 0;
}

二进制转为十六进制

/*****************************/
/** 二进制/十六进制转换器  **/
/** By www.fishc.com 小甲鱼 **/
/*****************************/

int main()
{
    ElemType c;
    sqStack s1;
    sqStack s2;
    int len, i, j, sum = 0;

    InitStack(&s1); // 初始化栈s1,用来存放二进制输入

    printf("请输入二进制数,输入‘#’号表示结束!\n\n");
    scanf("%c", &c);
    while( c != '#' )
    {
        if( c=='0' || c=='1' )  // 检查输入是否二进制
            Push(&s1, c);
        scanf("%c", &c);
    }
    getchar();      // 把'\n'从缓冲区去掉
    len = StackLen(s1);

    InitStack(&s2); // 初始化栈s2,用来存放转换的八进制

    for( i=0; i < len; i+=4 )
    {
        for( j=0; j < 4; j++ )
        {
            Pop( &s1, &c ); // 取出栈顶元素
            sum = sum + (c-48) * pow(2, j);

            if( s1.base == s1.top )
            {
                break;
            }
        }

        switch( sum )
        {
            case 10: sum = 'A'; break;
            case 11: sum = 'B'; break;
            case 12: sum = 'C'; break;
            case 13: sum = 'D'; break;
            case 14: sum = 'E'; break;
            case 15: sum = 'F'; break;
            default: sum += 48;
        }

        Push( &s2, sum );
        sum = 0;
    }

    printf("\n转化为十六进制数是: ");
    while( s2.base != s2.top )
    {
        Pop( &s2, &c );
        printf("%c", c);
    }
    printf("(H)\n");

    return 0;
}

二进制转为八进制

/*****************************/
/**  二进制/八进制转换器   **/
/** By www.fishc.com 小甲鱼 **/
/*****************************/

int main()
{
    ElemType c;
    sqStack s1;
    sqStack s2;
    int len, i, j, sum = 0;

    InitStack(&s1); // 初始化栈s1,用来存放二进制输入

    printf("请输入二进制数,输入‘#’号表示结束!\n\n");
    scanf("%c", &c);
    while( c != '#' )
    {
        if( c=='0' || c=='1' )  // 检查输入是否二进制
            Push(&s1, c);
        scanf("%c", &c);
    }
    getchar();      // 把'\n'从缓冲区去掉
    len = StackLen(s1);

    InitStack(&s2); // 初始化栈s2,用来存放转换的八进制

    for( i=0; i < len; i+=3 )
    {
        for( j=0; j < 3; j++ )
        {
            Pop( &s1, &c ); // 取出栈顶元素
            sum = sum + (c-48) * pow(2, j);

            if( s1.base == s1.top )
            {
                break;
            }
        }

        Push( &s2, sum+48 );
        sum = 0;
    }

    printf("\n转化为八进制数是: ");
    while( s2.base != s2.top )
    {
        Pop( &s2, &c );
        printf("%c", c);
    }
    printf("(O)\n");

    return 0;
}

逆波兰计算器//没看

实现对逆波兰输入的表达式进行计算。 支持带小数点的数据。

正常的表达式 ---> 逆波兰表达式

a+b ---> a b +

a+(b-c) ---> a b c - +

a+(b-c)*d ---> a b c - d * +

a+d*(b-c)---> a d b c - * +



int main()
{
    sqStack s;
    char c;
    double d, e;
    char str[MAXBUFFER];
    int i = 0;

    InitStack( &s );

    printf("请按逆波兰表达式输入待计算数据,数据与运算符之间用空格隔开,以#作为结束标志: \n");
    scanf("%c", &c);

    while( c != '#' )
    {
        while( isdigit(c) || c=='.' )  // 用于过滤数字
        {
            str[i++] = c;
            str[i] = '\0';
            if( i >= 10 )
            {
                printf("出错:输入的单个数据过大!\n");
                return -1;
            }
            scanf("%c", &c);
            if( c == ' ' )
            {
                d = atof(str);
                Push(&s, d);
                i = 0;
                break;
            }
        }

        switch( c )
        {
            case '+':
                Pop(&s, &e);
                Pop(&s, &d);
                Push(&s, d+e);
                break;
            case '-':
                Pop(&s, &e);
                Pop(&s, &d);
                Push(&s, d-e);
                break;
            case '*':
                Pop(&s, &e);
                Pop(&s, &d);
                Push(&s, d*e);
                break;
            case '/':
                Pop(&s, &e);
                Pop(&s, &d);
                if( e != 0 )
                {
                    Push(&s, d/e);
                }
                else
                {
                    printf("\n出错:除数为零!\n");
                    return -1;
                }
                break;
        }

        scanf("%c", &c);
    }

    Pop(&s, &d);
    printf("\n最终的计算结果为:%f\n", d);

    return 0;
}

// 5 - (6 + 7) * 8 + 9 / 4
// 5 - 13 * 8 + 9 / 4
// 5 - 104 + 2.25
// -99 + 2.25
// 5 6 7 + 8 * - 9 4 / +

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值