数据结构--栈

1. 基本概念

栈是一种逻辑结构,是特殊的线性表。特殊在:

  • 只能在固定的一端操作

只要满足上述条件,那么这种特殊的线性表就会呈现一种“后进先出”的逻辑,这种逻辑就被称为栈。栈在生活中到处可见,比如堆叠的盘子、电梯中的人们、嵌套函数的参数等等。

由于约定了只能在线性表固定的一端进行操作,于是给栈这种特殊的线性表的“插入”、“删除”,另起了下面这些特定的名称:

  • 栈顶:可以进行插入删除的一端
  • 栈底:栈顶的对端
  • 入栈:将节点插入栈顶之上,也称为压栈,函数名通常为push()
  • 出栈:将节点从栈顶剔除,也称为弹栈,函数名通常为pop()
  • 取栈顶:取得栈顶元素,但不出栈,函数名通常为top()

基于这种固定一端操作的简单约定,栈获得了“后进先出”的基本特性,如下图所示,最后一个放入的元素,最先被拿出来:

2. 存储形式

栈只是一种数据逻辑,如何将数据存储于内存则是另一回事。一般而言,可以采用顺序存储形成顺序栈,或采用链式存储形成链式栈。

  • 顺序栈
    顺序存储意味着开辟一块连续的内存来存储数据节点,一般而言,管理栈数据除了需要一块连续的内存之外,还需要记录栈的总容量、当前栈的元素个数、当前栈顶元素位置,如果有多线程还需要配互斥锁和信号量等信息,为了便于管理,通常将这些信息统一于在一个管理结构体之中:
struct seqStack
{
    datatype *data; // 顺序栈入口
    int size;       // 顺序栈总容量
    int top;        // 顺序栈栈顶元素下标
};

  • 链式栈
    链式栈的组织形式与链表无异,只不过插入删除被约束在固定的一端。为了便于操作,通常也会创建所谓管理结构体,用来存储栈顶指针、栈元素个数等信息:
// 链式栈节点
typedef struct node
{
    datatype data;
    struct node *next;
}node;

// 链式栈管理结构体
struct linkStack
{
    node *top; // 链式栈栈顶指针
    int  size; // 链式栈当前元素个数
};

3. 基本操作

不管是顺序栈,链式栈,栈的操作逻辑都是一样的,但由于存储形式不同,代码的实现是不同的。下面分别将顺序栈和链式栈的基本核心操作罗列出来:

  • 顺序栈
// 顺序栈管理结构体
typedef struct 
{
    datatype *data; // 顺序栈入口
    int size;       // 顺序栈总容量
    int top;        // 顺序栈栈顶元素下标
}seqStack;


// 初始化空栈
seqStack *initStack(int size)
{
    seqStack *s = (seqStack *)malloc(sizeof(seqStack))
    if(s != NULL)
    {
        s->data = (datatype *)malloc(sizeof(datatype) * size));
        if(s->data == NULL)
        {
            free(s);
            return NULL;
        }
        s->size = size;
        s->top  = -1;
    }

    return s;
}

// 判断栈是否已满
bool isFull(seqStack *s)
{
    return s->top == s->size-1;
}

// 判断栈是否为空
bool isEmpty(seqStack *s)
{
    return s->top == -1;
}

// 入栈
bool push(seqStack *s, datatype data)
{
    if(isFull(s))
        return false;

    s->data[++s->top] = data;
    return true;
}

// 出栈
bool pop(seqStack *s, datatype *pm)
{
    if(top(s, pm) == false)
        return false;

    s->top--;
    return true;
}

// 取栈顶元素
bool top(seqStack *s, datatype *pm)
{
    if(isEmpty(s))
        return false;

    *pm = s->data[s->top];
    return true;
}
  • 链式栈
// 链式栈节点
typedef struct node
{
    datatype data;
    struct node *next;
}node;

// 链式栈管理结构体
typedef struct linkStack
{
    node *top; // 链式栈栈顶指针
    int  size; // 链式栈当前元素个数
}linkStack;

// 初始化空栈
linkStack * initStack(void)
{
	linkStack * s = (linkStack *)malloc(sizeof(linkStack));
    if(s != NULL)
    {
        s->top  = NULL;
        s->size = 0;
    }
	return s;
}

// 判断栈是否为空
bool isEmpty(linkStack *s)
{
	return (top->size == 0);
}

// 入栈
bool push(linkStack *s, datatype data)
{
    // 创建链表节点
    node *new = (node *)malloc(sizeof(node));
	if(new == NULL)
		return false;

	new->data = data;

    // 将节点置入栈顶
	new->next = s->top;
	s->top = new;

    // 更新栈元素个数
    s->size++;
	return true;
}

// 出栈
bool pop(linkStack *s, datatype *pm)
{
	if(isEmpty(s))
		return false;

	linkStack *tmp = s->top;

    // 将原栈顶元素剔除出栈
	s->top    = tmp->next;
    tmp->next = NULL;

    // 返回栈顶元素,并释放节点
    *pm = tmp->data;
	free(tmp);

	return true;
}

// 取栈顶元素
bool top(linkStack *s, datatype *pm)
{
	if(isEmpty(s))
		return false;

    // 返回栈顶元素
    *pm = s->top->data;
	return true;
}
  • 13
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我不吃辣。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值