拔丝芋头的数据结构复习日记---Day2---堆栈、队列

2023-10-29 14:10

本文主要是介绍拔丝芋头的数据结构复习日记---Day2---堆栈、队列,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

< 今日知识点 >

  • 堆栈
  • 队列

·
·
·

—01 堆栈

在这里插入图片描述

1、栈的顺序存储实现

#define MAXSIZE  //储存数据元素的最大个数
typedef struct SNode *Stack;
struct SNode{ElementType Data[MAXSIZE];int top;
};
  • 栈的顺序存储结构通常由一个一维数组和一个记录栈顶元素位置的变量组成
  • 当栈为空时,通常初始化栈顶元素位置变量top为-1

2、栈的操作实现
(1)入栈

void Push(Stack S,ElementType X)
{if(S->top == MAXSIZE-1){printf("堆栈满");return ;}else{S->Data[++(S->top)] = X;return ;}
}

(2) 出栈

ElementType Pop(Stack S)
{if(S->top == -1){printf("堆栈空");return Error;   //ERROR是ElementType的特殊值,标志错误} else {return(S->Data[(S->top)--]);}
}


例子:在这里插入图片描述

-分析:一种比较聪明的方法是使这两个栈分别从数组的两头开始向中间生长,当两个栈的栈顶指针相遇时,就表示两个栈都满了

代码实现:

#define MAXSIZE   <储存数据元素的最大个数>
struct DStack{ElementType Data[MAXSIZE];int top1;int top2;
}S;
//初始化:
S.top==-1;
S.top2==MAXSIZE;

入栈操作:

void Push(struct DStack *S,ElementType item,int tag)
{if(S->top2 - S->top1 == 1){printf("堆栈已满");return ;}if(tag==1)     //对第一个堆栈进行操作S->Data[++(S->top1)] = item;else S->Data[--(S->top2)] = item;
}

出栈操作:

ElementType Pop(struct DStack *S,int tag)
{if(tag==1){if(S->top1==-1) {printf("堆栈1空");return NULL;else return S->Data[(S->top1)--];}else{if(S->top2==MAXSIZE){printf("堆栈2空");return NULL;else return S->Data[(S->top2)++];}
}
  • tag作为区分两个堆栈的标志,取值为1和2

3、堆栈的链式存储实现

typedef struct SNode *Stack;
struct SNode{ElementType *Data;struct SNode *Next;
};
  • 栈的链式存储结构实际上就是一个单链表,叫做栈链。插入和删除操作只能在栈链的栈顶进行。
  • 栈顶指针top应该在链表的哪一头? (应该在链表头的位置

4、栈的链式存储操作:
(1)堆栈初始化(建立空栈)

Stack CreateStack()
{Stack S;S = (Stack)malloc(sizeof(struct SNode));S->Next = NULL;return S;
}
  • 即堆栈的一个头结点,返回指针

(2) 判断堆栈是否为空

int IsEmpty(Stack S)
{return (S->Next == NULL)
  • 判断堆栈是否为空,若为空返回整数1,否则返回0

(3) 入栈

void Push(ElementType item,Stack S)
{struct SNode *TmpCell;TmpCell = (struct SNode*)malloc(sizeof(struct SNode));TmpCell->Element = item;TmpCell->Next = S->Next;S->Next = TmpCell;
}

(4) 出栈

ElementType Pop(Stack S)         
{      //删除并返回栈顶的元素struct SNode *FirstCell;ElementType topItem;if(IsEmpty(S)){printf("堆栈空");return NULL;}else {FirstCell = S->Next;S->Next = FirstCell -> Next;topItem = FirstCell -> Element;free(FirstCell);return topItem;}
}

5、堆栈应用:表达式求值
在这里插入图片描述

中缀表达式求值

基本策略:将中缀表达式转换为后缀表达式 (如何转换?)
观察一个简单例子:2+9 /3 -5 -> 2 9 3 / + 5 -
总结:
1、运算数相对顺序不变
2、运算符号顺序发生改变

  • 需要存储等待中的运算符号
  • 需要将当前运算符号与 等待中 的最后一个运算符 比较

在这里插入图片描述

中缀表达式如何转换为后缀表达式

-----> 从头到尾读取中缀表达式的每个对象,对每个对象按不同的情况处理
1、运算数:直接输出
2、左括号:压入堆栈
3、右括号:将栈顶的运算符弹出并输出,直到遇到左括号(出栈,不输出)
4、运算符:

  • 优先级大于栈顶运算符时,则把它压栈
  • 优先级小于栈顶运算符时,将栈顶运算符弹出并输出。再比较新的栈顶运算符,直到运算符大于栈顶运算符优先级为止,然后将该运算符压栈。
    5、若各对象处理完毕,则把堆栈中存留的运算符一并输出。在这里插入图片描述

·
·
·

—02 队列

1、
在这里插入图片描述

代码:

#define MAXSIZE  <储存数组元素的最大个数>
struct QNode{ElementType Data[MAXSIZE];int front;int rear;
};
typedef struct QNode *Queue;
  • 队列的顺序存储结构通常由一个一维数组和一个记录队列头元素位置的变量以及一个记录队尾元素位置的变量rear组成

2、 循环队列

在这里插入图片描述

思考题:
  • 堆栈空的判别条件是front==rear ,堆栈满的判别条件是(rear+1)%MAXSIZE == 0
  • 出现空、满无法区分的原因:堆栈可能出现的情况有七种,即空,和存在1、2、3、4、5、6个元素,而下标数字只有六种情况,即0~5,所以六个数字情况是无法不重复地表示堆栈的所有情况的,需要寻找新的表示方法

3、队列的操作
(1)入队列

void AddQ(Queue Q,ElementType item)
{ if(Q->rear+1)%MAXSIZE==Q->front){printf("队列满");return ;}Q->rear = (Q->rear+1% MAXSIZE;Q->Data[Q->rear] =item;
}

(2) 出队列

ElementType DeleteQ (Queue Q)
{if(Q->front == Q->rear){printf("队列空");return ERROR;}else{Q->front = (Q->front+1)%MAXSIZE;return Q->Data[Q->front];}
}
- front和rear指针的移动采用 加1取余 法,体现了顺序存储的循环使用特性。

4、队列的链式存储实现

  • 队列的链式存储结构也可以用一个单链表实现。插入和删除操作分别在链表的两头进行;
  • 思考:队列指针front和rear应该分别指向链表的哪一头??
  • (front进行的是删除操作,应该指向链表头,rear进行的是插入操作,应该指向链表尾。因为对front来说,如果指向的是链表尾,那么一旦删除了一个元素,就找不到其他的元素了,即丢失了)
struct Node{ElementType Data;struct Node *Next;
};struct QNode{        //链队列结构 struct Node *rear;         //指向队尾和队头节点struct Node *front;
}typedef struct QNode *Queue;
Queue Q;

在这里插入图片描述

  • 不带头结点的链式队列出队操作的一个示例:
ElementType DeleteQ(Queue Q)
{	struct Node *frontCell;ElementType frontElem;if(Q->front ==NULL){printf("队列空");return ERROR;}frontCell = Q->front;if(Q->front == Q->rear)       //若队列中只有一个元素,删除后 队列置为空Q->front = Q->rear =NULL;else Q->front = Q->front->Next;frontElem = frontCell->Data;free(frontCell);return frontElem;
}

·
·
·
附:文中所有PPT图片均来自中国大学mooc 浙江大学《数据结构》课程!!

这篇关于拔丝芋头的数据结构复习日记---Day2---堆栈、队列的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/301175

相关文章

Java中常见队列举例详解(非线程安全)

《Java中常见队列举例详解(非线程安全)》队列用于模拟队列这种数据结构,队列通常是指先进先出的容器,:本文主要介绍Java中常见队列(非线程安全)的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录一.队列定义 二.常见接口 三.常见实现类3.1 ArrayDeque3.1.1 实现原理3.1.2

C++ RabbitMq消息队列组件详解

《C++RabbitMq消息队列组件详解》:本文主要介绍C++RabbitMq消息队列组件的相关知识,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. RabbitMq介绍2. 安装RabbitMQ3. 安装 RabbitMQ 的 C++客户端库4. A

golang实现延迟队列(delay queue)的两种实现

《golang实现延迟队列(delayqueue)的两种实现》本文主要介绍了golang实现延迟队列(delayqueue)的两种实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的... 目录1 延迟队列:邮件提醒、订单自动取消2 实现2.1 simplChina编程e简单版:go自带的time

Java的栈与队列实现代码解析

《Java的栈与队列实现代码解析》栈是常见的线性数据结构,栈的特点是以先进后出的形式,后进先出,先进后出,分为栈底和栈顶,栈应用于内存的分配,表达式求值,存储临时的数据和方法的调用等,本文给大家介绍J... 目录栈的概念(Stack)栈的实现代码队列(Queue)模拟实现队列(双链表实现)循环队列(循环数组

Redis消息队列实现异步秒杀功能

《Redis消息队列实现异步秒杀功能》在高并发场景下,为了提高秒杀业务的性能,可将部分工作交给Redis处理,并通过异步方式执行,Redis提供了多种数据结构来实现消息队列,总结三种,本文详细介绍Re... 目录1 Redis消息队列1.1 List 结构1.2 Pub/Sub 模式1.3 Stream 结

SpringKafka错误处理(重试机制与死信队列)

《SpringKafka错误处理(重试机制与死信队列)》SpringKafka提供了全面的错误处理机制,通过灵活的重试策略和死信队列处理,下面就来介绍一下,具有一定的参考价值,感兴趣的可以了解一下... 目录引言一、Spring Kafka错误处理基础二、配置重试机制三、死信队列实现四、特定异常的处理策略五

C#数据结构之字符串(string)详解

《C#数据结构之字符串(string)详解》:本文主要介绍C#数据结构之字符串(string),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录转义字符序列字符串的创建字符串的声明null字符串与空字符串重复单字符字符串的构造字符串的属性和常用方法属性常用方法总结摘

Spring Boot整合消息队列RabbitMQ的实现示例

《SpringBoot整合消息队列RabbitMQ的实现示例》本文主要介绍了SpringBoot整合消息队列RabbitMQ的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的... 目录RabbitMQ 简介与安装1. RabbitMQ 简介2. RabbitMQ 安装Spring

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

Go语言中三种容器类型的数据结构详解

《Go语言中三种容器类型的数据结构详解》在Go语言中,有三种主要的容器类型用于存储和操作集合数据:本文主要介绍三者的使用与区别,感兴趣的小伙伴可以跟随小编一起学习一下... 目录基本概念1. 数组(Array)2. 切片(Slice)3. 映射(Map)对比总结注意事项基本概念在 Go 语言中,有三种主要