数据结构与算法(七) 栈以及栈的应用

栈的应用非常的广泛,在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
 

 

posted @   Alpha205  阅读(142)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示