数据结构--2. 栈


1. 栈的定义

类似弹夹里的子弹一样先进去后出来,后进的先出来。

栈(stack)是限定仅在表尾进行插入和删除操作的线性表。

栈顶允许插入和删除的一端

栈底固定的,不允许插入和删除的另一端

栈又称为后进先出的线性表,简称LIFO结构
在这里插入图片描述

2. 栈的抽象数据模型

进栈(插入) push

出栈(删除)pop

Operation
	InitStack(*S):初始化操作,建立一个空栈S
	DestoryStack(*S):若栈存在,则销毁它
	ClearStack(*S):将栈清空
	StackEmpty(S):若栈为空,返回True,否则返回False
	GetTop(S,*e):若栈存在且非空,用e返回S的栈顶元素
	Push(*S,e):若栈S存在,插入新元素e到栈S中并成为栈顶元素
	Pop(*S,*e):删除栈S中栈顶元素,并用e返回其值。
	StackLength(S):返回栈S的元素个数

3. 栈的顺序存储结构

栈的定义:

typedef int SElemType;
typedef struct
{
	SElemType data[MAXSIZE];
	int top;//用于栈顶指针
}SqStack;
3.1 进栈push

在这里插入图片描述

//插入元素e为新的栈顶元素
Status Push(SqStack *S,SElemType e)
{
    if(S->top == MAXSIZE-1)//栈满
    {
        return ERROR;
    }
    S->top++;
    S->data[s->top] = e;
    return OK;
}
3.2 出栈pop

在这里插入图片描述

//若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR
Status Pop(SqStack *S,SElemType *e)
{
	if(S->top == -1)
        return ERROR;
    *e = S->data[S->top];//将要删除的栈顶元素赋值给e
	S->top--;//栈顶指针减一
    return OK;
}

Tips:如果我们有两个相同类型的栈,我们为他们各自开辟了数组空间,极有可能出现第一个栈满了,再进栈就溢出了,而另一个栈还有很多存储空间空闲,所以就有了两栈共享空间。

4. 两栈共享空间

简单来说,一个数组有两个端点,而两个栈有两个栈底,一个栈的栈底为数组的始端,即下标为0处,另一个栈的的栈底为数组的尾端,两个栈由两个端点向中间延伸。

通常适用于一个栈增长时另一个栈在缩短的情况(两个栈相同数据类型)。

在这里插入图片描述

两栈为空:0号栈:top1 = -1 1号栈:top2 = MaxSize

栈满:top1 + 1 == top2

//两栈共享空间结构
typedef struct
{
    SElemType data[MAXSIZE];
    int top1;//栈顶指针
    int top2;
}SqDoubleStack;
4.1 进栈push

需要插入元素值参数和判断是0号栈还是1号栈的栈号参数 stackNumber

//插入元素e为新的栈顶元素
Status Push(SqDoubleStack *S,SElemType e,int stackNumber)
{
    if(S->top1+1 == S->top2)//栈满
        return ERROR;
    if(stackNumber == 0)//0号栈有元素进栈
        S->data[++S->top1] = e;
    else if(stackNumber == 1)//1号栈有元素进栈
        S->data[--S->top2] = e;
}
4.2 出栈pop
Status Pop(SqDoubleStack *S,SElemType e,int stackNumber)
{
    if(stackNumber == 0)//0号栈有元素出栈
        if(S->top1 == -1)//空栈
            return ERROR;
    	*e = S->data[S->top1--];
    else if(stackNumber == 1)//1号栈有元素出栈
    {
        if(S->top2 == MAXSIZE)//空栈
            return ERROR;
        *e = S->data[S->top2++];
    }
    return OK;
}

5. 栈的链式存储结构(链栈)

在这里插入图片描述

Tips:链栈不需要头节点,且基本不存在栈满的情况(除非内存没有可以使用的空间)。

//空栈时,头指针指向空,即 top = NULL
typedef struct StackNode
{
    SELemType data;
    struct StackNode *next;
}StackNode,*LinkStackPtr;

typedef struct LinkStack
{
    LinkStackPtr top;
    int count;
}LinkStack;
5.1 进栈push

在这里插入图片描述

//插入元素e为新的栈顶元素
Status push(LinkStack *S,SElemType e)
{
    LinkStackPtr s = (LinkStackPtr)malloc(sizeof(StackNode));
    s->data = e;
    s->next = S->top;//当前的栈顶元素赋值给新结点的直接后继
    S->top = s;//新的结点s赋值给栈顶指针
    S->count++;
    return OK;
}

时间复杂度为O(1)

5.2 出栈pop

在这里插入图片描述

//若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR
Status Pop(LinkStack *S,SElemType *e)
{
    LinkStackPtr p;
    if(StackEmpty(*S))
        return ERROR;
    *e = S->top->data;
    p = S->top;//将栈顶结点赋值给p
    S->top = S->top->next;//栈顶指针下移一位
    free(p);//释放结点p
    S->count--;
    return OK;
}

时间复杂度为O(1)

6. 栈的应用:递归

6.1 斐波那契数列的实现(兔子繁殖问题)

在这里插入图片描述

//斐波那契的递归函数
int Fbi(int i)
{
    if(i<2)
        return i == 0 ? 0 : 1;
    return Fbi(i-1)+Fbi(i-2);//这里的Fbi就是函数自己,它在调用自己
}
int main()
{
    int i;
    for(int i = 0;i < 40;i++)
    {
    	printf("%d",Fbi(i));    
    }
    return 0;
}
6.2 四则表达式求值
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值