栈(stack)

栈的应用

浏览器 “回退” 功能的实现,底层使用的就是栈存储结构。当你关闭页面 A 时,浏览器会将页面 A 入栈;同样,当你关闭页面 B 时,浏览器也会将 B入栈。因此,当你执行回退操作时,才会首先看到的是页面 B,然后是页面 A,这是栈中数据依次出栈的效果。

不仅如此,栈存储结构还可以帮我们检测代码中的括号匹配问题。多数编程语言都会用到括号(小括号、中括号和大括号),括号的错误使用(通常是丢右括号)会导致程序编译错误,而很多开发工具中都有检测代码是否有编辑错误的功能,其中就包含检测代码中的括号匹配问题,此功能的底层实现使用的就是栈结构。

同时,栈结构还可以实现数值的进制转换功能。例如,编写程序实现从十进制数自动转换成二进制数,就可以使用栈存储结构来实现。

1、栈(Stack)是一种线性存储结构,它具有如下特点:

(1)栈中的数据元素遵守“先进后出"(First In Last Out)的原则,简称FILO结构。

(2)限定只能在栈顶进行插入和删除操作。
2、栈的常用操作为:

(1)弹栈,通常命名为pop

(2)压栈,通常命名为push

(3)求栈的大小

(4)判断栈是否为空

(5)获取栈顶元素的值
3.使用标准库的栈时, 应包含相关头文件,在栈中应包含头文件: #include< stack > 。定义:stack< int > stk;

stk.empty(); //如果栈为空则返回true, 否则返回false;
stk.size(); //返回栈中元素的个数
stk.top(); //返回栈顶元素, 但不删除该元素
stk.pop(); //弹出栈顶元素, 但不返回其值
stk.push(); //将元素压入栈顶

顺序栈4要素:
栈空条件:top=-1
栈满条件:top=MaxSize-1
进栈e操作:top++; 将e放在top处
退栈操作:从top处取出元素e; top–;
3.在顺序栈中实现栈的基本运算算法。

(1)初始化栈initStack(&s)
建立一个新的空栈s,实际上是将栈顶指针指向-1即可。对应算法如下:
csharp void InitStack(SqStack *&s) { s=(SqStack *)malloc(sizeof(SqStack)); s->top=-1; }
2)销毁栈ClearStack(&s)
释放栈s占用的存储空间。对应算法如下:
void DestroyStack(SqStack *&s) {    free(s); }
(3)判断栈是否为空StackEmpty(s)
栈S为空的条件是s->top==-1。对应算法如下:
bool StackEmpty(SqStack *s) {    return(s->top==-1); }
(4)进栈Push(&s,e)
在栈不满的条件下,先将栈指针增1,然后在该位置上插入元素e。对应算法如下:

		bool Push(SqStack *&s,ElemType e)
		{
 		 if (s->top==MaxSize-1)  //栈满的情况,即栈上溢出
    				return false;
			 s->top++;           //栈顶指针增1
  			 s->data[s->top]=e;      //元素e放在栈顶指针处
  			 return true;
		}

(5)出栈Pop(&s,&e)
在栈不为空的条件下,先将栈顶元素赋给e,然后将栈指针减1。对应算法如下:

   bool Pop(SqStack *&s,ElemType &e)
	{
   			if (s->top==-1)  //栈为空的情况,即栈下溢出
    				return false;
   			e=s->data[s->top];   //取栈顶指针元素的元素
   			s->top--;        //栈顶指针减1
   			return true;
	}

6)取栈顶元素GetTop(s)
在栈不为空的条件下,将栈顶元素赋给e。对应算法如下:

bool GetTop(SqStack *s,ElemType &e)
{   
   if (s->top==-1)  //栈为空的情况,即栈下溢出     
      return false;
    e=s->data[s->top];  //取栈顶指针元素的元素
    return true;
}

例:编写一个算法利用顺序栈判断一个字符串是否是对称串。所谓对称串是指从左向右读和从右向左读的序列相同。 解:对于字符串str,先将其所有元素进栈。然后从头开始扫描str,并出栈元素,将两者进行比较,若不相同则返回false。当str扫描完毕仍没有返回时返回true。实际上,从头开始扫描str是从左向右读,出栈序列是从右向左读,两者相等说明该串是对称串

bool symmetry(ElemType str[])
{  
		 int i;  ElemType e;
  		 SqStack *st;
   		InitStack(st);           //初始化栈
   		for (i=0;str[i]!='\0';i++)   //将串所有元素进栈
    			Push(st,str[i]);        //元素进栈
  		 for (i=0;str[i]!='\0';i++)
   		{   
   				 Pop(st,e);        //退栈元素e
    			if (str[i]!=e)    //若e与当前串元素不同则不是对称串
    			{  
    					DestroyStack(st);//销毁栈
       					return false;
    			}
 		  }
  		 DestroyStack(st);      //销毁栈
   		return true;
}

例:编写一个算法判断输入的表达式中括号是否配对(假设只含有左、右圆括号)。
解:该算法在表达式括号配对时返回true,否则返回false。设置一个顺序栈St,扫描表达式exp,遇到左括号时进栈;遇到右括号时:若栈顶为左括号,则出栈,否则返回false。当表达式扫描完毕,栈为空时返回true;否则返回false。

