数据结构篇之栈
栈(stack)
概念
- 栈(stack)是限制插入和删除只能在一个位置上的进行的表,而这个模型唯一的开口位置是表的末端,叫做栈顶(top),相反表的首部,叫做栈底。对于栈的基本操作有Push(进栈)和Pop(出栈),前者相当于插入,后者则是删除表中最后一个元素(也就是处在栈顶位置的元素)。
- 栈是一个先进后出的模型
注意事项:
-
虽然这里将栈放在线性表外,但是栈模型也属于线性表。
-
栈是既可以用数组实现也可以用链表实现
- 如果栈的大小已知且固定,或者对随机访问元素效率有较高要求,使用数组实现栈可能更合适。
- 如果栈的大小不确定,或者插入和删除操作频繁且在栈顶之外发生,使用链表实现栈可能更有优势。
链表实现代码:
struct Node{
int data;
Node *next;
};
typedef Node* Stack;
Stack createStack(int data){
struct Node* p=new struct Node;
p->data=data;
p->next=NULL;
return p;
}
//进栈
void Push(Stack &head,int data){
Stack add= createStack(data);
if(head==NULL){
head=add;
}else{
Node* p=head;
add->next=p;
head=add;
}
}
//出栈
void Pop(Stack &head){
if(head==NULL){
cout<<"栈中没有数据"<<endl;
return;
}
Node* p=head;
head=p->next;
delete p;
}
//获取栈顶元素
int top(Stack head){
return head->data;
}
//打印栈
void printStack(Stack head){
if(head==NULL){
cout<<"栈中没有数据"<<endl;
return;
}
Node* p=head;
while (p!=NULL){
cout<<p->data<<" ";
p=p->next;
}
cout<<endl;
}
//获取栈的大小
int Size(Stack head){
Node* p=head;
int cnt=0;
if(p->data&&p->next==NULL){
cnt=1;
} else{
while (p!=NULL){
cnt++;
p=p->next;
}
}
return cnt;
}
//判断栈是否为空
bool empty(Stack head){
if (head!=NULL){
return false;
}else{
return true;
}
}
//清空栈
void destroy(Stack &head){
if(head==NULL){
cout<<"栈中没有数据"<<endl;
return;
}
Node* tail=head->next;
while (head!=NULL){
delete head;
head=tail;
if(tail!=NULL)
tail=tail->next;
else
return;
}
}
数组实现代码:
class stack{
public:
//入栈
void Push(int data){
head.push_back(data);
}
//出栈
void Pop(){
if(head.empty()){
cout<<"栈中没有数据!"<<endl;
return;
} else
head.pop_back();
}
//获取栈顶元素
int top(){
if(head.empty()){
cout<<"栈中没有数据!"<<endl;
return NULL;
}
return head.back();
}
//打印栈
void printstack(){
if(head.empty()){
cout<<"栈中没有数据"<<endl;
return;
}else{
for(vector<int>::const_iterator it=head.end()-1;it>=head.begin();it--){
cout<<*it<<" ";
}
cout<<endl;
}
}
//清空栈
void destory(){
head.clear();
}
//获取栈的大小
int Size(){
return head.size();
}
//判断栈是否为空
bool empty(){
if(head.empty()){
return true;
} else{
return false;
}
}
private:
vector<int>head;
};
逆波兰转换式
概念:
-
一种后缀表达式,例如a+b+c*d,转换成逆波兰表达式就为:a b + c d * +,然后我们将逆波兰表达式压入栈中(将元素压入栈中遇到运算符号就将栈中的两个元素进行出栈在进行运算,运算完后再压入栈中,重复操作就能得到逆波兰表达式的结果),逆波兰表达式中没有括号!
-
转换成逆波兰表达式,需要一个空栈跟一个临时输出区(但不直接输出),将运算元素放进临时输出区,将运算符号压入栈中。
- 如果运算符的优先级大于上一个运算符,就进行入栈。
- 如果运算符的优先级小于等于上一个运算符,就将前面的运算符出栈放在临时输出区,再将该运算符入栈。
- 如果栈中有左括号,后面入栈的运算符不是右括号的话,左括号就不出栈,而是继续重复上两个规则,直到右括号出现就将左括号出栈,但括号不放入临时输出区
- 当运算元素都放入临时输出区时,栈区还有运算符就直接出栈放入临时存放区,最终将临时存放区按顺序输出出来就是转换的逆波兰表达式
代码:
bool flag(char a,char b){
int a1,b1;
if(a=='+'||a=='-'){
a1=1;
}else if(a=='*'||a=='/'){
a1=2;
}else if(a=='('||a==')'){
a1=3;
}
if(b=='+'||b=='-'){
b1=1;
}else if(b=='*'||b=='/'){
b1=2;
}else if(b=='('||b==')'){
b1=3;
}
return a1>=b1;
}
vector<char> reversePolan(char *an,int len){
stack<char>s;
vector<char>v;
int cnt=0;
for(int i=0;i<len;i++){
if(an[i]!='+'&&an[i]!='-'&&an[i]!='*'&&an[i]!='/'&&an[i]!='('&&an[i]!=')'){
v.push_back(an[i]);
}else if(an[i]=='+'||an[i]=='-'||an[i]=='*'||an[i]=='/'||an[i]=='('||an[i]==')'){
if(s.empty()){
s.push(an[i]);
}else if(an[i]=='('){
s.push(an[i]);
cnt=1;
}else if(an[i]==')'&&cnt==1){
while (s.top()!='('){
v.push_back(s.top());
s.pop();
}
s.pop();
cnt=0;
} else if(flag(s.top(),an[i])){
while (!s.empty()){
if(s.top()=='('){
break;
}
v.push_back(s.top());
s.pop();
}
s.push(an[i]);
}else{
s.push(an[i]);
}
}
}
if(!s.empty()){
while (!s.empty()){
v.push_back(s.top());
s.pop();
}
}
return v;
}
int main() {
char an[]={'a','+','b','*','c','+','(','d','*','e','+','f',')','*','g'};
int len= sizeof(an)/ sizeof(an[0]);
auto a= reversePolan(an,len);
for(char i:a){
cout<<i<<" ";
}
cout<<endl;
system("pause");
return 0;
}
尾言
完整版笔记也就是数据结构与算法专栏完整版可到我的博客进行查看,或者在github库中自取(包含源代码)
- 博客1: codebooks.xyz
- 博客2:moonfordream.github.io
- github项目地址:Data-Structure-and-Algorithms