一、栈的原理
数组+循环->栈、队列
栈:例如进电梯,先进的后出来,后进的先出来,栈里面的数据可以是任意类型
栈与数组的区别:数组可以访问任意元素,栈只能访问最上面元素,栈只有两种操作,
入栈、出栈,只能放数组顶端,栈需要一个指针永远指向栈顶、且永远指向空白的空间,来数据直接把数据放在指针的空白空间,出栈就是把指针向下挪一位。
栈代码实现:stack[]
三大关键操作:入栈、出栈、栈顶指针、判断栈是否为空
入栈:往栈放入数据,不关心返回值
出栈:关心出栈的数据
栈顶指针:永远指向空区域
判断栈是否为空:判断栈顶指针数是否为0,不确定循环的话就用while()循环
栈的实现原理
#include <stdio.h>
char stack[32];
int top = 0;//定义一个栈顶指针
void puch(char c)
{
stack[top++] = c;//放入一个数据指针往上挪一下,此时指针为空
}
char pop()//出栈就让空指针往下挪一个,把指向的数据给返回
{
return stack[--top];
}
int is_empty()//判断栈是否为空
{
return (top == 0);
}
int main()
{
puch('a');
puch('b');
puch('c');
while(!is_empty())//栈不为空就一直出栈
{
putchar(pop());
}
puts("\n");
return 0;
}
二、栈的应用:逆波兰表示法
比如:(1+2)*(3-4)
中缀表示法:(1+2)*(3-4)
逆波兰表示法:12+34—*
用栈表示方法:1、2分别入栈,碰到加号,出栈两个数据,用来相加结果放到
栈里;3、4分别入栈,碰到-号,出栈两个数据相减,且4先出来
放到右边,相减结果入栈;碰到*号,出栈两个数据用来相乘
优势:节省括号,节省存储空间
核心思想:从大往小,分拆
如:5*{[9+8]*[4*6]+7}
拆分:5{[9+8]*[4*6]+7}*
598+46**7+*
编程思想:有了前面的原理,当入栈碰到操作数就入栈,碰到操作符就出栈就行运算
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int stack[32];
int top = 0;//定义一个栈顶指针
void push(int c)
{
stack[top++] = c;//放入一个数据指针往上挪一下
}
int pop()
{
return stack[--top];
}
int is_empty()
{
return (top == 0);
}
void reverse_polish()
{
char a[256] = {'\0'};
int i;
int n1;
int n2;
printf("please input a reverse_polish data:");
scanf("%s",a);
strlen(a);
for(i=0;i<strlen(a);i++)
{
if(a[i]>='0' && a[i]<='9')
{
push(a[i]-'0');//对字符做一个校正,必须有
}
else
{
n2 = pop();
n1 = pop();
switch(a[i])
{
case '+':
push(n1+n2);
break;
case '-':
push(n1-n2);
break;
case '*':
push(n1*n2);
break;
}
}
}
printf("result = %d\n",pop());
}
int main()
{
reverse_polish();
return 0;
}
598+46**7+*;结果2075
三、栈的应用:中缀表达式转后缀表达式
处理过程:
1、仍然从左至右处理数据
2、碰到左括号忽略
3、碰到数字直接输出
4、碰到运算符入栈
5、碰到右括号就把栈顶进行出栈
void change()
{
int i;
char str[32] = {'\0'};
printf("please input a data:");
scanf("%s",str);
int len = strlen(str);
for(i=0;i<len;i++)
{
if(str[i] == '(')
{
}
if(str[i] >= '0' && str[i] <= '9')
{
printf("%c",str[i]);
}
if(str[i] == '+' || str[i] == '-' || str[i] == '*')
{
push(str[i]);
}
if(str[i] == ')')
{
printf("%c",pop());
}
}
}
四、栈的应用:括号匹配
匹配哪个括号右括号和左括号匹配
1、碰到左括号,就把左括号序数入栈,其他的忽略
2、到右括号,就把栈顶序数出栈
void maching()
{
int i;
char str[32] = {'\0'};
printf("please input a data:");
scanf("%s",str);
int len = strlen(str);
for(i=0;i<len;i++)
{
if(str[i] == '(')
{
push(i);
}
if(str[i] == ')')
{
printf("%d maching %d ,",pop(),i);
}
}
printf("\n");
}
五、栈的应用:十进制转换为二进制
例如:13转换为二进制1101
13/2 = 6 13%2 = 1
6/2 = 3 6%2 = 0
3/2 = 1 3%2 = 1
1/2 = 1 1%2 = 1
void conver()
{
int data_10;
int rem;
printf("请输入一个十进制数:");
scanf("%d",&data_10);
while((data_10 != 0))
{
push(data_10 % 2);//先放余数,再重置十进制数
data_10 = data_10/2;
}
while(!is_empty())
{
printf("%d",pop());
}
}
六、栈的应用:回文判定
算法流程:
1.求出字符串的长度,将前一半的字符依次入栈
2.如果栈不为空,出栈栈项元素,将其与后半部分的字符串进行比较。
如果字符串长度是奇数的话,要跳过中心点的元素,比较中心点后面的元素如果比较的元素是相等的,一直比较直到栈为空
3、不确定的循环次数就用while
int is_plaindrom()
{
char str[32];
int i;
printf("please input a plaindrom:");
scanf("%s",str);
int len = strlen(str)/2;
for(i=0;i<len;i++)
{
push(str[i]);//先把字符串前一半放进栈
}
if(strlen(str)%2)
{
i++;
}
while(!is_empty())//这里才是核心算法,这个i随奇偶而变
{
if(pop() == str[i])
{
i++;
}
else
{
return 0;
}
}
return 1;
}
if(is_plaindrom())
{
printf("this is plaindrom\n");
}
else
{
printf("this is not a plaindrom\n");
}