数据结构与算法(七) 栈以及栈的应用
栈的应用非常的广泛,在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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 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)