【开卷数据结构 】 栈与队列

简介: 【开卷数据结构 】 栈与队列

上文详细的讲解了顺序表与链表的实现,相信大家在顺序表与链表的指基础上,很容易就能学会站和队列,废话不多说,我们马上开始!


🌺栈


🍁栈的定义


栈是一种线性表,但限定这种线性表只能在某一端进行插入和删除操作

3e76decb2d8d96c60c2695d5ff1410ed_9d16415e774c402a93144ad6610bcb1e.png


假设栈 【s = (a1,a2,……,an) 】,a1为栈底元素,an为栈顶元素。由于栈只能在栈顶进行插入和删除操作,所以进栈次序依次为【a1,a2,……,an】,出栈次序为【an,……,a2,a1】


由此可见:栈的操作特性可以明显地概括为后进先出


栈类似于线性表,它也有两种对应的存储方式分别为顺序栈和链栈。


🍁顺序栈


(1)顺序栈的定义

Q:什么是顺序栈?

A:采用顺序存储的栈成为顺序栈。它利用一组地址连续的存储单位存放自栈底到栈顶的数据元素,同时附设一个指针(top)来指示当前栈顶的位置。


栈的顺序存储类型可描述为


#define MaxSize 100    //定义栈中元素的最大个数
typedef struct
{
  SElemtype *base;    //栈底指针
  SElemtype *top;    //栈顶指针 
  int stacksize    //栈可用的最大容量 
}SqStack;


(2)顺序栈的初始化

Q:什么是顺序栈的初始化?

A:顺序栈的初始化操作就是为顺序栈动态分配一个最大容量为 MaxSize 的数组空间。


🔺实现原理


1️⃣为顺序栈动态分配一个最大容量为MAXSIZE的数组


2️⃣栈顶指针top初始为base,表示栈为空


3️⃣stacksize置为栈的最大容量MaxSize


💬 代码演示


Status InitStack(SqStack &S)
{//构造一个空栈S
  S. base=new SElemType[MaxSize];  //为顺序栈动态分配一个最大容量为MAxsini
  if(!S. base) exit(OVERFLOW);  //存储分配失败
  S. top=S. base;      //top初始为base,空栈
  S. stacksize=MaxSize;    //stacksize置为栈的最大容量MaxSize
  return OK;
}


(3)顺序栈的入栈

Q:什么是顺序栈的入栈?

A:入栈操作是将新元素进入栈


🔺实现原理


1️⃣判断栈是否满了,若满了返回ERROR


2️⃣将新元素压入栈,栈顶指针加1


💬 代码演示


Status Push(SqStack &S,SElemType e)
{//插入元素e为新的栈顶元素
  if(S.top-S.base==S:stacksize) return ERROR;//栈满 
  *S. top++=e;          //元素e压入栈顶,栈顶指针加1
  return OK;
}


(4)顺序栈的出栈

Q:什么是顺序栈的出栈?

A:出栈操作是将栈顶元素删除


🔺实现原理


1️⃣判断栈是否空,若空则返回ERROR


2️⃣栈顶指针减1,栈顶元素出栈


💬 代码演示


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


(5)取顺序栈的栈顶元素

Q:如何取顺序栈的栈顶元素?

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


🔺实现原理


1️⃣判断栈是否空


2️⃣返回栈顶元素的值,栈顶指针不变


💬 代码演示


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


🍁链栈


采用链式存储的栈称为链栈。链栈的优点是便于多个栈共享存储空间和提高其效率,且不存在栈满上溢的情况。通常采用单链表实现。


栈的顺序存储类型可描述为


typedef struct Linknode
{
  ElemType data;    //数据域
  struct Linknode *next;  //指针域
} *LiStack;

采用链式存储,便于结点的插入与删除。链栈的操作与链表类似,入栈和出栈的操作都在链表的表头进行。


🌺队列


🍁队列的定义


队列是一种线性表,但限定这种线性表只能在表的一端进行插入,在另一端进行删除。允许删除的一端为队头,又称为队首,允许插入的一端为队尾

1f41340c47a7511a172e09603bfdc72a_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQ2V5bGFuXw==,size_20,color_FFFFFF,t_70,g_se,x_16.png


队列与生活中的排队一样,最早排队的最先离开,队列的操作特性可以明显地概括为先进先出


队列有两种存储表示,分别为顺序表示与链式表示


🍁队列的顺序表达与实现


(1)队列顺序存储结构

和顺序栈相类似,在队列的顺序存储结构中,除了用一组地址连续的存储单元依次列头到队列尾的元素之外。还需附设两个整型变量【front】和【rear】分别指示队列头元素及队间的位置(后面分别称为头指针和尾指针)。


队列的顺序存储结构表示如下:


#define   MAXSIZE    100  //队列容量
typedef   struct 
{   
  ElemType *base;             //存储空间
  int front,rear;             //队首,队尾
}SqQueue ;


(2)假溢出

6731a960edeef5e3453e66a7aa1785f2_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQ2V5bGFuXw==,size_20,color_FFFFFF,t_70,g_se,x_16.png

图(1)所示为队列的初始状况。此时有【front == rear == 0】 成立。该条件可以作为队列判空的条件。


但是【rear == MAXSIZE】不能作为队列满的条件。为什么呢?


图(4)队列中只有一个元素,仍满足该条件。这时入队出现上溢出。但是这种溢出并不是真正的溢出,在队列中依然存在可以存放元素的空位置,所以是一种假溢出。


如何解决循环链表的这一缺点呢?


🍁循环队列


