栈算是一种表(list),但是它只能在表的末端(栈顶top)进行操作,栈的特点是后进先出(LIFO)。
实现栈同样可以用链表和数组,一般大家比较喜欢用数组,避免了指针,而且没有分配内存的时间开销,不过需要事先声明数组大小,所有涉及到数组的都存在这个问题。
一、用链表实现
链表实现栈要记住的是表头为栈顶,因为稍微模拟一下就可以知道,如果把链表末尾当做栈顶,那么在出栈的时候栈无法指向这个结点的前一个结点。
StackList.h
#pragma once
#include<iostream>
using namespace std;
struct Node;
typedef int ElementType;
typedef Node* PtrToNode;
typedef PtrToNode Stack;
Stack createStack();
void makeEmpty(Stack);
void dispose(Stack);
void push(ElementType, Stack);
ElementType pop(Stack);
ElementType top(Stack);
void printStack(Stack);
struct Node
{
ElementType data;
PtrToNode next;
};
StackList.cpp
#include "stdafx.h"
#include "StackList.h"
Stack createStack()
{
Stack s;
s = (Stack)malloc(sizeof(struct Node));
if (s==nullptr)
{
cout << "space error" << endl;
return s;
}
s->next = nullptr;
makeEmpty(s);
return s;
}
void makeEmpty(Stack s)
{
if (s==nullptr)
{
return;
}
while ((s->next)!=nullptr)
{
pop(s);
}
}
void dispose(Stack s)
{
if (s == nullptr)
return;
makeEmpty(s);
free(s);
}
void push(ElementType e, Stack s)
{
Node *node = (Node*)malloc(sizeof(struct Node));
if (node==nullptr)
{
cout << "space error" << endl;
}
node->data = e;
node->next = s->next;
s->next = node;
}
ElementType pop(Stack s)
{
if (s->next!=nullptr)
{
Node *node = s->next;
ElementType e = node->data;
s->next = node->next;
free(node);
return e;
}
return -1;
}
ElementType top(Stack s)
{
if ((s==nullptr) || (s->next == nullptr))
{
cout << "empty" << endl;
return -1;
}
return s->next->data;
}
void printStack(Stack s)
{
if (s == nullptr)
{
return;
}
Node *ptr = s->next;
while (ptr!=nullptr)
{
cout << ptr->data << endl;
ptr = ptr->next;
}
}
二、用数组实现
StackArray.h
#pragma once
#include<iostream>
using namespace std;
struct Node;
typedef int ElementType;
typedef Node* Stack;
bool isFull(Stack);
bool isEmpty(Stack);
Stack createStack(int max_capacity);
void makeEmpty(Stack);
void dispose(Stack);
void push(ElementType, Stack);
ElementType pop(Stack);
ElementType top(Stack);
void printStack(Stack);
struct Node
{
int capacity;
int top_of_stack;
ElementType *array_data;
};
StackArray.cpp
#include "stdafx.h"
#include "StackArray.h"
bool isFull(Stack s)
{
return (s->top_of_stack) >= (s->capacity);
}
bool isEmpty(Stack s)
{
return s->top_of_stack <= -1;
}
Stack createStack(int max_capacity)
{
Stack s;
s = (Stack)malloc(sizeof(struct Node));
if (s==nullptr)
{
return s;
}
s->array_data = (ElementType*)malloc(sizeof(ElementType)*max_capacity);
if (s->array_data==nullptr)
{
return nullptr;
}
s->capacity = max_capacity;
makeEmpty(s);
return s;
}
void makeEmpty(Stack s)
{
if (s==nullptr)
{
return;
}
s->top_of_stack = -1;
}
void dispose(Stack s)
{
makeEmpty(s);
free(s->array_data);
free(s);
s->capacity = 0;
}
void push(ElementType e, Stack s)
{
if (isFull(s))
{
return;
}
s->array_data[++s->top_of_stack] = e;
}
ElementType pop(Stack s)
{
if (!isEmpty(s))
{
return s->array_data[s->top_of_stack--];
}
return -1;
}
ElementType top(Stack s)
{
if (!isEmpty(s))
{
return s->array_data[s->top_of_stack];
}
return -1;
}
void printStack(Stack s)
{
if (!isEmpty(s))
{
for (int i=0;i<=(s->top_of_stack);++i)
{
std::cout << (s->array_data)[i] << std::endl;
}
}
}
注:程序中包含的vld.h是一个内存泄漏的检查工具,只需要把路径放在包含目录,include头文件就可以检测是否泄漏,一般快速的检查就是不打断点debug一下,在输出窗口会输出内存泄漏的信息。
三、应用
(1)检查括号匹配的简单代码
bool isMatching(string &str)
{
Stack s = createStack(100);
char e;
for (auto c:str)
{
switch (c)
{
case '{':
case '(':
case '[':
push(c, s);
break;
case '}':
if (isEmpty(s)||(e=pop(s)) !='{')
return false;
break;
case ']':
if (isEmpty(s) || (e = pop(s)) != '[')
return false;
break;
case ')':
if (isEmpty(s) || (e = pop(s)) != '(')
return false;
break;
}
}
return true;
}
(2)整数的四则运算
//整数四则运算
int computeInt(int a, int b,char c)
{
int res = -1;
switch (c)
{
case '+':
res = a + b;
break;
case '-':
res = a - b;
break;
case '*':
res = a*b;
break;
case '/':
if (b!=0)
{
res = a / b;
break;
}
break;
default:
break;
}
return res;
}
//计算后缀表达式表示的式子
int computeSuffix(string &str)
{
Stack s = createStack(100);
int a, b,d;
for (auto c:str)
{
if (isdigit(c))
{
d = c - '0';
push(d, s);
}
else
{
b = pop(s);
a = pop(s);
push(computeInt(a, b, c),s);
}
}
return pop(s);
}
bool isPrior(char a,char b)
{
if (a=='(')
{
return true;
}
if ( (b == '*' || a == '/')&&(a=='+'||b=='-'))
{
return true;
}
return false;
}
//中缀转后缀表达式
string infixToSuffix(string &str)
{
string prefix;
int d;
Stack s = createStack(100);
for (auto c:str)
{
if (isdigit(c))
{
prefix += c;
}
else if (isEmpty(s)|| c == '(')
{
push(c, s);
}
else if (c==')')
{
char popout = pop(s);
while (popout!='(')
{
prefix += popout;
popout = pop(s);
}
}
else if (isPrior(top(s),c))
{
push(c, s);
}
else
{
prefix += pop(s);
push(c, s);
}
}
while (!isEmpty(s))
{
prefix += pop(s);
}
return prefix;
}
int main()
{
string s = "6+5*3*(2+4)*4";
string prefix = infixToSuffix(s);
cout << prefix << endl;
int res = computeSuffix(prefix);
cout << res << endl;
return 0;
}