《数据结构与算法分析》学习笔记(四)——栈ADT
一、栈ADT是what?
1、定义
栈,是限制插入和删除都只能在一个位置上进行的表。
2、图示
3、栈的基本功能
(1)是否为空
(2)进栈
(3)出栈
(4)清空
(5)取栈顶
二、栈的链表实现
#ifndef Exercise_Stack_h
#define Exercise_Stack_h typedef struct Node *PrtToNode;
typedef PrtToNode Stack;
typedef int ElementType; struct Node
{
ElementType Element;
PrtToNode Next;
}; bool IsEmpty(Stack S); Stack CreateStack(); void MakeEmpty(Stack S); void Push(ElementType X,Stack S); void Pop(Stack S); ElementType Top(Stack S); #endif bool IsEmpty(Stack S)
{
return S->Next==nullptr;
} Stack CreateStack()
{
Stack S; S = new struct Node;
if(S==nullptr)
{
std::cout<<"Create Error!"<<std::endl;
return nullptr;
} S->Next=nullptr; return S;
} void MakeEmpty(Stack S)
{
if(S==nullptr)
{
std::cout<<"not initStack Error!"<<std::endl;
return ;
} while (!IsEmpty(S))
{
Pop(S);
} } void Push(ElementType X,Stack S)
{
PrtToNode Temp; Temp = new struct Node;
if(Temp==nullptr)
{
std::cout<<"init Node Error!"<<std::endl;
return;
} Temp->Element=X;
Temp->Next=S;
S->Next=Temp;
} void Pop(Stack S)
{
if(IsEmpty(S))
{
std::cout<<"Stack Empty!"<<std::endl;
return;
}
auto temp = S->Next;
S->Next=S->Next->Next;
delete temp;
} ElementType Top(Stack S)
{
if(IsEmpty(S))
{
std::cout<<"Stack Empty!"<<std::endl;
return ;
}
return S->Next->Element;
}
PS:优点:不用担心栈溢出的现象
缺点:开辟内存和释放内存的时候貌似开销比较昂贵。
三、栈的数组实现
typedef int ElementType;
const int MaxCapacity = ; struct StackRecord
{
int Capacity;
int TopOfStack;
ElementType *Array;
}; typedef struct StackRecord *Stack; bool IsFull(Stack S); bool IsEmpty(Stack S); Stack CreateStack(int MaxElements); void DisposeStack(Stack S); void MakeEmpty(Stack S); void Push(ElementType X,Stack S); void Pop(Stack S); ElementType Top(Stack S); ElementType TopandPop(Stack S); Stack CreateStack(int MaxElements)
{
Stack S; S = new struct StackRecord;
if(S==nullptr)
{
std::cout<<"Out of space!"<<std::endl;
return nullptr;
} S->Array = new ElementType(MaxElements);
if(S->Array==nullptr)
{
std::cout<<"Out of space!"<<std::endl;
return nullptr;
} S->Capacity=MaxElements;
S->TopOfStack=-; MakeEmpty(S); return S; } void DisposeStack(Stack S)
{
if(S!=nullptr)
{
delete S->Array;
delete S;
}
} bool IsEmpty(Stack S)
{
return S->TopOfStack==-;
} void MakeEmpty(Stack S)
{
S->TopOfStack=-;
} void Push(ElementType X,Stack S)
{
if(IsFull(S))
{
std::cout<<"Full Stack"<<std::endl;
return;
}
S->Array[++S->Array[S->TopOfStack]]=X; } ElementType Top(Stack S)
{
if(!IsEmpty(S))
{
return S->Array[S->TopOfStack];
} std::cout<<"Empty Error"<<std::endl;
return ;
} void Pop(Stack S)
{
if(IsEmpty(S))
{
std::cout<<"Empty Error"<<std::endl;
}
else{
S->TopOfStack--;
}
} ElementType TopandPop(Stack S)
{
if(!IsEmpty(S))
{
return S->Array[S->TopOfStack--];
}
std::cout<<"Empty Error"<<std::endl;
return ; } bool IsFull(Stack S)
{
return S->Capacity==MaxCapacity;
}
优点:把不断开空间的时间省下来了;
缺点:数组商都是有限的;
四、应用
(1)括号的匹配
void test(string s)
{
auto stack = CreateStack(); for(auto c: s)
{
if(c=='['||c=='{'||c=='(')
{
Push(c, stack);
}
else
{
if(c==']'||c=='}'||c==')')
{
if(IsEmpty(stack))
{
cout<<"Error!"<<endl;
}
else
{
if(c==']')
{
auto temp = TopandPop(stack);
if(temp!='[')
{
cout<<"Error!"<<endl;
}
}
else if(c=='}')
{
auto temp = TopandPop(stack);
if(temp!='{')
{
cout<<"Error!"<<endl;
}
}
else if(c==')')
{
auto temp = TopandPop(stack);
if(temp!='(')
{
cout<<"Error!"<<endl;
}
}
else
{
cout<<"Scanf Error!"<<endl;
} }
}
else
{
cout<<"Scanf Error!"<<endl;
}
} } if(stack->TopOfStack==-)
{
cout<<"RIGHT"<<endl;
}
else
{
cout<<"Error!"<<endl;
} }
(2)后缀表达式的计算。
后缀表达式的优点就是完全不需要考虑什么优先级之类的,直接从左边算到右边就可以了,简直方便快捷,在这里我就默默的实现下,小白勿喷
int calculate(string S) //10以内的整数运算
{ auto stack = CreateStack(); for(auto c:S)
{
switch (c)
{
case '+' :
{
auto t1=TopandPop(stack);
auto t2=TopandPop(stack);
double t3=t1+t2; Push(t3, stack);
} break;
case '-':
{
auto t1=TopandPop(stack);
auto t2=TopandPop(stack);
double t3=t2-t1; Push(t3, stack);
}
break;
case '*':
{
auto t1=TopandPop(stack);
auto t2=TopandPop(stack);
double t3=t2*t1; Push(t3, stack);
}
break;
case '/':
{
auto t1=TopandPop(stack);
auto t2=TopandPop(stack);
double t3=t2/t1; Push(t3, stack);
}
break;
default:
{
Push(c-'', stack);
}
break;
}
} return Top(stack); }
3、中缀表达式转化成后缀表达式
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std; int pre(char a) //操作符优先级比较
{
if(a == '=' || a == '(')
return ;
else if(a == '+' || a == '-')
return ;
else if(a == '*' || a == '/')
return ;
else
{
cout<<"Error!"<<endl;
return ;
}
} int main()
{
string str;
stack<char> ope; //操作符
vector<char> ans;//后缀表达式
vector<char>::iterator start, end;
getchar(); //清除输入垃圾 while(!ope.empty()) //初始化
ope.pop();
ans.clear();
ope.push('='); //结束标志
cin>>str;
auto len = str.length();
for(int i = ; i < len; ++i)
{
if(str[i] >= '' && str[i] <= '') //操作数直接存入ans
ans.push_back(str[i]);
else if(str[i] == '(') //左括号入栈
ope.push(str[i]);
else if(str[i] == ')') //右括号,将匹配的左括号内容存入ans,左括号出栈
{
while (ope.top() != '(')
{
ans.push_back(ope.top());
ope.pop();
}
ope.pop(); //左括号出栈
}
else if(pre(str[i]) > pre(ope.top())) //优先级大于栈顶元素则入栈
ope.push(str[i]);
else //小于栈顶元素
{
while(pre(str[i]) <= pre(ope.top()))
{
ans.push_back(ope.top());
ope.pop();
}
ope.push(str[i]);
}
}
while(ope.top() != '=') //其余操作符存入后缀表达式中
{
ans.push_back(ope.top());
ope.pop();
}
for(start = ans.begin(), end = ans.end(); start < end; ++start)
printf("%c", *start);
printf("\n"); return ;
}
《数据结构与算法分析》学习笔记(四)——栈ADT的更多相关文章
- java之jvm学习笔记四(安全管理器)
java之jvm学习笔记四(安全管理器) 前面已经简述了java的安全模型的两个组成部分(类装载器,class文件校验器),接下来学习的是java安全模型的另外一个重要组成部分安全管理器. 安全管理器 ...
- <数据结构与算法分析>读书笔记--最大子序列和问题的求解
现在我们将要叙述四个算法来求解早先提出的最大子序列和问题. 第一个算法,它只是穷举式地尝试所有的可能.for循环中的循环变量反映了Java中数组从0开始而不是从1开始这样一个事实.还有,本算法并不计算 ...
- <数据结构与算法分析>读书笔记--运行时间计算
有几种方法估计一个程序的运行时间.前面的表是凭经验得到的(可以参考:<数据结构与算法分析>读书笔记--要分析的问题) 如果认为两个程序花费大致相同的时间,要确定哪个程序更快的最好方法很可能 ...
- <数据结构与算法分析>读书笔记--利用Java5泛型实现泛型构件
一.简单的泛型类和接口 当指定一个泛型类时,类的声明则包括一个或多个类型参数,这些参数被放入在类名后面的一对尖括号内. 示例一: package cn.generic.example; public ...
- 官网实例详解-目录和实例简介-keras学习笔记四
官网实例详解-目录和实例简介-keras学习笔记四 2018-06-11 10:36:18 wyx100 阅读数 4193更多 分类专栏: 人工智能 python 深度学习 keras 版权声明: ...
- C#可扩展编程之MEF学习笔记(四):见证奇迹的时刻
前面三篇讲了MEF的基础和基本到导入导出方法,下面就是见证MEF真正魅力所在的时刻.如果没有看过前面的文章,请到我的博客首页查看. 前面我们都是在一个项目中写了一个类来测试的,但实际开发中,我们往往要 ...
- IOS学习笔记(四)之UITextField和UITextView控件学习
IOS学习笔记(四)之UITextField和UITextView控件学习(博客地址:http://blog.csdn.net/developer_jiangqq) Author:hmjiangqq ...
- Learning ROS for Robotics Programming Second Edition学习笔记(四) indigo devices
中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...
- Typescript 学习笔记四:回忆ES5 中的类
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- ES6学习笔记<四> default、rest、Multi-line Strings
default 参数默认值 在实际开发 有时需要给一些参数默认值. 在ES6之前一般都这么处理参数默认值 function add(val_1,val_2){ val_1 = val_1 || 10; ...
随机推荐
- c++实现加密和解密算法以及JNI技术的应用实例
#include "jiami.h" #include "jni.h" #include "com_test_start_CommonClassLoa ...
- Java&.Net虚拟机精简(GreenJVM&GreenDotNet发布) .
精简JRE体积的小工具:http://blog.csdn.net/cping1982/archive/2008/09/02/2865198.aspx 项目地址:http://code.google.c ...
- Java-java中的有符号,无符号操作以及DataInputStream
1. 无符号和有符号 计算机中用补码表示负数,并且有一定的计算方式:另外,用二进制的最高位表示符号,0表示正数.1表示负数.这种说法本身没错,可是要有一定的解释,不然它就是错的,至少不能解释,为什么字 ...
- oracle经典书籍推荐 转
很多网友询问如何选择入门书籍,学Oracle有什么好书,这里给出一些常见书籍的介 绍.首先声明,本文只涉及国外作品,因为国内的作品好的极少,大多是拼凑之作. 提到入门学习,我又得搬Tom(Thomas ...
- linux 下如何给用户添加权限
linux 添加用户.权限:# useradd –d /usr/sam -m sam此命令创建了一个用户sam,其中-d和-m选项用来为登录名sam产生一个主目录/usr/sam(/usr为默认的用户 ...
- MD5 Message Digest Algorithm MD5(中文名为消息摘要算法第五版)
MD5 编辑 Message Digest Algorithm MD5(中文名为消息摘要算法第五版)为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护.该算法的文件号为RFC 1321( ...
- VIM、GVIM在WINDOWS下中文乱码的终极解决方案
文章转自:http://www.liuhuadong.com/archives/68 vim.gvim在windows下中文乱码的终极解决方案在windows下vim的中文字体显示并不好,所以我们需要 ...
- ASP.NET MVC学习笔记-----使用自定义的View Engine
我们都知道在ASP.NET MVC中自带了Razor View Engine,Razor十分的强大,可以满足我们绝大部分的需要.但是ASP.NET MVC的高度可扩展性,使我们可以使用自定义的View ...
- JavaScript初级教程(Jquery)
序,学习前端页面编程技术,JS是不得不学的一门技术,目前JS不仅可以作为前端编程语言,在服务器端也有了一定发展,例如NodeJS.废话不多书,本篇博客主要介绍JS作为前端语言,怎样获得和改变HTML标 ...
- 深入理解Java中的继承
对于面向对象的程序设计而言,每一个程序员都应该去了解Java中的封装,继承和多态,那么我今天来说的主要是以继承为核心的主题. 一.关于对继承的理解. 继承是面向对象的三大特性之一,是java中实现代码 ...