栈:一种数据结构,先进后出,元素一次入栈可以有多种出栈方式。栈的特有就是栈顶,和栈底,各种数据操作都在栈顶进行,所以,栈顶一般会有top用于表示栈顶指针,当栈为空时,top=-1。
一 、顺序栈:最普通的栈
#include <stdio.h>
#include <stdlib.h>
#include "math.h"
#include "time.h"
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 20 /* 存储空间初始分配量 */
typedef int Status;
typedef int Ele; //元素
//栈包含两个部分,一个是栈的元素数据,一个是栈顶指针
//遵循先进后出的原则
//当栈为空时,top=-1
//此时进栈和出栈的复杂度均为O(1)
//定义
typedef struct {
Ele data[MAXSIZE];
int top; //用于栈顶指针
}Stack;
//构造一个指向栈的指针 Stack *S
//构造一个空栈,即就是初始化
Status InitStack(Stack *S){
S->top = -1;
return OK;
}
//清空重置
Status ClearStack(Stack S){
S.top = -1;
return OK;
}
//是否为空栈
Status IsEmpty(Stack S){
if(S.top==-1){
printf("该栈为空\n");
return ERROR;
}else{
printf("该栈不为空\n");
return OK;
}
}
//获取栈的长度
int getStackLength(Stack S){
int length = S.top+1;
printf("该栈的长度为%d\n",length);
return length;
}
//遍历栈元素
Status StackVisit(Stack S){
int i =0;
printf("该栈的所有元素为:\n") ;
while(i<S.top+1){
printf("%d ",S.data[i]);
i++;
}
printf("\n");
}
//进栈操作
Status Push(Stack *S,Ele e){
if(S->top==MAXSIZE-1){
return ERROR;
}
S->top++;
S->data[S->top] = e;
return OK;
}
//出栈操作
Status Pop(Stack *S,Ele e){
if(S->top==-1){
return ERROR;
}
e = S->data[S->top];
printf("%d ",e);
S->top--;
return OK;
}
int main(){
int j;
Stack S;
Ele e;
//初始化
//进栈10个数剧
if(InitStack(&S) == OK){
for(j=1;j<=10;j++){
Push(&S,j);
}
}
StackVisit(S);
//依次出栈
if(IsEmpty(S)){
printf("出栈的顺序为:\n");
for(j=1;j<=10;j++){
Pop(&S,e);
}
printf("\n");
}
//清空重置
ClearStack(S);
IsEmpty(S);
return 0;
}
二、两栈共享:一般用于两个且数据类型都一样的栈,主要是节省空间,使得空间最大化的利用。
#include "stdio.h"
#include "stdlib.h"
#include "io.h"
#include "math.h"
#include "time.h"
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 20 /* 存储空间初始分配量 */
//两栈共享主要是利用一个数组给两个栈用,这样做的好处:
//就是节省空间,让更多空间得到充分利用
//在这里需要top1 和 top2两个栈顶指针
//进栈和出栈操作都必须用指针
typedef int Status;
typedef int Ele;
//定义
typedef struct {
Ele data[MAXSIZE];
int top1;
int top2;
}DoubleStacks;
//初始化 ,构造一个空栈
Status InitStack(DoubleStacks *S){
S->top1 = -1;
S->top2 = MAXSIZE;
return OK;
}
//重置,清空
Status ClearStack(DoubleStacks *S){
S->top1 = -1;
S->top2 = MAXSIZE;
return OK;
}
//判断是否为空
Status IsEmpty(DoubleStacks S){
if(S.top1==-1 && S.top2 == MAXSIZE){
return TRUE;
}else{
return ERROR;
}
}
//共用栈的元素个数
int StackLength(DoubleStacks S){
int length = (S.top1+1) + (MAXSIZE-S.top2);
printf("该栈的长度为:%d\n",length);
return length;
}
//进栈操作,因为这里有两个栈,所以我们要做两个栈的标志,用1 和2 来表示
Status Push(DoubleStacks *S,Ele e,int StackNumber){
//栈满的条件
if(S->top1+1 == S->top2){
printf("栈已满\n");
return ERROR;
}
if(StackNumber == 1){
S->data[++S->top1] = e; //栈1操作
}else if(StackNumber==2){
S->data[--S->top2] =e; //栈2操作
}
return OK;
}
//出栈操作
Status Pop(DoubleStacks *S,Ele e,int StackNumber){
if(StackNumber == 1){
if(S->top1 == -1){
return ERROR;
}
e = S->data[S->top1--];
}else if(StackNumber == 2){
if(S->top2==MAXSIZE){
return ERROR;
}
e = S->data[S->top2++];
}
}
//遍历栈操作
Status StackVisit(DoubleStacks S){
int i = 0;
printf("该栈的所有元素为:\n");
while(i<=S.top1){
printf("%d ",S.data[i++]);
}
i = S.top2;
while(i<MAXSIZE){
printf("%d ",S.data[i++]);
}
printf("\n");
return OK;
}
int main(){
int i;
Ele e;
DoubleStacks S;
//插入,进栈
printf("进栈后:\n");
if(InitStack(&S)==OK){
for(i=1;i<=5;i++){
Push(&S,i,1); //进栈1
}
for(i=6;i<=10;i++){
Push(&S,i,2); //进栈2
}
}
StackVisit(S);
//删除,出栈
printf("出栈后:\n");
if(!IsEmpty(S)){
for(i=0;i<3;i++){
Pop(&S,e,1); //出栈1
}
for(i=0;i<3;i++){
Pop(&S,e,2); //出栈2
}
}
StackVisit(S);
//栈的元素个数
StackLength(S);
//清空,重置
printf("清空,重置后:\n");
ClearStack(&S);
StackVisit(S);
return 0;
}
三、链栈:就是栈的链式存储结构,在单链表中需要头结点,而在这里 用了栈顶指针做了代替,对于链栈来说,不会出现栈满的情况。
链栈的空可以表示为top = NULL.
入栈:
出栈:
#include "stdio.h"
#include "stdlib.h"
#include "io.h"
#include "math.h"
#include "time.h"
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
//链栈:
// 就是栈的链式存储结构,在单链表中需要头结点,而在这里 用了栈顶指针做了代替
// 对于链栈来说,不会出现栈满的情况
//链栈的操作和单链表的操作类似,只不过这些操作是在栈顶进行。用top的变化来代替指针的变化
typedef int Status;
typedef int Ele;
//定义结构,这个也是链表的结构
typedef struct StackNode{
Ele data;
struct StackNode *next; //一个p->next指向链表结构
}StackNode,*LinkStackPtr;
typedef struct {
LinkStackPtr top; //一个栈顶指向链表结构
int count; //栈的长度
}LinkStack;
//初始化
Status InitStack(LinkStack *S){
S->top = (LinkStackPtr)malloc(sizeof(StackNode));
if(!S->top){
return ERROR;
}
S->top = NULL;
S->count = 0;
return OK;
}
//重置清空,也相当于把每一个结点清空,所以与链表的操作基本一样
Status ClearStack(LinkStack *S){
LinkStackPtr p,q; //两个指针,p为主要,q作为辅助
p = S->top; //栈顶指针指向p
while(p){
q = p;
p = p->next; //下一个结点
free(q); //释放原来的结点,即就是辅助的q
}
S->count = 0; //栈的长度 为0
return OK;
}
//判断栈是否为空
int IsEmpty(LinkStack *S){
if(S->count==0){
return 0;
}else{
return 1;
}
}
//入栈
Status Push(LinkStack *S,Ele e){
LinkStackPtr s = (LinkStackPtr)malloc(sizeof(StackNode));
s->data = e;
s->next = S->top; //把原来的栈顶指针所指向的结点赋给新的结点s的后继
S->top = s; //然后这里的栈顶指针发生变化,指向新的结点s
S->count++; //栈的长度+1
return OK;
}
//出栈
Status Pop(LinkStack *S,Ele e){
LinkStackPtr p;
if(!IsEmpty(S)){
return ERROR;
}
e = S->top->data;
printf("出栈的元素为%d\n",e);
p = S->top;
S->top = S->top->next; //此时的栈顶指针就是原来栈顶指针的下一个结点的指针
free(p);
S->count--;
return OK;
}
//遍历
Status StackVisit(LinkStack *S){
LinkStackPtr p;
p = S->top;
printf("该栈的所有元素为:\n");
if(IsEmpty(S)){
while(p){
printf("%d ",p->data);
p = p->next;
}
printf("\n");
}
return OK;
}
int main(){
int i;
LinkStack S;
Ele e;
//入栈操作
printf("入栈操作后,");
if(InitStack(&S)==OK){
for(i=1;i<=10;i++){
Push(&S,i);
}
}
StackVisit(&S);
//出栈操作
printf("出栈操作后\n");
for(i=0;i<5;i++){
Pop(&S,e);
}
StackVisit(&S);
//清空操作
printf("清空操作后\n");
ClearStack(&S);
StackVisit(&S);
return 0;
}
总的来说,根据自己需要选择适合的栈结构