数据结构之栈

栈:一种数据结构,先进后出,元素一次入栈可以有多种出栈方式。栈的特有就是栈顶,和栈底,各种数据操作都在栈顶进行,所以,栈顶一般会有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;
}

总的来说,根据自己需要选择适合的栈结构

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值