【数据结构】栈及栈的实现

目录

一、栈

      1. 栈的概念及结构

  2. 栈的表示和实现

       2.1  栈的顺序存储表示的实现

栈的初始化    

入栈操作

出栈操作

获取栈顶元素

获取栈中有效元素的个数   

 栈的判空操作  

栈的销毁

代码汇总

2.2  栈的链式存储表示的实现

初始化为空栈

入栈

出栈

栈的长度

获取栈顶元素

判断栈空

清空栈为空栈

栈的遍历

代码汇总



一、栈

      1. 栈的概念及结构

    栈(stack):是限定仅在表尾进行插入或删除操作的一种特殊的线性表。它的特殊之处就在于限制了线性表的插入和删除位置。允许插入和删除的一端称为栈顶(top),另一端称为栈底;不含任何元素的栈称为空栈。栈又称为后进先出 (Last In First Out) 的线性表,简称LIFO结构。

压栈:栈的插入操作叫做进栈/压栈/入栈。入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶。
 

  2. 栈的表示和实现

            和线性表类似,栈也有两种存储表示方法,即顺序栈(栈的顺序存储结构)链栈(栈的链式         存储结构)。这两种结构都可以实现,但相对而言数组结构更优一些。

       2.1  栈的顺序存储表示的实现

               顺序栈(栈的顺序存储结构):是利用一组地址连续的存储单元依次存放自栈底到栈顶的数          据元素,同时附设指针 top 指示栈顶元素在顺序栈中的位置。(以 top=0或top=-1来表示空          栈)。此处顺序栈的实现以 top=0来实现 

 

      对于栈的实现,此处分模块进行

        ①Stack.h    //创建头文件,这部分进行函数的声明及类型的定义

        ②Stack.c    //源文件,主要是函数的实现

   下面是所有要实现的函数的声明、类型的定义:都在头文件Stack.h中进行

//所需要包含的头文件
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>

//栈的结构定义
typedef int STDataType; //STDataType类型根据实际情况而定,这里假设为int
typedef struct Stack
{
    STDataType* a;
    int top;  //用于栈顶指针
    int capacity; //栈当前可使用的最大容量
}SqStack;

//函数的声明
//初始化栈
void SqStackInit(SqStack* ps);

//栈的销毁
void SqStackDestroy(SqStack* ps);

//入栈
void SqStackPush(SqStack* ps, STDataType x);

//出栈
void SqStackPop(SqStack* ps);

//获取栈顶元素
STDataType SqStackTop(SqStack* ps);

//获取栈中有效元素个数
int SqStackSize(SqStack* ps);

//判断栈是否为空
bool SqStackEmpty(SqStack* ps);


   

以下函数的实现均在 Stack.c中进行。

栈的初始化    
//初始化栈
void SqStackInit(SqStack* ps)
{
    assert(ps); //以防ps为空指针
    ps->a = NULL;
    ps->top = 0;  //在栈底的位置
    ps->capacity = 0; //当前最大容量初始化为0
}
入栈操作
//入栈
void SqStackPush(SqStack* ps, STDataType x)
{
    assert(ps);
    //栈满动态扩容
    if (ps->top == ps->capacity)
    {
        int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;//容量扩容
        //动态开辟空间,成功则返回空间首地址
        STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newcapacity);
        //判断空间申请是否成功,失败退出
        if (tmp == NULL)
        {
            perror("realloc fail");
            exit(-1);
        }
        ps->a = tmp;
        ps->capacity = newcapacity;
    }
    ps->a[ps->top] = x; //元素入栈
    ps->top++; //栈顶指针加一
}

      上面代码个别语句的解释如下:

      上述代码中扩容的那条语句首先需要判断当前最大容量是否为0,若为0直接扩容多大,否则扩容当前容量的2倍; 然后就是动态开辟空间此处用的是 realloc 而没有用 malloc 原因是因为此处用realloc可以避免后面由于开辟的空间不足还要使用realloc进行动态扩容。这里由于一开始数组中元素为零,此时realloc和malloc的作用相同的,因此就避免先使用malloc,在使用realloc扩容的问题 .

出栈操作
//出栈
void SqStackPop(SqStack* ps)
{
    assert(ps);
    assert(ps->top > 0); //避免为空,assert更为暴力,也可if判断
    --ps->top; //栈顶指针减一
}

获取栈顶元素
//获取栈顶元素
STDataType SqStackTop(SqStack* ps)
{
    assert(ps);
    assert(ps->top > 0); 
    return ps->a[ps->top - 1]; //将栈顶元素返回
}

    由于top指向栈底时的值为0,即top=0;top的值总比数组元素下标多一,因此,top-1指向栈顶元素

