栈(stack)(数据结构与算法基础)

目录

栈(stack)

栈与一般线性表的区别

思考

顺序栈

顺序栈的定义

顺序栈的初始化

顺序栈的销毁

判断顺序栈是否为空

求顺序栈的长度

取栈顶元素

清空顺序栈

顺序栈的入栈

顺序栈出栈

链栈

链栈的定义

链栈的初始化

判断链栈是否为空

取栈顶元素

链栈的入栈

链栈的出栈


栈(stack)

特点

  • 是一个特殊的线性表,是限定仅在一端(通常是表尾)进行插入和删除操作的线性表。

  • 又称为 后进先出(Last In First Out)的线性表,简称LIFO结构。

  • 表尾称为 栈顶 Top,表头称为 栈底 Base。

  • 插入元素到 栈顶 的操作,称为 入栈。(压栈)(PUSH)

  • 栈顶 删除最后一个元素的操作,称为 出栈。(弹栈)(POP)

逻辑结构

  • 与线性表相同,仍为一对一关系。

存储结构

  • 顺序栈或链栈,顺序栈更常见。

实现方式

  • 主要是入栈和出栈函数,链栈和顺序栈不同。

栈与一般线性表的区别

一般线性表
逻辑结构一对一一对一
存储结构顺序表、链表顺序栈、链栈
运算规则随机存取后进先出(LIFO)

思考

  • 假设有3个元素a,b,c,入栈顺序是a,b,c,则出栈顺序有几种可能?

  • 利用栈实现进制转换(如十进制数转换为八进制数)。

  • 扩号匹配的检验(括号的顺序、数量检查)(假设只有圆括号和方括号)。

顺序栈

栈的顺序存储:同一般线性表的顺序存储结构完全相同。利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素。栈底一般在低地址端。

  • 附设 top 指针,指示栈顶元素在顺序栈中的位置。

  • 另设 base 指针,指示栈底元素在顺序栈中的位置。

    但是,为了方便操作,通常top指示真正的 栈顶元素之上 的下标地址。

  • 另外,用stacksize表示栈可使用的最大容量。

使用数组作为顺序栈存储方式的特点:

简单、方便、但容易产生溢出(数组大小固定)。

上溢(overflow):栈已经满,又要压入元素。是一种错误,使问题处理无法进行。

下溢(underflow):栈已经空,还要弹出元素。一般不认为是错误,而是一种结束条件,即问题处理结束。

顺序栈的定义

 #define MAXSIZE 100
 typedef struct {
     SElemType *base;    //栈底指针
     SElemType *top;     //栈顶指针
     int stacksize;      //栈的最大容量
 } SqStack;

但是顺序栈的top和base指针可以是 int 类型 用来存放数组下标,并不是真正意义上的指针变量。

存数组单元的地址也可以,在做一些操作时(比如top-base,得到的值是两个数组单元的距离),和存放下标的方式区别不大。

顺序栈的初始化

算法思路:

  1. 开辟一片大小为stacksize的空间

  2. top和base都指向栈底

算法描述:

 Status InitStack(SqStack &S) {  //构造一个空栈
     S.base = new SElemType[MAXSIEZE];
     //或S.base = (SElemType*)malloc(MAXSIZE*sizeof(SElemType));
     if(!S.base) exit (OVERFLOW);    //存储分配失败
     S.top = S.base; //栈顶指针等于栈底指针
     S.stacksize = MAXSIZE;
     return OK;
 }

顺序栈的销毁

算法思路:

  • 把整个栈空间释放掉

    1. 释放掉base指向的空间

    2. 把stacksize设置为0

算法描述:

 Status DestroyStack(SqStack &S) {
     if(S.base) {
         delete S.base;
         S.stacksize = 0;
         S.base = S.top = NULL;
     }
     return OK;
 }

判断顺序栈是否为空

算法思路:

  • top指针和base指针都指向栈底,此时top == base

算法描述:

 Status StackEmpty(SqStack S) {
         //若栈为空,返回TRUE,否则返回FALSE
     if(S.top == S.base)
         return TRUe;
     else
         return FALSE;
 }

求顺序栈的长度

算法思路:

  • 指针相减,差为两个指针的间隔,也就是元素个数。

算法描述:

 int StackLength(SqStack S) {
     return S,top - S.base;
 }

取栈顶元素

算法思路:

  1. 判断栈是否存在并且非空

  2. 返回栈顶元素

算法描述:

 Status GetTop(S, &e) {
     if(S.top == S.base) return ERROR;
     e = *(S.top-1);
     return OK;
 }

清空顺序栈

算法思路:

  • 把栈当作是空就行了,也就是top也指向栈底位置。

算法描述:

 Status ClearStack(SqStack S) {
     if(S.base) S.top = S.base;
     return OK;
 }

顺序栈的入栈

算法思路

  1. 判断是否栈满,若满则出错(上溢)

  2. 将元素存到top所指的位置

  3. top上移

算法描述:

 Status Push(SqStack &S, SElemType e) {
     if(S.top - S.base == S.stacksize)   //栈满
         return ERROR;
     *S.top++ = e;       //(*S.top=e;S.top++;)
     return OK;
 }

顺序栈出栈

算法思路:

  1. 判断是否栈空,若空则出错(下溢)

  2. top下移

  3. 取top指针所指位置上的元素

算法描述:

Status Pop(SqStack &S, SElemType &e) {
    //若栈不空,则“删除”栈顶元素,用e返回,“删除”成功返回OK,失败返回ERROR
   	if(S.top == S.base) //if(StackEmpty(S))
    	return ERROR;
    e = *--S.top;	//--S.top;e = *S.top;
  	 return OK;
}

链栈

逻辑都是相似的。

  • 链栈是运算受限的单链表,只能在链表头部进行操作。

几个注意的点:

  • 链表的头指针就是栈顶

  • 不需要头结点

  • 基本不存在栈满的情况

  • 空栈相当于头指针指向空

  • 插入和删除仅在栈顶处执行

链栈的定义

typedef struct StackNode {
    SElemType data;
    struct StackNode *next;
} StackNode, *LinkStack;
LinkStack S;

如同定义单链表。

链栈的初始化

算法描述:

void InitStack(LinkStack &S) {
    //构造一个空栈,栈顶指针置空
    S = NULL;
    return OK;
}

判断链栈是否为空

算法思路:

  • 头指针不指向任何元素时为空

算法描述:

Status StackEmpty(LinkStack S) {
    if(S == NULL) return TRUE;
    else return FALSE;
}

取栈顶元素

算法思路:

  • 直接取出S所指的元素

算法描述:

SElemType GetTop(LinkStack S) {
    if(S != NULL)
        return S->data;
}

链栈的入栈

算法思路:

  1. 生成新结点p

  2. 将新节点插入栈顶

  3. 修改栈顶指针

算法描述:

Status Push(LinkStack &S, SElemType e) {
    p = new Stacknode;	//生成新结点p
    p->data = e;	//将新节点的数据域置为e
    p->next = S;	//将新节点插入栈顶
    S = p;			//修改栈顶指针
    return OK;
}

链栈的出栈

算法思路:

  1. 判断栈是否存在且非空

  2. 保存当前栈顶地址

  3. 修改栈顶指针

  4. 释放刚才的栈顶空间

算法描述:

Status Pop(LinkStack &S, SElemType &e) {
    if(S == NULL) return ERROR;
    e = S->data;
    p = S;
    S = S->next;
    delete P;
    return OK;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值