【数据结构——栈】个人总结摘要(C++版)
目录
一、 栈的基本概念
1.栈的定义
栈(Stack)是只允许在一端进行插入或者删除的线性表。首先,栈是一种线性表,限定这种线性表只能在某一端进行插入和删除操作。
栈顶(Top),线性表只允许进行插入删除操作的那一端。
栈底(Bottom),是栈的另一端,不允许进行插入删除操作的那一端。
空栈,即为不含任何元素的空表。
如上图(1.1),a1为栈底元素,a7为栈顶元素。由于只能在栈顶进行插入和删除,所以入栈顺序依次为a1,a2,a3,a4,a5,a6,a7,而出栈顺序为a7,a6,a5,a4,a3,a2,a1。由此可见,栈的操作特性为后进先出。
2.栈的顺序存储结构
栈类似于线性表,也有对应的两种存储方式,即顺序存储和链式存储。
(1) 栈的初始化
采用顺序存储的栈称为顺序栈,其利用一组地址连续的存储的单元(可理解为数组)存放自栈底到栈顶的数据元素,用一个标记top指向栈顶,栈的初始化即为空栈,栈中无任何元素,故初始化top为-1。
template<class DataType>
SeqStack<DataType>::SeqStack()
{
top=-1;
}
(2) 入栈
入栈 ,若栈未满,则将要插入的元素放入栈顶,此后再进入元素,栈顶标记加1后放入元素。
template<class DataType>
void SeqStack<DataType>::input(DataType x)
{
if(top==StackSize) cout<<"Stack is full"<<endl; //StackSize为栈的最大长度
else
{
top++;
data[top]=x; //存放栈的数组,则入栈依次为data[0],data[1],...,data[StackSize]
}
}
(3) 出栈
若栈不为空则取栈顶元素值,然后将top-1。
出栈是移动栈顶标记,并且输出,移动标记top后,栈顶元素相当于删除,故若想输出栈顶可用两种方法:
* 调用取栈顶函数(见下文),输出栈顶元素,然后移动标记top。
* 下面代码段实际包括了取栈顶函数,具体为
- 定义一个变量暂存栈顶元素
- 移动top(出栈需删除栈顶元素)
- 返回栈顶元素
template<class DataType>
DataType SeqStack<DataType>::output()
{
if(top==-1) cout<<"Stack is empty"<<endl;
else
{
DataType temp; //暂存栈顶元素
temp=top[top];
top--; //栈顶标记-1
return temp; //返回栈顶,即出栈
}
}
(4) 判空
此操作较简单,栈顶标记为-1则为空。
template<class DataType>
bool SeqStack<DataType>::empty()
{
if(top==-1) return true; //true是空
else return false; //非空
}
(5) 取栈顶元素
栈不为空则直接返回栈顶元素,标记top不需要移动
template <class DataType>
DataType SeqStack<DataType>::getpop()
{
return data[top];
}
(6)主函数及头文件声明
#include<iostream> //本例采用C++模板机制
using namespace std;
#define StackSize 20
template <class DataType>
class SeqStack
{
private:
DataType data[StackSize];
int top;
public:
SeqStack();
~SeqStack(){};
void input(DataType x);
DataType output();
bool empty();
DataType getpop();
};
//主函数可根据需要自行修改,与其他代码段拼接即可运行
int main()
{
SeqStack<int> l;
int n,m;
cin>>n;
try{
for(int i=0;i<n;i++)
{
cin>>m;
l.input(m);
}
if(l.empty()==1) cout<<"Stack is empty;"<<endl;
else
{
cout<<l.getpop()<<endl;
cout<<l.output()<<endl;
cout<<l.getpop()<<endl;
}
}
catch(char *str){cout<<str<<endl;}
return 0;
}
3.栈的链式存储结构
链栈与单链表类似,本例采用不带头结点的链表实现链栈。
是否带头结点的链表在具体操作上会有不同,带有头结点的链表是初始化一个空结点,不带头结点的链表是通过一个指针指向第一个结点。
栈采用链式存储,便于结点的插入与删除,且不存在栈满上溢的情况。
(1) 链栈的初始化
建立一个头指针,将头指针指向空,此时栈顶为空值。
LinkStack() //构造函数,链栈的初始化
{
head = NULL; //头指针指向空,此时栈顶为空值
}
(2) 入栈
template<class DataType>
void LinkStack<DataType>::push(DataType x)
{
Node<DataType>* s;
s = new Node<DataType>;
s->data = x;
s->next = head;
head = s; //头指针指向第一个结点,即栈顶,head始终指向栈顶
}
(3) 出栈
出栈原理类似于上文顺序栈,这里就不多赘述了。代码如下:
template<class DataType>
void LinkStack<DataType>::pop()
{
if (head == NULL) cout << "LinkStack is empty" << endl;
else
{
Node<DataType>* temp;
DataType topdata;
temp = head; //暂存要删除的栈顶
topdata = temp->data; //保存要出栈的元素值
head = head->next; //栈顶指针指向下一个结点
delete temp; //删除栈顶
}
}
(4) 取栈顶元素
template<class DataType>
DataType LinkStack<DataType>::Gettop()
{
if (head == NULL) cout << "LinkStack is empty" << endl;
else
{
return head->data;
}
}
(5) 判空
此操作较简单,栈顶==NULL则为空。
template<class DataType>
bool LinkStack<DataType>::empty()
{
if (head == NULL) return true;
else return false;
}
(6) 主函数及头文件声明
#include<iostream>
using namespace std;
template<typename DataType>
struct Node
{
DataType data;
Node<DataType>* next;
};
template<class DataType>
class LinkStack
{
private:
Node<DataType>* head; //不带头结点的链栈
public:
LinkStack() { head = NULL; } //头指针指向空,此时栈顶为空值
void push(DataType x);
void pop();
DataType Gettop();
bool empty();
};
//以上各段操作放在类定义与主函数之间
#include<iostream>
#include"标头.h"
using namespace std;
int main()
{
LinkStack<int> l;
int data, n;
cout << "输入入栈个数: ";
cin >> n;
for (int i = 0; i < n; i++)
{
cout << "输入第 " << i+1 << " 个数据: ";
cin >> data;
l.push(data);
}
cout << "栈是否为空: ";
cout << l.empty() << endl;
if (!l.empty())
{
cout << "输出栈顶数据:";
cout << l.Gettop() << endl;
cout << "输出出栈后的栈顶数据:";
l.pop();
cout << l.Gettop() << endl;
}
return 0;
}
4.C++库函数——栈的快捷使用
库函数在使用时需声明头文件,栈的头文件是"#include<stack>",之后在定义栈时,与类模板相似,声明方式为"stack<DataType数据类型>+名称"。
*调用函数进行栈的操作,具体如下:
//例如要定义的栈为:
stack<int> s;
int x; //x为要入栈的数据
-s.push(x); //压栈函数" XXX.push(x); ",无返回值,可直接调用
-s.pop(x); //出栈函数" XXX.pop(x); ",无返回值,可直接调用
-s.top(x); //取栈顶函数" cout<<XXX.top(x); ",有返回值,为栈顶元素,得赋值给一个变量或直接输出
-s.empty(); //判断栈是否为空函数" cout<<XXX.empty();",不需要传参,但有返回值,返回值为1,表示该栈为空,为0表示该栈不为空
以下为具体使用示例:
#include<iostream>
#include<stack> //注意此处
using namespace std;
int main()
{
stack<int> s;
int n,i,x;
cin>>n; //要入栈的数据个数
for(i=0;i<n;i++)
{
cin>>x;
s.push(x);
}
if(s.empty()) cout<<"Stack is empty"<<endl; //如果栈是空,输出提示信息
else
{
cout<<s.top()<<endl; //输出栈顶元素
s.pop(); //进行出栈操作
cout<<s.top()<<endl; //之后查看栈顶
}
return 0;
}
小伙伴们,因为我本身也在学习数据结构中,此系列文章也作为笔记记录分享给大家,如有错误希望各位指正,我会继续努力,提高自己水平。
注:
参考书籍《2022年数据结构考研复习指导》,王道论坛组 编。