数据结构与算法(七) 栈以及栈的应用
栈的应用非常的广泛,在C++的STL中,提供了用数组实现的栈。把线性表的插入和删除操作都限制在同一端,就得到栈的数据结构。是一个后进先出的数据结构。
因为栈是一种特殊的线性表,所以可以从线性表类派生出stack类。通过派生的方法可以降低栈的开发难度,但是代码的执行效率也会降低。
定义和应用:
栈:一种特殊的线性表,插入和删除操作都限制在表的同一端进行,这端称为栈顶,另一端称为栈底。
应用: 计算机执行递归函数就用到了栈。
1.直接创建基于数组的栈:
arrayStack类:
arraystack.h文件
#ifndef ARRAY_STACK_H
#define ARRAY_STACK_H
#include <iostream>
#include "E:\back_up\code\c_plus_code\sparseMatrix\external_file\stackemptyException.h" // 异常类
using namespace std;
template<typename T=int>
class arrayStack
{
private:
T* element;
int elem_number; // 栈中元素的个数
int capacity; // 栈的容量
void ensureCaoacity();
// stack ADT
public:
arrayStack(int init_capacity=10);
~arrayStack();
arrayStack(const arrayStack& stack); // 拷贝构造函数
bool empty() const;
int size() const; // 返回栈中元素的个数
T top() const; // 返回栈顶元素的值
void pop(); // 删除栈顶元素
void push(T x); // 入栈
void print_stack() const;
// 定义友元函数;
};
// arrayStack实现
template<typename T>
arrayStack<T>::arrayStack(int init_capacity)
{
elem_number = 0;
capacity = init_capacity;
element = new T[capacity];
}
template<typename T>
arrayStack<T>::~arrayStack()
{
delete []element;
}
template<typename T>
arrayStack<T>::arrayStack(const arrayStack& stack)
{
elem_number = stack.elem_number; // 栈中的元素个数
capacity = stack.capacity;
element = new T[capacity];
// 赋值元素
for(int i=0; i<elem_number; i++)
{
element[i] = stack.element[i];
}
}
template<typename T>
void arrayStack<T>::ensureCaoacity()
{
if(elem_number>=capacity)
{
T* old = element;
// delete element;
// delete的本质是: delete之后,下次再重新申请的时候可以
// 再申请这块内存地址,对于这块地址的内容,没有进行清空处理(也没有必要)
capacity = elem_number*2;
element = new T[capacity];
for(int i=0; i<elem_number; i++)
{
element[i] = old[i];
}
delete []old;
}
// 还可以添加栈中数组大小动态减小的代码
}
template<typename T>
bool arrayStack<T>::empty() const
{
return elem_number==0;
}
template<typename T>
int arrayStack<T>::size() const // 返回栈中元素的个数
{
return elem_number;
}
template<typename T>
T arrayStack<T>::top() const
{
if(empty())
throw stack_empty_exception(0);
return element[elem_number-1]; // 返回栈顶元素的值
}
template<typename T>
void arrayStack<T>::pop()
{
if(empty())
throw stack_empty_exception(0);
elem_number--;
}
template<typename T>
void arrayStack<T>::push(T x)
{
ensureCaoacity();
element[elem_number++] = x;
}
template<typename T>
void arrayStack<T>::print_stack() const
{
if(empty())
{
cout << "The stack is empty" << endl;
}
else
{
for(int i=0; i<elem_number; i++)
{
cout << element[i] << " ";
}
cout << endl;
}
}
#endif
在栈为空的时候,不能进行出栈操作,这一功能由异常类实现:
stackemptyException.h文件
// 自定义异常类:
#ifndef STACK_EMPTY_EXCEPTION
#define STACK_EMPTY_EXCEPTION
#include <stdexcept>
using namespace std; // 因为stdexcept
class stack_empty_exception : public runtime_error
{
private:
int current_stack_size;
public:
stack_empty_exception(int stack_size):runtime_error("Stack is empty")
{
this->current_stack_size = stack_size;
}
void display_error_info()
{
cout << "----------------------------" << endl;
cout << "The stack size is " << current_stack_size << endl;
cout << "----------------------------" << endl;
}
};
#endif
测试文件
main.cpp
#include <iostream>
#include "E:\back_up\code\c_plus_code\sparseMatrix\external_file\arraystack.h"
using namespace std;
int main(int argc, char *argv[])
{
arrayStack<int> stack(10);
try // 异常测试
{
stack.pop();
}
catch(stack_empty_exception& ex)
{
cout << ex.what() << endl;
ex.display_error_info();
}
try // 异常测试
{
stack.pop();
}
catch(stack_empty_exception& ex)
{
cout << ex.what() << endl;
ex.display_error_info();
}
stack.print_stack();
for(int i=0; i<13; i++)
{
stack.push(i+1);
}
stack.print_stack();
cout << "stack size: " << stack.size() << endl;
while(!stack.empty()) // 出栈
{
cout << stack.top() << " ";
stack.pop();
}
cout << endl;
}
运行结果:
2
添加新的方法,将stack中的数据分为a,b两部分:
template<typename T>
void arrayStack<T>::split_stack(arrayStack& stack_a, arrayStack& stack_b)
{
if(elem_number<2)
throw stack_empty_exception(2);
int criterion = elem_number/2;
int count = 0;
while(elem_number>0)
{
if(count < criterion)
{
stack_a.push(element[elem_number-1]);
count++;
elem_number--;
}
else
{
stack_b.push(element[elem_number-1]);
count++;
elem_number--;
}
}
}
测试函数:
main.cpp
#include <iostream>
#include "E:\back_up\code\c_plus_code\sparseMatrix\external_file\arraystack.h"
using namespace std;
int main(int argc, char *argv[])
{
arrayStack<int> stack(10);
//stack.print_stack();
for(int i=0; i<10; i++)
{
stack.push(i+1);
}
stack.print_stack();
arrayStack<int> a;
arrayStack<int> b;
try
{
stack.split_stack(a, b);
cout << "split stack into two parts" << endl;
cout << "stack_a: ";
a.print_stack();
cout << "stack_b: ";
b.print_stack();
}
catch(stack_empty_exception& ex)
{
cout << ex.what() << endl;
ex.display_error_info();
}
}
运行结果:
2. 此外栈和可以由线性表的类派生而来,如arrayLIst类和chain类
3.栈的应用:
(a). 括号匹配:
例如:(a*(b+c)+d)进行括号匹配:从左到右扫描字符串,没哟个右括号都与最近扫描到的未匹配的左括号进行匹配
#include <iostream>
#include "E:\back_up\code\c_plus_code\sparseMatrix\external_file\arraystack.h"
#include <string>
using namespace std;
void printMatchedPairs(string expr)
{
arrayStack<int> s;
int expr_length = (int)expr.size();
// 扫描表达式
for(int i=0; i<expr_length; i++)
{
if(expr.at(i)=='(')
{
s.push(i); // 左括号的位置
}
else
{
if(expr.at(i)==')') // 如果是右括号,则进行匹配
try
{
cout << s.top() << " " << i << endl;
s.pop();
}
catch(stack_empty_exception& ex)
{
cout << "NO match for ) at " << i << endl;
}
}
}
while(!s.empty())
{
cout << "NO match for left bracket" << s.top() << endl;
s.pop();
}
}
int main(int argc, char *argv[])
{
string expression("((a+b)*2)+3");
printMatchedPairs(expression);
}
输出:
1 5
0 8