获取栈中有效元素的个数   
//获取栈中有效元素个数
int SqStackSize(SqStack* ps)
{
    assert(ps);
    return ps->top; //返回当前元素的个数
}

       

 栈的判空操作  
//判断栈是否为空
bool SqStackEmpty(SqStack* ps)
{
    assert(ps);
    return ps->top == 0;
}
栈的销毁
//栈的销毁
void SqStackDestroy(SqStack* ps)
{
    assert(ps);
    free(ps->a);
    ps->a = NULL;
    ps->top = 0;
    ps->capacity = 0;
}

 

代码汇总
//Stack.h

//所需要包含的头文件
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>

//栈的结构定义
typedef int STDataType; //STDataType类型根据实际情况而定,这里假设为int
typedef struct Stack
{
    STDataType* a;
    int top;  //用于栈顶指针
    int capacity; //栈当前可使用的最大容量
}SqStack;

//函数的声明
void SqStackInit(SqStack* ps);

void SqStackDestroy(SqStack* ps);

void SqStackPush(SqStack* ps, STDataType x);

void SqStackPop(SqStack* ps);

STDataType SqStackTop(SqStack* ps);

int SqStackSize(SqStack* ps);

bool SqStackEmpty(SqStack* ps);



//Stack.c

//初始化栈
void SqStackInit(SqStack* ps)
{
    assert(ps); 
    ps->a = NULL;
    ps->top = 0;  
    ps->capacity = 0; 
}


//入栈
void SqStackPush(SqStack* ps, STDataType x)
{
    assert(ps);

    if (ps->top == ps->capacity)
    {
        int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
        STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newcapacity);
        if (tmp == NULL)
        {
            perror("realloc fail");
            exit(-1);
        }
        ps->a = tmp;
        ps->capacity = newcapacity;
    }
    ps->a[ps->top] = x; 
    ps->top++; 
}


//出栈
void SqStackPop(SqStack* ps)
{
    assert(ps);
    assert(ps->top > 0); 
    --ps->top; 
}


//获取栈顶元素
STDataType SqStackTop(SqStack* ps)
{
    assert(ps);
    assert(ps->top > 0); 
    return ps->a[ps->top - 1]; 
}


//获取栈中有效元素个数
int SqStackSize(SqStack* ps)
{
    assert(ps);
    return ps->top; 
}


//判断栈是否为空
bool SqStackEmpty(SqStack* ps)
{
    assert(ps);
    return ps->top == 0;
}


//栈的销毁
void SqStackDestroy(SqStack* ps)
{
    assert(ps);
    free(ps->a);
    ps->a = NULL;
    ps->top = 0;
    ps->capacity = 0;
}




2.2  栈的链式存储表示的实现

        栈的链式存储结构,简称为链栈,它是运算受限的单链表,即插入和删除操作仅限制在表头(对于链式栈对应的是栈顶,即把栈顶放在单链表的头部)位置进行。既然把栈顶放在单链表的头部,那单链表中比常用的头结点也就失去了意义,通常对于链栈来说,是不需要头结点的;基本不存在栈满的情况。

        对于空栈来说,链表原定义是头指针指向空,那么链栈的空就是 top=NULL.

     

 

         对于链栈的实现与顺序栈一样分两个模块。

         函数的声明、类型的定义:  LinkStack.h       

#include <stdio.h>
#include <stdlib.h>   
#include <stdbool.h>  
#include <assert.h>


typedef int SElemType; // SElemType类型根据实际情况而定,这里假设为int 
/* 链栈结构 */
typedef struct StackNode
{
    SElemType data;
    struct StackNode* next;
}StackNode;

typedef struct
{
    StackNode* top;
    int count;
}LinkStack;


//  构造一个空栈S 
void InitStack(LinkStack* S);

//遍历并输出栈中元素
void StackTraverse(LinkStack* S);

// 把S置为空栈 
void ClearStack(LinkStack* S);

// 若栈S为空栈,则返回TRUE,否则返回FALSE 
bool StackEmpty(LinkStack* S);

// 返回S的元素个数,即栈的长度 
int StackLength(LinkStack* S);

// 若栈不空,返回栈顶元素
SElemType GetTop(LinkStack* S);

// 插入元素e为新的栈顶元素 
void StackPush(LinkStack* S, SElemType e);

// 出栈,若栈不空,则删除S的栈顶元素,并返回0;否则返回-1 
int StackPop(LinkStack* S);

  函数的实现:LinkStack.c 

