栈是一种非常常见的数据结构,包括在之后的存储中,我们会了解到很多创建的数据其实都是在栈中的。那么现在就让我演示栈的创建及入栈,出栈,取栈顶元素和判断栈是否空或是否满的操作。
本次程序均采用c++实现
1.顺序栈
顺序栈跟顺序表类似,实际上是以数组的形式实现的,他的特点是需要一整块的空间,在元素的查找上比较方便,在对栈顶的操作上也比较简便,并且顺序栈的元素个数一般是固定的,适合于用在已知元素个数的栈上。
整体代码演示
#include<iostream>
using namespace std;
const int MAX=100;
class Stack{
private:
char *data;//指针指向数组首地址
int top;//top代表栈顶
int size; //size代表栈实际大小
public:
Stack();//初始化
Stack(int s);//给定指定长度的栈,形参指的是栈元素个数
~Stack();//析构函数
void push(char ch);//入栈
char pop();//出栈并返回栈顶元素
char gettop();//返回栈顶元素
bool isempty();//判断栈是否为空
bool isfull();//判断栈是否满
};
Stack::Stack(){
top=-1;
size=MAX;
data=new char[MAX];
}
Stack::Stack(int s){
top=-1;
size=s;
data=new char[s];
}
Stack::~Stack(){
delete []data;
}
void Stack::push(char ch){
if(!isfull()){
top++;
data[top]=ch;
}
}
char Stack::pop(){
if(!isempty()){
return data[top];
top--;
}
}
char Stack::gettop(){
return data[top];
}
bool Stack::isempty(){
if(top!=-1){
return 1;
}
else return 0;
}
bool Stack::isfull(){
if(top==MAX-1){
return 0;
}
else return 1;
}
int main(){
Stack s;
s.push('a');
cout<<s.pop()<<endl;
}
该程序整体没有过于复杂的地方,但有几个点需要单独拿出来说一说:在整体元素个数的声明上,需要用宏定义事先定义一个常量作为数组元素个数的最大值即本程序中使用的MAX,若没有指定元素个数则将MAX赋给size即可。
对top的处理上,top每次要成为数组的最后一个元素,因此在添加元素时,要将top的值加一,在出栈时要将top的值减一。
2.链栈
链栈跟链表类似,是使用一个个定义好的结构体用指针将他们相互连接起来,不同的是链栈不需要头节点,取而代之的是一个top指针,让它每次都指向链栈的最顶端。
对比两种数据结构,发现之间还是有很大的相似性在的。栈实际上最大的特点是top结点,因为栈是先进后出的数据结构,因此这个节点在处理上需要有不一样的操作,拿进栈来举例,如下图所示
该图能够很好的诠释插入的节点跟top节点的关系,在开始时只有top节点,让它指向空,每当需要有元素进栈时,就需要将元素放在top下面,首先开辟一个节点空间s,让s的数据域存放实参,让next指针域指向top,再将s本身赋给top,就完成了角色的位置转换,并且可以保证每次进行完入栈操作后,top始终位于最顶端。
代码演示:
#include<iostream>
using namespace std;
typedef struct node{
int data;
struct node *next;
}NODE,*PNODE;
void init(PNODE &s);//初始化
void push(PNODE &s,int a);//压栈
int pop(PNODE &s);//出栈
int gettop(PNODE &s);//取栈顶元素
int main(){
PNODE s;
init(s);
push(s,2);
push(s,3);
cout<<pop(s)<<endl;
cout<<gettop(s)<<endl;
}
void init(PNODE &s){
s=NULL;
}
void push(PNODE &s,int a){
PNODE p=new NODE;
p->data=a;
p->next=s;
s=p;
}
int pop(PNODE &s){
if(s!=NULL){
PNODE p=s;
int a=s->data;
s=s->next;
delete p;
return a;
}
}
int gettop(PNODE &s){
if(s!=NULL){
return s->data;
}
}
该程序已经说完了入栈操作,再讲一下出栈操作:出栈时要将最顶端的节点删除,在构建方法时,可以用一个结构体指针p来存储最上方节点,再将top节点往下移,即指向它的next,再将p释放,实际上还可以在形参中加一个指针变量,让它存储最上方节点的数据域,不过我懒省事没写。
总结
由以上代码可以发现。链栈没有判断栈是否空或是否满的操作,这也是链栈的特点,它可以随时添加节点,并且跟链表一样,两个相连节点的地址并不是挨在一起的。所以链栈适用于需要随时添加元素的场景,而顺序栈适用于查找,少量添加和删除元素的场景。