数据结构(严蔚敏版)第三章——栈和队列(二)【栈的表示和操作的实现】

3.3、栈的表示和操作的实现

3.3.1、栈的类型定义

栈的基本操作的抽象数据类型定义:

ADT Stack {
  数据对象; D  = {ai | ai 属于 ElementSet, i = 1, 2, ... , n, n >= 0}
  数据关系: R1 = {<ai - 1, ai> | ai - 1, ai 属于 D, i = 2, ... , n }
  					约定an端为栈顶,a1端为栈底
  基本操作:
  	InitStack(&S)
    操作结果:构造一个空栈
    DestroyStack(&S)
    初始条件:栈S已存在
    操作结果:栈S被销毁
    ClearStack(&S)
    初始条件:栈S已存在
    操作结果:将栈S清空为空栈
    StackEmpty(S)
    初始条件:栈S已存在
    操作结果:若栈S为空栈,则返回true,否则则返回false
    StackLength(S)
    初始条件:栈S已存在
    操作结果:返回S的元素个数,即栈的长度
    GetTop(S, e)
    初始条件:栈S已存在
    操作结果:返回S的栈顶元素,不修改栈顶的指针 
    Push(&S, e)
    初始条件:栈S已存在
    操作结果:插入元素e为新的栈顶元素
    Pop(S)
    初始条件:栈S已存在
    操作结果:删除S的栈顶元素,并用e返回其值
    StackTraverse(S)
    初始条件:栈S已存在且非空
    操作结果:从栈底到栈顶依次对S的每个数据元素进行访问          
}ADT Stack

3.3.2、顺序栈的表示和实现

  • 栈的存储方式有两种:顺序存储和链式存储

    • 栈的顺序存储——顺序栈
    • 栈的链式存储——链栈
  • 存储方式:同一般的线性表的顺序存储结构完全相同,

  • 利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素。栈底一般在低地址端

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

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

image-20221013084655325

顺序栈的定义:

#define MAXSIZE 100 			// 顺序栈存储空间的初始分配量
typedef struct 
{
  SElemType *base;				// 栈底指针
  SElemType *top;					// 栈顶指针
  int stacksize;					// 栈可用的最大容量
}SqStack;

说明:

  1. base为栈底指针,初始化完成之后,栈底指针始终指向栈底的位置,若base为NULL。则表明栈的结构不存在。top为栈顶指针,其初值指向栈底。每插入新的栈顶元素时,指针top增1;删除栈顶元素时,指针top减1.因此栈空时top和base的值相等,即空栈:base == top;栈非空时,top始终指向栈顶元素的上一个位置。栈满的标志:top - base == stacksize
  2. stacksize指示栈可使用的最大容量,后面的算法将stacksize置为MAXSIZE
  3. 上溢:栈已经满,又要压入元素
  4. 下溢:栈已经空,还要弹出元素

顺序栈的表示:

image-20221013100723572

1、顺序栈的初始化

【算法步骤】

  • 为顺序栈动态分配一个最大容量为MAXSIZE的数组空间,使base指向这段空间的基地址,即栈底
  • 栈顶指针top初始为base,表示栈为空
  • stacksize置为栈的最大容量MAXSIZE

【算法描述】

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

2、判断顺序栈是否为空

判断条件:是否满足top == base

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

3、求顺序栈长度

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

4、清空顺序栈

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

5、销毁顺序栈

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

6、顺序栈的入栈

  • 判断栈是否满,若满则返回ERROR
  • 将新元素压入栈顶,栈顶指针加1
Status Push(SqStack &S, SElemType e)
{	// 插入元素e为新的栈顶元素
  if (S.top - S.base == S.stacksize) return ERROR; 		// 栈满
  *S.top++ = e;
  // 或 *S.top = e; S.top++;
  return OK;
}

7、顺序栈的出栈

【算法步骤】

  • 判断栈是否为空,若为空则返回ERROR
  • 栈顶指针减1,栈顶元素出栈

【算法描述】

Status Pop(SqStack &S, SElemType &e)
{ // 删除S的栈顶元素,用e返回其值
  if (S.top == S.base) return ERROR; 	// 栈空
  e = *--S.top;												// 栈顶指针减1,将栈顶元素赋给e
  // 或 e = S.top; S.top--;
  return OK;
  
}

8、取栈顶元素

  • 当栈非空时,此操作返回当前栈顶的元素值,栈顶指针保持不变。

【算法描述】

SElemType GetTop(SqStack S) 
{ // 返回S的栈顶元素,不修改栈顶指针
  if(S.top != S.base) 				// 栈非空
    return *(S.top - 1);			// 返回栈顶元素的值,栈顶指针不变
  
}

3.3.3、链栈的表示和实现

  • 链栈是运算受限的单链表,只能在链表头部进行操作
  • 链栈的指针指向的元素是数据域的前驱
  • 链表的头指针就是栈顶、不需要头结点,基本不存在栈满的情况
  • 空栈相当于头指针指向空
  • 插入和删除仅在栈顶处执行

image-20221013110241170

链栈的定义:

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

1、链栈的初始化

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

2、判断链栈是否为空

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

3、链栈的入栈

【算法步骤】

  • 为入栈元素e分配空间,用指针p指向
  • 将新结点数据域置为e
  • 将新结点插入栈顶
  • 修改栈顶指针为p

【算法描述】

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

4、链栈的出栈

【算法步骤】

  • 判断栈是否为空,若为空则返回ERROR
  • 将栈顶元素赋给e
  • 临时保存栈顶指针,指向新的栈顶元素
  • 释放原栈顶元素的空间

【算法描述】

Status Pop(LinkStack &S, SElemType &e)
{  // 删除S的栈顶元素,用e返回其值
  if (S == NULL)
 		return ERROR;										// 栈空
  e = S -> data;										// 将栈顶元素赋给e
  p = S;														// 用p临时保存栈顶元素空间,以备释放
  S = S -> next;										// 修改栈顶指针
  delete p;													// 释放原栈顶元素的空间
  return OK;
}

5、取栈顶元素

与顺序栈一样,当栈非空时,此操作返回当前栈顶元素的值,栈顶指针S保持不变。

【算法描述】

SElemType GetTop(LinkList S)
{  // 返回S的栈顶元素,不修改栈顶元素
  if (S != NULL)								// 栈非空
  {
    return S -> data;						// 返回栈顶元素的值,栈顶指针不变
  }
}
posted @   java小豪  阅读(283)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· DeepSeek在M芯片Mac上本地化部署
点击右上角即可分享
微信分享提示