栈的定义
1、栈是操作被限制的线性表,栈底不能操作,入栈和出栈的操作都在栈顶,一般用数组来表示,栈底就是下标为0的数组元素,另一头为栈顶。
2、栈分为两种,顺序栈和链栈,最主要的是顺序栈。
3、栈符合先进后出,后进先出的规则
一、顺序栈
1、结构
顺序栈的结构包含了数据项(数组)和指针项(数组下标),指针项称为栈顶指针top,通常栈顶指针top指向栈顶元素,那么就可以推出当栈顶指针top=(-1)时是个空栈。
2、顺序栈的操作
(1)栈结构的定义
typedef struct//栈体的定义
{
int num[MAXSIZE];//栈元素的存储
int top;//栈顶指针,为-1时为空栈,等于MAXSIZE-1时为满栈
}Sequen;
(2)栈的初始化操作
Sequen* Init(void)//栈的初始化,包括栈结构的内存申请,栈顶指针的初始赋值,返回栈结构的地址
{
Sequen *st=(Sequen*)malloc(sizeof(Sequen));//申请结构体的空间大小,并把地址赋给st,申请失败会返回0
st->top=-1;
return st;
}
(3)入栈
void pushsstack(Sequen* st,int data)//入栈
{
if(!st || st->top==MAXSIZE-1)//判断栈结构是申请到空间或者是否满栈
{
printf("满了或没有栈体\n");
return;
}
st->top++;//将栈顶指针往后移动一位
st->num[st->top]=data;//将入栈的元素放入栈顶中
return;
}
(4)出栈
int popsstack(Sequen* st)//出栈
{
int i;
if(!st || st->top==-1)//判断栈结构是申请到空间或者是否空栈
{
printf("满了或没有栈体\n");
return 0;
}
i=st->num[st->top];//将要出栈的元素保存在i中
st->top--;//栈顶指针往前移动一位
return i;
}
(5)取栈顶元素
int qusstack(Sequen* st)//取栈顶元素
{
int i;
if(!st || st->top==-1)
{
printf("满了或没有栈体\n");
return 0;
}
i=st->num[st->top];//注意:此时不需要改变栈顶的指针位置
return i;
}
(6)判断栈空
void kosstack(Sequen* st)//判断空栈
{
if(st->top==-1)//如果栈顶指针等于-1则
{
printf("空\n");
}
else if(!st)//如果没有申请成功栈体则
printf("没有栈体\n");
return;
}
(7)清除栈
void clearsstack(Sequen* st)//清除栈
{
st->top=-1;//将栈顶指针复位-1
return;
}
(8)栈的调试
void main()
{
int i;
Sequen* st;//定义栈体指针
st=Init();//栈的初始
kosstack(st);//判断栈空,此时应该为空
pushsstack(st,100);//入栈
i=popsstack(st);//出栈
pushsstack(st,200);//入栈
i=qusstack(st);//取栈顶元素
printf("%d \n",i);
}
3、总程序
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 5
typedef struct//栈体的定义
{
int num[MAXSIZE];//栈元素的存储
int top;//栈顶指针,为-1时为空栈,等于MAXSIZE-1时为满栈
}Sequen;
Sequen* Init(void)//栈的初始化,包括栈结构的内存申请,栈顶指针的初始赋值,返回栈结构的地址
{
Sequen *st=(Sequen*)malloc(sizeof(Sequen));//申请结构体的空间大小,并把地址赋给st,申请失败会返回0
st->top=-1;
return st;
}
void pushsstack(Sequen* st,int data)//入栈
{
if(!st || st->top==MAXSIZE-1)//判断栈结构是申请到空间或者是否满栈
{
printf("满了或没有栈体\n");
return;
}
st->top++;//将栈顶指针往后移动一位
st->num[st->top]=data;//将入栈的元素放入栈顶中
return;
}
int popsstack(Sequen* st)//出栈
{
int i;
if(!st || st->top==-1)//判断栈结构是申请到空间或者是否空栈
{
printf("满了或没有栈体\n");
return 0;
}
i=st->num[st->top];//将要出栈的元素保存在i中
st->top--;//栈顶指针往前移动一位
return i;
}
int qusstack(Sequen* st)//取栈顶元素
{
int i;
if(!st || st->top==-1)
{
printf("满了或没有栈体\n");
return 0;
}
i=st->num[st->top];//注意:此时不需要改变栈顶的指针位置
return i;
}
void kosstack(Sequen* st)//判断空栈
{
if(st->top==-1)//如果栈顶指针等于-1则
{
printf("空\n");
}
else if(!st)//如果没有申请成功栈体则
printf("没有栈体\n");
return;
}
void clearsstack(Sequen* st)//清除栈
{
st->top=-1;//将栈顶指针复位-1
return;
}
void main()
{
int i;
Sequen* st;//定义栈体指针
st=Init();//栈的初始
kosstack(st);//判断栈空,此时应该为空
pushsstack(st,100);//入栈
i=popsstack(st);//出栈
pushsstack(st,200);//入栈
i=qusstack(st);//取栈顶元素
printf("%d \n",i);
}
二、链栈
1、结构
链栈就是链表,将链表的头指针看成栈顶指针,去掉头节点,用链表的头插法实现栈的出入即可
2、链栈的操作
(1)栈节点结构及栈的维护定义
//定义链的节点的结构体
typedef struct linkst
{
int data;//数据域
struct linkst *next;//指针域
}Listnode;
//链栈的维护结构
typedef struct
{
int num;//栈的计数
struct linkst *top;//栈顶指针
}safeg;
(2)栈的初始化操作
safeg* Init()//返回的是维护结构的地址
{
safeg* st=(safeg*)malloc(sizeof(safeg));//申请维护结构内存
st->num=0;//将栈元素的计数清0
st->top=NULL;//栈顶指针指向NULL,避免野指针
return st;//返回维护结构的地址
}
(3)入栈
void pushstack(safeg *st,int n)//输入维护(操作)的结构体地址和入栈的数据
{
Listnode* tmp;//定义一个指向结构体节点的指针
if(!st)//如果申请的维护结构失败了,没钱不干了
{
printf("链栈的维护结构未创建\n");
return;
}
tmp =(Listnode*)malloc(sizeof(Listnode));//申请链的节点的内存
if(st->num==0 || st->top==NULL)//如果是空栈,即第一次入栈
{
st->top=tmp;//先将栈顶指针 指向新申请的第一个节点地址
tmp->data=n;//将入栈的数据放入第一个节点
tmp->next=NULL;//头插法,将第一个的节点的指针域置为NULL
st->num++;//将栈计数器加一
return;//函数返回
}
else//不是第一次入栈
{
tmp->data=n;//将入栈的数据放入节点
tmp->next=st->top;//将新的节点的指针域指向栈顶指针
st->top=tmp;//将栈顶指针指向新的节点
st->num++;//将栈计数器加一
}
}
(4)出栈
int popstack(safeg *st)//返回出栈的数据
{
int i;
Listnode* tmp;//定义结构体节点的指针
if(!st || st->num==0 || st->top==NULL)//判断是否申请了维护结构的内存或者为空栈
{
printf("非法!\n");
return 0;
}
tmp=st->top;//将结构体的指针指向栈顶指针同个地址(要出栈的地址)
i=tmp->data;//将要出栈的数据保存
st->top=tmp->next;//将栈顶指针移向下一个链节点
(st->num)--;//将栈计数器减一
tmp->next=NULL;//将出栈节点的指针域指向NULL
free(tmp);//释放出栈的节点
tmp=NULL;//避免野指针
return i;//返回出栈节点的数据
}
(5)取栈顶元素
//取栈顶元素
int getstack(safeg *st)//和出栈类似,但是栈顶指针不用移动
{
int n;
if(!st || (st->top==NULL) || st->num==0)
{
printf("非法!\n");
return 0;
}
n=(st->top)->data;
return n;
}
(6)判断栈空
void kostack(safeg *st)
{
if(!st || (st->top==NULL) || st->num==0)
{
printf("非法!\n");
}
}
(7)清除栈
void clearstack(safeg *st)
{
Listnode *p1,*p2;//定义两个链节点的指针
if(!st || (st->top==NULL) || st->num==0)//判栈空
{
return;
}
p1=st->top;//将p1指向栈顶指针的节点地址(要删除的节点地址)
p2=p1->next;//p2指向下一个节点
while(p1!=NULL)//只要栈顶指针不为空
{
st->top=p2;//将栈顶指针移动到下一个节点位置
p1->next=NULL;//将要删除节点的指针域指向NULL1
free(p1);//释放要删除的节点
p1=NULL;//避免野指针
p1=p2;
if(p2) p2=p1->next;//如果p2指向不为NULL,则将p2移动到下一个节点
else p2=NULL;//否则,p2为NULL
st->num--;//将栈计数器减一
}
}
(8)栈的调试
void main()
{
int i,n;
safeg* st;
st=Init();
pushstack(st,100);
pushstack(st,200);
pushstack(st,300);
printf("栈的元素个数:%d\n",st->num);
/*for(i=0;i<4;i++)
{
n=popstack(st);
printf("%d ",n);
}*/
clearstack(st);
printf("栈的元素个数:%d\n",st->num);
}
三、总程序
#include<stdio.h>
#include<stdlib.h>
//定义链的节点的结构体
typedef struct linkst
{
int data;//数据域
struct linkst *next;//指针域
}Listnode;
//链栈的维护结构
typedef struct
{
int num;//栈的计数
struct linkst *top;//栈顶指针
}safeg;
//链栈维护的初始化
safeg* Init()//返回的是维护结构的地址
{
safeg* st=(safeg*)malloc(sizeof(safeg));//申请维护结构内存
st->num=0;//将栈元素的计数清0
st->top=NULL;//栈顶指针指向NULL,避免野指针
return st;//返回维护结构的地址
}
//入栈
void pushstack(safeg *st,int n)//输入维护(操作)的结构体地址和入栈的数据
{
Listnode* tmp;//定义一个指向结构体节点的指针
if(!st)//如果申请的维护结构失败了,没钱不干了
{
printf("链栈的维护结构未创建\n");
return;
}
tmp =(Listnode*)malloc(sizeof(Listnode));//申请链的节点的内存
if(st->num==0 || st->top==NULL)//如果是空栈,即第一次入栈
{
st->top=tmp;//先将栈顶指针 指向新申请的第一个节点地址
tmp->data=n;//将入栈的数据放入第一个节点
tmp->next=NULL;//头插法,将第一个的节点的指针域置为NULL
st->num++;//将栈计数器加一
return;//函数返回
}
else//不是第一次入栈
{
tmp->data=n;//将入栈的数据放入节点
tmp->next=st->top;//将新的节点的指针域指向栈顶指针
st->top=tmp;//将栈顶指针指向新的节点
st->num++;//将栈计数器加一
}
}
//出栈
int popstack(safeg *st)//返回出栈的数据
{
int i;
Listnode* tmp;//定义结构体节点的指针
if(!st || st->num==0 || st->top==NULL)//判断是否申请了维护结构的内存或者为空栈
{
printf("非法!\n");
return 0;
}
tmp=st->top;//将结构体的指针指向栈顶指针同个地址(要出栈的地址)
i=tmp->data;//将要出栈的数据保存
st->top=tmp->next;//将栈顶指针移向下一个链节点
(st->num)--;//将栈计数器减一
tmp->next=NULL;//将出栈节点的指针域指向NULL
free(tmp);//释放出栈的节点
tmp=NULL;//避免野指针
return i;//返回出栈节点的数据
}
//取栈顶元素
int getstack(safeg *st)//和出栈类似,但是栈顶指针不用移动
{
int n;
if(!st || (st->top==NULL) || st->num==0)
{
printf("非法!\n");
return 0;
}
n=(st->top)->data;
return n;
}
//判断栈空
void kostack(safeg *st)
{
if(!st || (st->top==NULL) || st->num==0)
{
printf("非法!\n");
}
}
//清除栈
void clearstack(safeg *st)
{
Listnode *p1,*p2;//定义两个链节点的指针
if(!st || (st->top==NULL) || st->num==0)//判栈空
{
return;
}
p1=st->top;//将p1指向栈顶指针的节点地址(要删除的节点地址)
p2=p1->next;//p2指向下一个节点
while(p1!=NULL)//只要栈顶指针不为空
{
st->top=p2;//将栈顶指针移动到下一个节点位置
p1->next=NULL;//将要删除节点的指针域指向NULL1
free(p1);//释放要删除的节点
p1=NULL;//避免野指针
p1=p2;
if(p2) p2=p1->next;//如果p2指向不为NULL,则将p2移动到下一个节点
else p2=NULL;//否则,p2为NULL
st->num--;//将栈计数器减一
}
}
//主函数
void main()
{
int i,n;
safeg* st;
st=Init();
pushstack(st,100);
pushstack(st,200);
pushstack(st,300);
printf("栈的元素个数:%d\n",st->num);
/*for(i=0;i<4;i++)
{
n=popstack(st);
printf("%d ",n);
}*/
clearstack(st);
printf("栈的元素个数:%d\n",st->num);
}