bool Match(char exp[],int n)
{  
		int i=0; char e;  bool match=true; SqStack *st;
   		InitStack(st);             //初始化栈
   		while (i<n && match)       //扫描exp中所有字符
   		{    
   				if ( exp[i]=='()  //当前字符为左括号,将其进栈
       					Push(st,exp[i]);
    			else if (exp[i]==')')   //当前字符为右括号
      			{
      				if (GetTop(st,e)==true)
       				{
       					if (e!='(')    //栈顶元素不为'('时表示不匹配
           						match=false;
       					 else
           						Pop(st,e);    //将栈顶元素出栈
       				 }
      				else  match=false;  //无法取栈顶元素时表示不匹配
     			 }
   				 i++;                 //继续处理其他字符
   		}
 	if (!StackEmpty(st))      //栈不空时表示不匹配
    		match=false;
   	DestroyStack(st);         //销毁栈
   	return match;
}

例:括号配对
不能使用栈(15min,不太好想,mad,笔试那会儿就没想到!)

   以下是我的想法,具体的过程如下:

  (1)由于不能使用栈,将左括号定义为数值1,右括号定义为数值-1,存放到向量id(C++)或列表tmp (Python)中;

  (2)初始化变量sum,用于判断总的求和结果是否等于0,若不等于0,则肯定不正确,若等于0,不一定正确;

  (3)循环遍历输入的括号向量vec,判断当前括号属性的同时,进行累加求和,如果求和值小于等于-1,break(跳出循环);

  (4)最后再检查sum是否等于0,此时若等于0,则为正确。
#include <iostream>
#include <vector>
using namespace std;
bool isRight(vector<char> &vec)
{
   	vector<int> id(vec.size()); //用于存放左右括号的属性:左括号用1表示,右括号用-1表示
   	int sum = 0;
   	bool index = false;
   	if (vec.size() <= 1 || vec[0]!='(' || vec.size()%2!=0)
   	{
   			return index;
   	}
   	for (int i = 0; i < vec.size(); i++)
   	{
   			if (vec[i] == '(')
   			{
   					id.push_back(1);
   					sum = id[i] + sum;
   			}	
   			else if (vec[i] == ')')
   			{
   					id.push_back(-1);
   					sum = id[i] + sum;
   					if (sum <= -1)
   							break;
   			}
   	}
   	if (sum == 0)
   			index = true;
   	return index;
}
int main()
{
   		//输入不定长的括号
   		vector<char> vec;
   		char tmpCh;
   		char t;
   		cout << "输入一串括号为:";
   		do{
   				cin >> tmpCh;
   				vec.push_back(tmpCh);
   			} while ((t = cin.get()) != '\n');
   		//调用isRight函数
   		bool myRes = isRight(vec);
   		cout << myRes << endl;
   		system("pause");
   		return 0;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这个问题非常适合用程序解决。以下是用stack实现简单计算器的c代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #define STACKLEN 1000 /* 的最大容量 */ typedef struct { int top; /* 顶指针 */ double data[STACKLEN]; /* 元素数组 */ } Stack; void push(Stack *pstack, double value) { if (pstack->top == STACKLEN - 1) { printf("Error: stack overflow!\n"); exit(EXIT_FAILURE); } else { pstack->data[++pstack->top] = value; } } double pop(Stack *pstack) { if (pstack->top == -1) { printf("Error: stack underflow!\n"); exit(EXIT_FAILURE); } else { return pstack->data[pstack->top--]; } } bool is_digit(char c) { return (c >= '0' && c <= '9'); } int precedence(char op) { if (op == '+' || op == '-') return 1; else if (op == '*' || op == '/') return 2; else return 0; } double calculate(double left, char op, double right) { switch (op) { case '+': return left + right; case '-': return left - right; case '*': return left * right; case '/': return left / right; default: printf("Error: invalid operator!\n"); exit(EXIT_FAILURE); } } double eval(char *expr) { Stack operandStack; operandStack.top = -1; Stack operatorStack; operatorStack.top = -1; int len = strlen(expr); int i = 0; while (i < len) { char c = expr[i]; if (is_digit(c)) { double value = 0.0; while (i < len && is_digit(expr[i])) { value = value * 10.0 + (double)(expr[i] - '0'); i++; } push(&operandStack, value); } else { while (operatorStack.top != -1 && precedence(operatorStack.data[operatorStack.top]) >= precedence(c)) { char op = operatorStack.data[operatorStack.top--]; double right = pop(&operandStack); double left = pop(&operandStack); push(&operandStack, calculate(left, op, right)); } push(&operatorStack, c); i++; } } while (operatorStack.top != -1) { char op = operatorStack.data[operatorStack.top--]; double right = pop(&operandStack); double left = pop(&operandStack); push(&operandStack, calculate(left, op, right)); } return pop(&operandStack); } int main() { char s[1000]; printf("Please enter an expression: "); scanf("%s", s); double result = eval(s); printf("Result: %f\n", result); return 0; } ``` 这段代码定义了两个:一个操作数(operandStack)和一个操作符(operatorStack),通过不断入和出的操作,实现对表达式进行求值。其中,is_digit函数用于判断一个字符是否是数字;precedence函数用于比较两个运算符的优先级;calculate函数用于计算两个操作数和一个操作符的运算结果;eval函数是主函数,用于将输入的表达式转化为数字计算结果。 希望这个回答能够帮助您!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值