草庐IT

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

java小豪 2023-03-28 原文

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指示真正的栈顶元素之上的下标地址

顺序栈的定义:

#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. 下溢:栈已经空,还要弹出元素

顺序栈的表示:

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、链栈的表示和实现

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

链栈的定义:

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;						// 返回栈顶元素的值,栈顶指针不变
  }
}

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

  1. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  4. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  5. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  6. ruby - 我如何添加二进制数据来遏制 POST - 2

    我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_

  7. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  8. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  9. FOHEART H1数据手套驱动Optitrack光学动捕双手运动(Unity3D) - 2

    本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01  客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02  数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit

  10. 使用canal同步MySQL数据到ES - 2

    文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co

随机推荐