数据结构学习笔记(特殊的线性表:栈与队列)

简介:                      栈与队列栈是限定仅在表尾(栈顶)进行插入和删除操作的线性表(后进先出)。队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表(先进先出)。 栈(Stack):1.下标为0的一端作为栈底比较好,因为首元素都存在栈底,变化最小,所以让它作为栈底。

                     栈与队列

栈是限定仅在表尾(栈顶)进行插入和删除操作的线性表(后进先出)。
队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表(先进先出)。

 

栈(Stack):

1.下标为0的一端作为栈底比较好,因为首元素都存在栈底,变化最小,所以让它作为栈底。
定义一个top变量来指示栈顶元素在数组中的位置。栈顶位置top必须小于存储栈长度StackSize,把空栈的判定条件定位top等于-1。

 

2.进栈与出栈操作(顺序存储结构):

进栈操作push:
/*插入元素e为新的栈顶元素*/
Status Push(SqStack *S, SElemType e)
{
if (S->top == MAXSIZE - 1) /*栈满*/
return ERROR;
S->top++; /*栈顶指针增加一*/
S->data[S->top] = e; /*将新插入元素赋值给栈顶空间*/
return OK;
}


出栈操作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;
}

*进栈与出栈两者的时间复杂度均是O(1)。


3.两栈共享空间:
数组有两个端点,两个栈有两个栈底,让一个栈的栈底为数组的始端,即下标为0处,另一个栈为栈的末端,即下标为数组长度n-1处。这样,两个栈如果增加元素,就是两端点向中间延伸。
栈1为空时,就是top1等于-1时;而当top2等于n时,即是栈2为空时。
两个栈见面知识,也就是两个指针之间相差1时,即top1 + 1 == top2 为栈满。


4.栈的链式存储结构:
栈顶放在单链表的头部。
对于链栈来说,是不需要头结点的。
对于链栈来说,基本不存在栈满的情况。
链栈的空其实就是top=NULL。

 

5.进栈与出栈操作(链式存储结构):

进栈操作:
/*插入元素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;
}

 

出栈操作:
/*若栈不空,则删除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;
}

 

*链栈的出栈push和出栈pop操作没有任何循环操作,时间负责度均为O(1)。
*顺序栈和链栈,它们在时间复杂度上是一样的,均为O(1)。
*如果栈的使用过程中元素变化不可预料,有时很小,有时非常大,那么最好是用链栈;反之,如果它的变化在可控范围内,建议使用顺序栈会更好一些。


6.栈的应用:递归
递归定义:把一个直接调用自己或者通过一系列的调用语句间接地调用自己的函数,称作递归函数。
每个递归定义必须至少有一个条件,满足时递归不再进行,即不再引用自身二十返回值退出。
*迭代和递归的区别是:迭代使用的是循环结构,递归使用的是选择结构。递归能使程序的结构更清晰,更简洁,更容易让人理解,从而减少读懂代码的时间。但是大量的递归调用会建立函数的副本,会耗费大量的时间和内存。迭代则不需要反复调用函数和占用额外的内存。
递归过程退回的顺序是它前行顺序的逆袭。


7.栈的应用:四则运算表达式求值
后缀表达式:所有的符号都是在要运算数字的后面出现。
中缀表达式:标准四则运算表达式。
*后缀表达式运算规则:从左到右遍历表达式的每个数字和符号,遇到数字就进栈,遇到是符号,就将处于栈顶两个数字出栈,进行运算(后出栈的那个数字是“被”的,比如“被减数”,前面那个比如“减数”,运算结果出栈,一直到最终获得结果。

*中缀表达式转后缀表达式:
规则:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出,并将当前符号出栈,一直到最终输出后缀表达式为止。

 

队列(Queue):
1.队列定义:队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
队列是一种先进先出的线性表。允许插入的一端称为队尾,允许删除的一端称为队头。

 

2.把队列的这种头尾相接的顺序存储结构称为循环对列。


3.判断队列究竟是空还是满?
*办法一是设置一个标志变量flag,当front == rear,且flag = 0 时为队列空,当front == rear,且 flag = 1时为队列满。
*办法二是当队列空时,条件就是front = rear,当队列满时,我们修改其条件,保留一个元素空间:
设队列的最大尺寸为QueueSize,队列满的条件是(rear+1)% QueueSize == front(取模“%”的目的就是为了整合rear与front大小为一个问题)。
通用的计算队列长度公式为:
(rear - front + QueueSize) % QueueSize

 

4.循环队列操作(队列的顺序存储结构):

循环队列的顺序存储结构代码如下:
typedef int QElemType; /*QElemType类型根据实际情况而定,这里假设为int*/
/*循环队列的顺序存储结构*/
typedef struct
{
QElemType data[MAXSIZE];
int front; /*头指针*/
int rear; /*尾指针,若队列不空,指向队列尾元素的下一位置*/
}SqQueue;

 