初始化为空栈
void InitStack(LinkStack* S)
{
    S->top = (StackNode*)malloc(sizeof(StackNode));
    if (S->top == NULL)
    {
        perror("malloc fail");
    }
    S->top = NULL;
    S->count = 0;
}
入栈
// 插入元素e为新的栈顶元素
void StackPush(LinkStack* S, SElemType e)
{
    StackNode* s = (StackNode*)malloc(sizeof(StackNode));
    if (s == NULL)
    {
        perror("malloc fail");
        exit(-1);
    }
    s->data = e;
    s->next = S->top;	// 把当前的栈顶元素赋值给新结点的直接后继
    S->top = s;         // 将新的结点s赋值给栈顶指针
    S->count++;
}


出栈
// 出栈,若栈不空,则删除S的栈顶元素,并返回0;否则返回-1 
int StackPop(LinkStack* S)
{
    StackNode* p;
    if (StackEmpty(S))
        return -1;
    p = S->top;	           // 将栈顶结点赋值给p
    S->top = S->top->next; // 使得栈顶指针下移一位,指向后一结点
    free(p);               // 释放结点p 
    S->count--;
    return 0;
}

栈的长度
// 返回S的元素个数,即栈的长度 
int StackLength(LinkStack* S)
{
    assert(S);
    return S->count;
}

获取栈顶元素
// 若栈不空,返回栈顶元素 
SElemType GetTop(LinkStack* S)
{
    assert(S->top);
    return S->top->data;
}

判断栈空
// 若栈S为空栈,则返回TRUE,否则返回FALSE 
bool StackEmpty(LinkStack* S)
{
    if (S->count == 0)
        return true;
    else
        return false;
}

清空栈为空栈
// 把S置为空栈 
void ClearStack(LinkStack* S)
{
    StackNode* p, *q;
    p = S->top;
    while (p)
    {
        q = p;
        p = p->next;
        free(q);
    }
    S->count = 0;
}

栈的遍历
//遍历并输出栈中元素
void StackTraverse(LinkStack* S)
{
    StackNode* p;
    p = S->top;
    while (p)
    {
        printf("%d ->", p->data);
        p = p->next;
    }
    printf("\n");
}

代码汇总
//LinkStack.h

#include <stdio.h>
#include <stdlib.h>   
#include <stdbool.h>  
#include <assert.h>


typedef int SElemType; // SElemType类型根据实际情况而定,这里假设为int 
/* 链栈结构 */
typedef struct StackNode
{
    SElemType data;
    struct StackNode* next;
}StackNode;

typedef struct
{
    StackNode* top;
    int count;
}LinkStack;

 
void InitStack(LinkStack* S);

void StackTraverse(LinkStack* S);

void ClearStack(LinkStack* S);
 
bool StackEmpty(LinkStack* S);

int StackLength(LinkStack* S);

SElemType GetTop(LinkStack* S);
 
void StackPush(LinkStack* S, SElemType e);
 
int StackPop(LinkStack* S);


//

void InitStack(LinkStack* S)
{
    S->top = (StackNode*)malloc(sizeof(StackNode));
    if (S->top == NULL)
    {
        perror("malloc fail");
    }
    S->top = NULL;
    S->count = 0;
}


void StackPush(LinkStack* S, SElemType e)
{
    StackNode* s = (StackNode*)malloc(sizeof(StackNode));
    if (s == NULL)
    {
        perror("malloc fail");
        exit(-1);
    }
    s->data = e;
    s->next = S->top;	// 把当前的栈顶元素赋值给新结点的直接后继
    S->top = s;         // 将新的结点s赋值给栈顶指针
    S->count++;
}

 
int StackPop(LinkStack* S)
{
    StackNode* p;
    if (StackEmpty(S))
        return -1;
    p = S->top;	           // 将栈顶结点赋值给p
    S->top = S->top->next; // 使得栈顶指针下移一位,指向后一结点
    free(p);               // 释放结点p 
    S->count--;
    return 0;
}


int StackLength(LinkStack* S)
{
    assert(S);
    return S->count;
}


SElemType GetTop(LinkStack* S)
{
    assert(S->top);
    return S->top->data;
}

 
bool StackEmpty(LinkStack* S)
{
    if (S->count == 0)
        return true;
    else
        return false;
}


void ClearStack(LinkStack* S)
{
    StackNode* p, *q;
    p = S->top;
    while (p)
    {
        q = p;
        p = p->next;
        free(q);
    }
    S->count = 0;
}


void StackTraverse(LinkStack* S)
{
    StackNode* p;
    p = S->top;
    while (p)
    {
        printf("%d ->", p->data);
        p = p->next;
    }
    printf("\n");
}


  • 17
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值