数据结构-栈容器的实现
2021/11/23 更新 将用于生成栈节点的
StackNode
类改为Stack
类的内嵌类,不仅使组织结构更合理,还减少了函数调用,有效减少了代码量.
栈的实现
栈是一种重要的数据结构,是一种线性结构,具有后进先出的特点.
因为线性表有 2 种实现方式,故栈也有 2 种实现方式,即顺序存储结构和链式存储结构.
本篇将以链式存储结构给出一种实现方式.
链栈的存储结构
和单链表的存储结构类似,链栈的存储映像也包括数据域和指针域两个部分.存储结构表示如下:
class StackNode
{// 这里不妨先用 T 来表示数据类型,后面将看到它的作用T data_;StackNode* next_;
};
为了方便管理一组栈节点不妨定义个 Stack 类如下:
class Stack
{private:StackNode<T>* ptr_;// 这里的 T 表示它所指向的栈节点数据域是 T 类型的
};
栈的主要操作
1. 初始化
初始化的任务就是构造一个空栈,与链表不同的是,链栈没有必要设置头节点,故只需将栈顶指针制空即可.可利用 Stack 类构造函数实现,如下:
Stack(){ptr_ = nullptr;}
2. 入栈
算法步骤
- 创建一个 StackNode 对象,用指针 ptr 指向.
- 将节点数据域制为 data.
- 将新节点插入栈顶.
- 修改栈顶指针.
具体实现如下:
bool Stack::push(T data){StackNode* ptr = new StackNode(data, ptr_);ptr_ = ptr;return true;}
3. 出栈
算法步骤
- 判断栈是否为空,若空返回
false
. - 将栈顶元素赋给 data.
- 临时保存栈顶元素的空间,以备释放
- 修改栈顶指针,指向新的栈顶元素.
- 释放原栈顶元素的指针.
具体实现如下:
bool Stack::pop(T& data){if (ptr_ == nullptr){return false;}data = ptr_->data_;StackNode* ptr = ptr_;ptr_ = ptr_->next_;delete ptr;return true;}
其中 get_data
和 get_next
分别为返回当前节点的数据元素和指针的函数.
4. 取栈顶元素
当栈非空时,返回当前栈顶元素的值,具体实现如下:
T Stack::get_top(){if (ptr_ != nullptr)return ptr_->data_;}
当然除了这些还可以定义其它接口,比如说,求栈长、清空栈等.这里就不一一赘述了.
其实到这里为止栈的数据结构基本已经实现完了,但任有改进的余地.
比方说,如果要同时使用存储 int
型数据的栈和 double
型数据的栈.上述代码就显得无能为力了. 你当然可以单独定义一个DoubleStack
类来存储 double
型数据.但为每种类型都单独定义相同功能的类的话是不现实的(因为还有用户自定义类型), 应用范围有限.那有没有一种方法可以定义一次对各种类型都适用呢? 有! C++ 的泛型.
栈容器的实现
其实在这里我们只要稍微修改我们的代码,就可以让我们的栈存储任意类型的数据了(这才叫容器嘛).基本思想一样,整合如下:
#pragma oncetemplate <typename T>
// 用于创建一个栈
class Stack
{public:// 在栈顶插入元素bool push(T);// 弹出栈顶元素,并保存bool pop(T&);// 弹出栈顶元素bool pop();// 取栈顶元素T get_top();// 清空栈void clear();// 求栈长size_t length();// 判断栈是否为空bool is_empty();Stack(){ptr_ = nullptr;length_ = 0;}~Stack(){clear();}private:template <typename T>// 用于生成栈节点class StackNode{public:StackNode() : data_(), next_() {}StackNode(T data) : StackNode(data, nullptr) {}StackNode(T data, StackNode* next) : data_(data), next_(next) {}// 栈节点的数据域T data_;// 指向下一个栈节点的指针域StackNode* next_;};// 栈的头指针,可标志一个栈StackNode<T>* ptr_;// 栈的长度size_t length_;
};template <typename T>
bool Stack<T>::push(T data)
{StackNode<T>* ptr = new StackNode<T>(data, ptr_);ptr_ = ptr;++length_;return true;
}template <typename T>
bool Stack<T>::pop(T& data)
{if (ptr_ == nullptr){return false;}data = ptr_->data_;StackNode<T>* ptr = ptr_;ptr_ = ptr_->next_;delete ptr;--length_;return true;
}template <typename T>
bool Stack<T>::pop()
{if (ptr_ == nullptr){return false;}StackNode<T>* ptr = ptr_;ptr_ = ptr_->next_;delete ptr;--length_;return true;
}template <typename T>
inline T Stack<T>::get_top()
{return ptr_->data_;
}template <typename T>
void Stack<T>::clear()
{while (ptr_){StackNode<T>* ptr = ptr_;ptr_ = ptr_->next_;delete ptr;}length_ = 0;
}template <typename T>
inline size_t Stack<T>::length()
{return length_;
}template <typename T>
bool Stack<T>::is_empty()
{if (ptr_){return false;}return true;
}
测试
可写出测试代码来测试代码是否正确,如下:
#include <iostream>
#include "linkstack.h" // 这里存放我们编写的栈容器using namespace std;int main(void)
{Stack<double> double_stack;Stack<int> int_stack;for (size_t i = 1; i < 10; i++){double_stack.push(i * 2.5);int_stack.push(i);}cout << "double 栈的长度:" << double_stack.length() << endl;cout << "int 栈的长度:" << int_stack.length() << endl;cout << "弹出 double 栈前5个元素\n";for (size_t i = 1; i < 5; i++){double data;double_stack.pop(data);cout << data << " ";}cout << "\ndouble 栈:我的长度变了。变成:" << double_stack.length() << endl;cout << "int 栈:我的长度没变。还是:" << int_stack.length() << endl;return 0;
}
运行结果如下:
接下来测试是否可以正确存放用户自定义类型,可定义一个平面点集如下:
注:这里不要缺省默认构造函数
class CPoint
{private:int x_;int y_;
public:CPoint(): CPoint(0, 0) {}CPoint(int x, int y): x_(x), y_(y) {}friend std::ostream& operator<<(std::ostream& out, CPoint point){out << "(" << point.x_ << "," << point.y_ << ")";return out;}
};
测试代码如下:
#include <iostream>
#include "linkstack.h" // 这里存放我们编写的栈容器using namespace std;int main(void)
{Stack<CPoint> stack_point;for (size_t i = 1; i < 10; i++){CPoint point(i, i * i);stack_point.push(point);}cout << "现在栈的长度为:" << stack_point.length() << endl;cout << "弹出所有的元素:" << endl;while (!stack_point.is_empty()){CPoint point;stack_point.pop(point);::std::cout <<point << " ";}cout << "\n现在栈的长度为:" << stack_point.length() << endl;system("pause");return 0;
}
结果如下:
这就很爽了,利用泛型使得我们的栈不仅可以存储基本数据类型,还能存储用户自定义类型。嗯,这可能就叫一次编程,终身受益吧!
数据结构-栈容器的实现相关推荐
- 数据结构栈队列链表数组
目录: 数据结构 栈(stack) 队列 链表 数组 数据结构 数据结构是什么 简单来说,数据结构就是设计数据以何种方式存储在计算机中 比如:列表,集合,与字典等都是一种数据结构 程序 = 数据结构 ...
- JVM【带着问题去学习 02】数据结构栈+本地方法栈+虚拟机栈+JVM栈运行原理
1.数据结构栈 栈是一种比较简单的数据结构,后进先出.栈本身是一个线性表,但是这个表中只有一端允许数据的进出.栈的常用操作包括入栈push和出栈pop,对应于数据的压入和弹出.由于栈后进先出的特性,常 ...
- C++STL之stack栈容器
C++STL之stack栈容器 1. 再谈栈 回顾一下之前所学的栈,栈是一种先进后出的数据结构,而实现方式需要创建多个结构体,通过链式的方式进行实现,这是标准的栈的思路,而在STL中栈可以以更为简单的 ...
- C++ STL之stack栈容器
一.STL: 1)标准模版库,提供了通用的模版库和函数.如:向量.链表.队列.栈. 2)核心组建包括:容器(Containers).算法(Algorithms).迭代器(Iterators). 二.S ...
- 数据结构——栈与队列相关题目
数据结构--栈与队列相关题目 232. 用栈实现队列 思路 225. 用队列实现栈 1.两个队列实现栈 2.一个队列实现栈 20. 有效的括号 思路 1047. 删除字符串中的所有相邻重复项 思路 1 ...
- 怎么删除结构体数组中的一组数据_数据结构-栈
数据结构-栈 1)栈的定义. 栈是只能通过访问它的一端来实数据存储和检索的一种线性数据结构,逻辑结构和线性表相同.特点在于运算有所限制:即主要特征是"后进先出"(先进后出). 在栈 ...
- php+spl+栈,PHP SPL标准库之数据结构栈(SplStack)介绍
PHP SPL标准库之数据结构栈(SplStack)介绍2020-06-13 22:01:42 栈(Stack)是一种特殊的线性表,因为它只能在线性表的一端进行插入或删除元素(即进栈和出栈) SplS ...
- 8皇后以及N皇后算法探究,回溯算法的JAVA实现,非递归,数据结构“栈”实现
是使用递归方法实现回溯算法的,在第一次使用二维矩阵的情况下,又做了一次改一维的优化 但是算法效率仍然差强人意,因为使用递归函数的缘故 下面提供另一种回溯算法的实现,使用数据结构"栈" ...
- 数据结构栈和队列_使您的列表更上一层楼:链接列表和队列数据结构
数据结构栈和队列 When you want to store several elements somewhere in a program, the go-to data type is an a ...
最新文章
- 使用jpmml-sparkml-executable生成PMML模型文件
- autosar架构详细介绍_【技术】基于AUTOSAR的电机驱动系统分析
- SQL Server数据库中、获得刚插入新记录的自动ID号
- 自定义log4j2配置文件地址
- 百度的索引真的比雅虎多么?
- 【Java】八进制那些事
- numpy-array
- __attribute__((section(name))) study again
- kmeans及模型评估指标_聚类分析的过程和两个常用的聚类算法
- DataContractJsonSerializer 没有using 类库找不到
- UITableView性能-圆角图片
- 位置变量示例_shell脚本
- 毛毛虫 树形DP
- vs2008 html5 的安装,vs2008安装教程,详细教您vs2008安装教程
- 安装oracle的时候ORA12705,解决ORA-12705无法访问NLS问题
- solr引入mysql数据库数据,出现Requests: 1, Fetched: 0, Skipped: 0, Processed: 0
- 深析 | 手机摄像产业趋势—多摄/TOF/高倍变焦或成行业新风口
- From little Cutie to Rockin Beauty(about Hilary Duff and someone concerned.)
- 微服务网关Gateway实战
- SQL Server 2008性能故障排查(三)——I/O