栈(stack)是简单的数据结构,但在计算机中使用很广泛,它的定义很简单:只允许在一端进行插入或删除操作的线性表,所以首先栈是一种线性表,其次栈限定只能在某一端进行插入和删除操作。
我们来举一个形象的例子,当我们往箱子里放一叠书的时候,先放的书在箱子最下面,后放的书在箱子上面,当我们拿书的时候,必须将后面放的书都取出来,才能看到或者拿出前面放的书。假如这个箱子的平面面积只能容纳一本书,并且所有书的面积也完全契合箱子的平面面积,放书的时候只能平着放,不能竖着放(程序员考虑的问题就比较多),那么我们就可以把这个箱子看成一个栈
接下来我们给几个定义:
栈顶(Top):允许进行插入删除操作的一端,也即是箱子的顶部;
栈底(Bottom):固定并且不允许进行插入和删除操作的一端,也就是箱子的底部;
空栈:不含有任何元素的空表。
自己编了一个stack容器,基本功能如下:
//init:初始化一个空栈;
//empty:判断一个栈是否为空,若为空返回true,否则返回false;
//push(x):进栈,若栈未满则将x加入并使之成为新栈顶;
//pop():出栈,若栈非空则弹出栈顶元素;
//top():访问栈顶元素;
//destroy:销毁栈并释放栈占用的存储空间
//.hpp头文件
#pragma once
//init:初始化一个空栈;
//empty:判断一个栈是否为空,若为空返回true,否则返回false;
//push(x):进栈,若栈未满则将x加入并使之成为新栈顶;
//pop():出栈,若栈非空则弹出栈顶元素;
//top():访问栈顶元素;
//destroy:销毁栈并释放栈占用的存储空间
template <class T>
class stack {
public:
stack(int c_capacity)
{
capacity=c_capacity;
size = -1;
data = new T [c_capacity];
cout << "构造函数" << endl;
}
~stack()
{
if(this->data!=NULL)
{
delete[] this->data;
this->data = NULL;
cout << "析构函数" << endl;
}
}
bool empty();
void push(T c_data);
void pop();
void top();
void destroy(){}
private:
int capacity;
int size;
T *data;
};
template <class T>
bool stack<T>::empty()
{
return size == -1;
}
template <class T>
void stack<T>::push(T c_data)
{
if (this->size!=this->capacity-1)
{
data[++size] = c_data;
}
else
cout << "溢出!" << endl;
}
template <class T>
void stack<T>::pop()
{
if (empty())
cout << "容器已是空!" << endl;
else
this->size--;//让size减1即可,后期就访问不到了
}
template <class T>
void stack<T>::top()
{
if(empty())
cout << "容器已是空!" << endl;
else
cout << this->data[size]<<endl;
}
#include<iostream>
#include<string>
using namespace std;
#include"stack.hpp"
void test()
{
stack<string> s(10);
s.push("赵");
s.push("钱");
s.push("孙");
s.push("李");
s.push("周");
bool ret=s.empty();
cout << boolalpha << ret << endl;
s.pop();
s.top();
}
int main()
{
test();
return 0;
system("pause");
}
C++的STL已经帮我们通过容器适配器(container adaptors)实现好了一个功能完善的栈结构,它使用的是特定容器类的封装对象作为底层容器,并且提供了一组特定的成员函数来访问其元素,主要有以下接口:
- top():返回一个栈顶元素的引用,类型为 T&。如果栈为空,返回值未定义。
- push(const T& obj):可以将对象副本压入栈顶。这是通过调用底层容器的 push_back() 函数完成的。
- push(T&& obj):以移动对象的方式将对象压入栈顶。这是通过调用底层容器的有右值引用参数的 push_back() 函数完成的。
- pop():弹出栈顶元素。
- size():返回栈中元素的个数。
- empty():在栈中没有元素的情况下返回 true。
- emplace():用传入的参数调用构造函数,在栈顶生成对象。
emplace操作是C++11新特性,新引入的的三个成员emlace_front、empace 和 emplace_back,这些操作构造而不是拷贝元素到容器中,这些操作分别对应push_front、insert 和push_back,允许我们将元素放在容器头部、一个指定的位置和容器尾部
注意栈不能遍历!
当调用insert时,我们将元素类型的对象传递给insert,元素的对象被拷贝到容器中,而当我们使用emplace时,我们将参数传递元素类型的构造函数,emplace使用这些参数在容器管理的内存空间中直接构造元素。
例子
假定d是一个Date类型的容器。
//使用三个参数的Date构造函数,在容器管理的内存空间中构造新元素。
d.emplace_back(“2016”,”05”,”26”);//错误,push_back没有这种用法
d.push_back(“2016”,”05”,”26”);//push_back()创建一个临时对象,然后将临时对象拷贝到容器中
d.push_back(Date(“2016”,”05”,”26”));通过例子发现,使用C++11新特性emplace向容器中添加新元素,在容器管理的内存空间中构造新元素,与insert相比,省去了构造临时对象,减少了内存开销。
- swap(stack<T> & other_stack):将当前栈中的元素和参数中的元素交换。参数所包含元素的类型必须和当前栈的相同。对于 stack 对象有一个特例化的全局函数 swap() 可以使用。
此函数用于将一个堆栈的内容与另一个相同类型的堆栈交换,但是大小可能会有所不同