循环队列的初始化代码如下:
/*初始化一个空队列Q*/
Status InitQueue(SqQueue *Q)
{
Q->front = 0;
Q->rear = 0;
return OK;
}

 

循环队列求队列长度代码如下:
/*返回Q的元素个数,也就是队列的当前长度*/
int QueueLength(SqQueue Q)
{
return (Q.rear - Q.front + MAXSIZE) % MAXSIZE;
}

 

循环队列的入队列操作代码如下:
/*若队列未满,则插入元素e为Q新的队尾元素*/
Status EnQueue(SqQueue *Q, QElemType e)
{
if((Q->rear+1)%MAXSIZE == Q->front) /*队列满的判断*/
return ERROR;
Q->data[Q->rear]=e; /*将元素e赋值给队尾*/
Q->rear=(Q->rear+1)%MAXSIZE; /*rear指针后移一位置*/
return OK;
}

 

循环队列的出队列操作代码如下:
/*若队列不空,则删除Q中队头元素,用e返回其值*/
Status DeQueue(SqQueue *Q, QElemType *e)
{
if (Q->front == Q->rear) /*队列空的判断*/
return ERROR;
*e = Q->data[Q->front]; /*将队头元素赋值给e*/
Q->front = (Q->front + 1) % MAXSIZE; /*front指针向后移一位置*/
/*若到最后则转到数组头部*/
return OK;
}

 

 

5.队列的链式存储结构—-尾进头出。
队头指针指向链队列的头结点。队尾指针指向终端结点。空队列时,front和rear都指向头结点。

 

链队列的结构为:
typedef int QElemType; /*QElemType类型根据实际情况而定,这里假设为int*/
typedef struct QNode; /*结点结构*/
{
QElemType data;
struct QNode *next;
}QNode, *QueuePtr;

 

typedef struct /*队列的链表结构*/
{
QueuePtr front, rear; /*队头,队尾指针*/
}LinkQueue;

 

 

6.队列的链式存储结构—-入队与出队操作:
入队操作:其实就是在链表尾部插入结点。
/*插入元素e为Q的新的队尾元素*/
Status EnQueue(LinkQueue *Q, QElemType e)
{
QueuePtr s=(QueuePtr)malloc(sizeof(QNode));
if(!s) /*存储分配失败*/
exit(OVERFLOW);
s->data=e;
s->next=NULL;
Q->rear->next=e; /*把拥有元素e的新结点s赋值给原队尾结点的后继,*/
Q->rear=s; /*把当前s设置为队尾结点,rear指向s*/
return OK;
}

 

 

出队操作:就是头结点的后继结点出队,将头结点的后继改为它后面的结点,若链表除头结点外只剩一个元素时,则需将rear指向头结点。
/*若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR*/
Status DeQueue(LinkQueue *Q, QElemType *e)
{
QueuePtr p;
if(Q->front==Q->rear)
return ERROR;
p=Q->front->next; /*将欲删除的队头结点暂存给p*/
*e=p->data; /*将欲删除的队头结点的值赋值给e*/
Q->front->next=p->next; /*将原队头结点后继p->next赋值给头结点后继*/
if(Q->rear==p) /*若队头是队尾,则删除后将rear指向头结点*/
Q->rear=Q->front;
free(p);
return OK;
}

 

 

*循环队列与链队列比较:
时间上:时间复杂度都为O(1);
空间上:循环队列需要事先申请好空间,使用期间不释放,在空间上,链队列更加灵活。
*建议:在可以确定队列长度最大值的情况下,建议用循环队列,如果无法预估队列的长度时,则用链队列。

 

 

#总结:栈分为顺序栈和链栈,其中顺序栈可以通过使用“两栈共享空间”的方法解决顺序栈的弊端;
           队列分为顺序队列和链队列,其中顺序队列可以通过使用“循环队列”的方法解决顺序队列的弊端。

 

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