Q:什么是循环队列?

A:将顺序队列臆造成一个环状的空间,即把存储队列元素的表从逻辑上视为一个环,称为循环队列。


(1)循环队列的初始化

Q:什么是循环队列的初始化?

A:循环队列的初始化就是动态分配一个预定义大小为 MAXSIZE 的数组空间


🔺实现原理


1️⃣为队列动态分配一个最大容量为MAXSIZE的数组空间


2️⃣base指向数组空间的首地址


3️⃣头指针与尾指针置为零,表示队列为空


💬 代码演示


Status InitQueue ( SqQueue  &Q )
{
  Q.base=new  ElemType[MAXSIZE];
  if(!Q.base) return OVERFLOW;
  Q.front=Q.rear=0;
  return OK;
}


🌹循环队列的入队


Q:什么是循环队列的入队?

A:入队操作是指在队尾插入一个新的元素


🔺实现原理


1️⃣判断队列是否满


2️⃣满了返回ERROR


3️⃣将新元素插入队尾


4️⃣队尾指针加一


💬 代码演示


Status EnQueue(SqQueue &Q,ElemType e)
{
    if((Q.rear+1)%MAXSIZE==Q.front) //判满    
     return ERROR;
  Q.base[Q.rear]=e;
  Q.rear=(Q.rear+1)%MAXSIZE;
  return OK;
}


🌹循环队列的出队


Q:什么是循环队列的出队?

A:出队操作是删除队头元素


🔺实现原理


1️⃣判断队列是否为空


2️⃣为空返回ERROR


3️⃣保留队头元素


4️⃣队头指针加一


💬 代码演示


Status DeQueue(SqQueue &Q, ElemType &e)
{
    if( Q.rear==Q.front )  
  return ERROR;   //判空
  e = Q.base[Q.front];
  Q.front = (Q.front+1)%MAXSIZE;  
  return OK;
}


🍁链队列


Q:什么是链队列?

A:队列的链式表示称为链队列。它实际上是一个同时带有队头指针和队尾指针的单链表,头指针指向对头结点,尾指针指向队尾结点。


队列的链式存储如图:

9a8d121b032e309fa53b14c645d4db2f_eff55ff206e74ce1b5a46473e6cfa91f.png


队列的链式存储类型可描述为:


typedef struct Qnode
{       
  ElemType data;
    struct QNode * next;
}Qnode,*QueuePtr;                  //结点
typedef struct 
{ 
  QueuePtr  front;
  QueuePtr rear;
}LinkQueue;                       //链队

(1)链栈的初始化

Q:什么是链队列的初始化?

A:链栈的初始化操作就是构建一个只有头结点的空队。


🔺实现原理


1️⃣生成新结点作为头结点


2️⃣队头指针和队尾指针指向该结点


3️⃣头指针的指针域置空


💬 代码演示


Status InitQueue(LinkQueue &Q)
{ 
  Q.front=Q.rear=new QNode;
  p->next=NULL;
  return OK;
}


🌹链栈的入队


🔺实现原理


1️⃣为入队元素分配结点空间,用指针p指向


2️⃣将新结点数据域置为e


3️⃣将新结点插入到队尾


4️⃣修改队尾指针为p


💬 代码演示


Status EnQueue(LinkQueue &Q,ElemType e)
{
  p=new QNode;  //为入队元素分配结点空间,用指针p指向
  p->data=e;         //将新结点数据域置为e
  p->next=NULL;  
  Q.rear->next=p;     //将新结点插入到队尾
  Q.rear=p;   //修改队尾指针为p
  return OK;
}


🌹链栈的出队


🔺实现原理


1️⃣判断是否为空,为空返回ERROR


2️⃣保留头元素空间,以备释放


3️⃣修改头指针的指针域,指向下一结点


4️⃣判断出队元素是否是最后一个元素,若是,将队尾指针重新赋值,指向头结点


5️⃣释放原队头元素的空间


💬 代码演示


Status DeQueue(LinkQueue &Q,ElemType &e)
{
  if(Q.front==Q.rear)   //若队列为空,返回ERROR
  return ERROR;
  QNode *p=Q.front->next;  //保留头元素空间,以备释放
  Q.front->next=p->next;  //修改头指针的指针域,指向下一结点
    if(Q.rear==p)    //判断出队元素是否是最后一个元素,若是,将队尾指针重新赋值,指向头结点
  Q.rear=Q.front; 
  delete p;     //释放原队头元素的空间
  return OK;
}


05d250eb22e3badf2cfb05fc5f2f91af_94536690f848438fab30aa17191a6ea2.png

本人不才,如有错误,欢迎各位大佬在评论区指正。有帮助的话还请【关注➕点赞➕收藏】,不行的话我再努努力💪💪💪  


相关文章
|
1月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
210 9
|
1月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
37 1
|
28天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
53 5
|
1月前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
1月前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
1月前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
52 4
|
1月前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
1月前
|
算法
数据结构之购物车系统(链表和栈)
本文介绍了基于链表和栈的购物车系统的设计与实现。该系统通过命令行界面提供商品管理、购物车查看、结算等功能,支持用户便捷地管理购物清单。核心代码定义了商品、购物车商品节点和购物车的数据结构,并实现了添加、删除商品、查看购物车内容及结算等操作。算法分析显示,系统在处理小规模购物车时表现良好,但在大规模购物车操作下可能存在性能瓶颈。
49 0
|
2月前
数据结构(栈与列队)
数据结构(栈与列队)
23 1
|
2月前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
48 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器

热门文章

最新文章