C语言队列课件
数据结构——用C语言描述(第3版)教学课件第3章 栈和队列
if(S->top==-1) /*栈为空*/
return(FALSE);
else
{*x = S->elem[S->top];
return(TRUE);
}
返回主目录}[注意]:在实现GetTop操作时,也可将参数说明SeqStack *S 改为SeqStack S,也就是将传地址改为传值方式。传 值比传地址容易理解,但传地址比传值更节省时间、 空间。
返回主目录
算法:
void BracketMatch(char *str) {Stack S; int i; char ch; InitStack(&S); For(i=0; str[i]!='\0'; i++) {switch(str[i])
{case '(': case '[': case '{':
3.1.3 栈的应用举例
1. 括号匹配问题
思想:在检验算法中设置一个栈,若读入的是左括号, 则直接入栈,等待相匹配的同类右括号;若读入的是 右括号,且与当前栈顶的左括号同类型,则二者匹配, 将栈顶的左括号出栈,否则属于不合法的情况。另外, 如果输入序列已读尽,而栈中仍有等待匹配的左括号, 或者读入了一个右括号,而栈中已无等待匹配的左括 号,均属不合法的情况。当输入序列和栈同时变为空 时,说明所有括号完全匹配。
return(TRUE);
}
返回主目录
【思考题】
如果将可利用的空闲结点空间组织成链栈来管理,则申 请一个新结点(类似C语言中的malloc函数)相当于链 栈的什么操作?归还一个无用结点(类似C语言中的 free函数)相当于链栈的什么操作?试分别写出从链栈 中申请一个新结点和归还一个空闲结点的算法。
数据结构(C语言版)_第4章 栈和队列
4.2 栈 4.2.1 栈的定义
栈(stack)是限定在表的一端进行插入或删除操 作的线性表。插入元素的操作称为入栈,删除元素的 操作称为出栈。在任何时候,都只有栈顶元素才能出 栈。换句话说,栈的修改是按先进后出、后进先出的 原则进行的,如图4-1所示。
图4-1 栈的示意图
因此,栈又称为先进后出(First In Last Out)表, 简称FILO表,或后进先出(Last In First Out)表,简称为 LIFO表。通常将允许进行插入或删除操作的一端称为栈顶 (top),被固定的另一端称为栈底(bottom)。不含数据元素的 栈称为空栈。
【拓展学习】两个栈共享同一存储空间。 在某些应用中,为了节省空间,可以让两个数据元素类型一致的 栈共享同一段一维数组空间。可以将两个栈的栈底设在存储空间 的两端,让两个栈分别向中间延伸。两个栈的栈顶变量分别为 top1、top2。只要整个存储空间未被占满,无论哪个栈的入栈都不 会发生上溢。只有两个栈的栈顶位置在中间相遇时(即 top1+1=top2)才发生上溢。因此,这种方法可以有效的提高存储 空间的利用率。我们把这种结构称为双栈,双栈如图4-7所示。
{ if (IsNull_Stack ( s ) ) return 0; /*栈空*/ else return (s->data[s->top] );
}
6. 置空栈操作 【算法4.6】置空栈 void Clear_Stack(Se_Stack *s) {
s->top=0; }
7. 求栈的长度 【算法4.7】求栈长 int StackLength(Se_Stack *s) {
第四章 栈和队列
本章要点
➢ 栈的定义和结构特点 ➢ 栈的顺序存储表示和基本操作的实现。 ➢ 栈的链式存储表示和基本操作的实现。 ➢ 队列的定义和结构特点 ➢ 队列的顺序存储表示和基本操作的实现。 ➢ 队列的链式存储表示和基本操作的实现。 ➢ 栈和队列的简单应用。
数据结构(C语言)第三章-栈和队列-讲义
Cin,Cout C++的输入输出函数作用与Scanf, printf, 类似,更为简单 for (i=1; i<=3;i++) cout<<"count="<<i<<endl; count=1 count=2 count= 3
cin>>a>>b; 可以从键盘输入: 20 32.45
定义在栈结构上的基本运算
(1) (2) (3) (4) (5) (6) (7)
生成空栈操作 init_stack(s) 判栈空函数 empty_stack(s) 数据元素入栈操作 push_stack(s,x) 数据元素出栈函数 pop_stack(s) 取栈顶元素函数 gettop_stack(s) 置栈空操作 clear_stack(s) 求当前栈元素个数函数
⑵ 判空栈 Status StackEmpty ( S ) { if (S.top= = S.base) return TRUE; else return FALSE; }
⑶ 入栈 Status Push ( SqStack *S, Elemtype e) { if ( S.top-S.base >= S.stacksize ) return OVERFLOW; /*栈满不能入栈*/ else *S.top++ = e; return OK; }
例、一叠书或一叠盘子。
栈顶
a a
n n-1
取出和放入 一件物品都只能 在顶端进行。
……
a2
栈底
a1
进栈和出栈
空栈
进栈和出栈
栈顶
67
数据结构C语言版第三章 栈和队列
第三章栈和队列重点难点掌握栈和队列这两种抽象数据类型的特点,并能在相应的应用问题中正确选用它们;熟练掌握栈类型的两种实现方法;熟练掌握循环队列和链队列的基本操作实现算法;理解递归算法执行过程中栈的状态变化过程,便于更好地使用递归算法。
典型例题1.设将整数1,2,3,4依次进栈,但只要出栈时栈非空,则可将出栈操作按任何次序夹入其中,请回答下述问题:(1)若入、出栈次序为Push(1), Pop(),Push(2),Push(3), Pop(), Pop( ),Push(4), Pop( ),则出栈的数字序列为何(这里Push(i)表示i进栈,Pop( )表示出栈)?(2) 能否得到出栈序列1423和1432?并说明为什么不能得到或者如何得到。
(3)请分析1,2 ,3 ,4 的24种排列中,哪些序列是可以通过相应的入出栈操作得到的。
【解】(1)出栈序列为:1324(2)不能得到1423序列。
因为要得到14的出栈序列,则应做Push(1),Pop(),Push(2),Push(3),Push(4),Pop()。
这样,3在栈顶,2在栈底,所以不能得到23的出栈序列。
能得到1432的出栈序列。
具体操作为:Push(1),Pop(),Push(2),Push(3),Push(4),Pop(),Pop(),Pop()。
(3)在1,2 ,3 ,4 的24种排列中,可通过相应入出栈操作得到的序列是:1234,1243,1324,1342,1432,2134,2143,2314,2341,2431,3214,3241,3421,4321不能得到的序列是:1423,2413,3124,3142,3412,4123,4132,4213,4231,43122.循环队列的优点是什么? 如何判别它的空和满?【解】循环队列的优点是:它可以克服顺序队列的"假上溢"现象,能够使存储队列的向量空间得到充分的利用。
《数据结构(C语言)》第3章 栈和队列
栈
❖ 栈的顺序存储与操作 ❖ 1.顺序栈的定义
(1) 栈的静态分配顺序存储结构描述 ② top为整数且指向栈顶元素 当top为整数且指向栈顶元素时,栈空、入栈、栈满 及出栈的情况如图3.2所示。初始化条件为 S.top=-1。
(a) 栈空S.top==-1 (b) 元素入栈S.stack[++S.top]=e (c) 栈满S.top>=StackSize-1 (d) 元素出栈e=S.stack[S.top--]
/*栈顶指针,可以指向栈顶
元素的下一个位置或者指向栈顶元素*/
int StackSize; /*当前分配的栈可使用的以 元素为单位的最大存储容量*/
}SqStack;
/*顺序栈*/
Data structures
栈
❖ 栈的顺序存储与操作 ❖ 1.顺序栈的定义
(2) 栈的动态分配顺序存储结构描述 ① top为指针且指向栈顶元素的下一个位置 当top为指针且指向栈顶元素的下一个位置时,栈空 、入栈、栈满及出栈的情况如图3.3所示。初始化条 件为S.top=S.base。
…,n-1,n≥0} 数据关系:R={< ai-1,ai>| ai-1,ai∈D,i=1,2
,…,n-1 } 约定an-1端为栈顶,a0端为栈底 基本操作:
(1) 初始化操作:InitStack(&S) 需要条件:栈S没有被创建过 操作结果:构建一个空的栈S (2) 销毁栈:DestroyStack(&S) 需要条件:栈S已经被创建 操作结果:清空栈S的所有值,释放栈S占用的内存空间
return 1;
}
Data structures
栈
第三章C队列
//-------------------基本操作的函数原型说明 基本操作的函数原型说明---------------------基本操作的函数原型说明 Status InitQueue (LinkQueue &Q); //构造一个空队列 构造一个空队列Q 构造一个空队列 Status DestroyQueue (LinkQueue &Q); //销毁队列 ,Q不再存在 销毁队列Q, 不再存在 销毁队列 Status ClearQueue (LinkQueue &Q); //把Q清为空队列 把 清为空队列 Status QueueEmpty (LinkQueue Q); //若队列 为空队列,则返回 若队列Q为空队列 若队列 为空队列,则返回TRUE,否则返回 ,否则返回FALSE Status QueueLength (LinkQueue Q); //返回 的元素个数,即为队列的长度 返回Q的元素个数 返回 的元素个数, Status GetHead (LinkQueue Q, QElemType &e); //若队列不空 则用 返回 的队头元素 并返回 若队列不空,则用 返回Q的队头元素 并返回OK; 若队列不空 则用e返回 的队头元素,并返回 //否则返回 否则返回ERROR 否则返回 Status EnQueue (LinkQueue &Q, QElemType e); //插入元素 为Q新的队尾元素 插入元素e为 新的队尾元素 插入元素 Status DeQueue (LinkQueue &Q, QElemType &e); //若队列不空,则删除 的队头元素,用e返回其值, 若队列不空, 的队头元素, 返回其值 返回其值, 若队列不空 则删除Q的队头元素 //并返回 并返回OK;否则返回 并返回 ;否则返回ERROR Status QueueTraverse (LinkQueue Q, visit () ); //从队头到队尾依次对队列 中每个元素调用函数 从队头到队尾依次对队列Q中每个元素调用函数 从队头到队尾依次对队列 中每个元素调用函数visit(). . //一旦 一旦visit()失败,则操作失败 失败, 一旦 失败
C语言《队列》
Ch3_5.txt
出队算法
Ch3_6.txt
队列的算法描述
– 队列的顺序存储结构
• 实现:用一维数组实现sq[M]
rear J6 5 5 5 5 J5 4 4 4 4 J4 3 3 3 3 rear rear J3 J3 2 2 front 2 2 front rear J2 J2 1 1 1 1 front rear 0 J1 0 0 0 front J1 J4,J5,J6入队 队空 front J1,J1,J3入队 front J1,J2,J3出队 空队列条件:front==rear 入队列:sq[++rear]=x; 出队列:x=sq[++front];
front
队列的算法描述
队空:front==rear 队满:front==rear
4 3
front rear
5 2 0 1
J5 J4 front 初始状态
4 3 5 2 0 1
rear J6
J5 J4 J9 front rear
4 3 5 2 0 1
J6 J7
解决方案: 1.另外设一个标志以区别队空、队满 2.少用一个元素空间: 队空:front==rear 队满:(rear+1)%M==front
• 解决方案
– 队首固定,每次出队剩余元素向下移动——浪费时间 —— – 循环队列 » 基本思想:把队列设想成环形,让sq[0]接在sq[M-1]之 后,若rear+1==M,则令rear=0;
数据结构与算法C版课件第三章栈和队列
不改变栈的状态。
4.栈的存储 (1)采用顺序方式存储的栈称为顺序栈(sequential stack) (2) 采用链接方式存储的栈称为链栈(linked stack)
3.1.2 顺序栈及运算的算法实现
用栈来实现括号匹配检查的原则是,对表达式从左到右扫描。 (1)当遇到左括号时,左括号入栈; (2)当遇到右括号时,首先检查栈是否空,若栈空,则表明该“右括弧”多余;否则比 较栈顶左括号是否与当前右括号匹配,若匹配,将栈顶左括号出栈,继续操作;否则,表明 不匹配,停止操作。 (3)当表达式全部扫描完毕,若栈为空,说明括号匹配,否则表明“左括弧”有多余的。
出队
a1 a2 a3 a4 a5
入队
队列图示
4.队列的应用
5. 在队列上进行的基本运算
(1)队列初始化initQueue(q):构造一个空队列。 (2)判队空emptyQueue(q):若q为空队则返回为1,否
则返回为0。
(3)入队enQueue(q,x):对已存在的队列q,插入一个元素x
到队尾,队发生变化。
队列中元素个数的计算公式。
(4)出队deQueue(q,x):删除队头元素,并通过x返回其值,
队发生变化。
(5)读队头元素frontQueue(q):读队头元素,并返回其值,
队不变。
3.2.2 顺序队列及运算的实现
采用顺序方法存储的队列称为顺序队列(sequential queue)
顺序队列的存储结构用c语言定义如下:
#define MAXSIZE 1024
运算受限的线性 表
表两端插删
VC编程教程 第3章 栈和队列.ppt
下面我们将给出链栈各项基本操作的算法。
1. 初始化栈S PLinkStack Init_LinkStack(void) { /*初始化链栈,入口参数:空,返回值:链栈指针,
NULL表示初始化失败*/ PLinkStack S; S=(PLinkStack)malloc(sizeof(LinkStack)); if (S) S->top=NULL; return (S); }
1 1 -01 1 1 1 0 1 1 1 1 2 1 1 -01 1 0 1 1 1 1 1 3 1 0 1 -01 -01 -01 -01 -01 1 1 4 1 0 1 1 1 -01 1 1 1 1 5 1 1 0 0 1 1 -01 -01 -01 1 6 1 0 1 1 0 0 1 1 -01 1 7 1111111111
A0 出栈
栈顶指针top,指向实际栈顶 位置,初值为-1
设数组维数为M top=-1,栈空,此时出栈,则下溢(underflow) top=M-1,栈满,此时入栈,则上溢(overflow)
存储结构的实现
#define MAXSIZE 100 typedef struct {datatype data[MAXSIZE]; int top; }SeqStack,*PSeqStack;
2)算法的设计
(1)防止重复到达某点的考虑 为避免发生死循环,当到达某点(i,j)后,使
maze[i][j]置-1,以便区分未到达过的顶点。算法结束前可 恢复原迷宫。
(2)算法描述 ① 栈初始化; ②将入口点坐标及初始试探方向(设为-1)入栈,并将
入口点设置为已走过; ③设置found为0(未找到出口点);
[例3-2]利用栈实现迷宫的求解:
第4章栈及队列
4.1.5 栈的链式存储结构——链栈 1.链栈结构及数据类型
它是一种限制运算的链表,即规定链表中的扦入和删 除运算只能在链表开头进行。链栈结构见下图。
top 头
an
an-1
……
栈顶
图 3-5 链栈结构示意图
a1 ^
栈底
单链表的数据结构定义为: typedef struct node
{ elemtype data; //数据域 struct node *next; //指针域
3.出栈: POP(&S) 删除栈S中的栈顶元素,也称为”退栈”、 “删除”、 “弹出”。
4.取栈顶元素: GETTOP(S) 取栈S中栈顶元素。 5.判栈空: EMPTY(S) 判断栈S是否为空,若为空,返回值为1,否则返回值为0。
4.1.3 栈的抽象数据类型描述
ADT Stack {
Data: 含有n个元素a1,a2,a4,…,an,按LIFO规则存放,每个元素的类型都为 elemtype。 Operation: Void inistack(&s) //将栈S置为一个空栈(不含任何元素) Void Push(&s,x) //将元素X插入到栈S中,也称为 “入栈”、 “插 入”、 “压入”
{s->top[0]=-1; s->top[1]=m; }
(2)两个栈共享存储单元的进栈算法 int push(duseqstack *s, elemtype x, int i) //将元素x进入到以S为栈空间的第i个栈中 { if (s->top[0] ==s->top[1]-1) { printf(“overflow”); return (0);} if (i!=0 || i!=1) {printf(“栈参数出错“);return (0);} if(i= =0) //对0号栈进行操作 { s->top[0]++;s->stack[s->top[0]]=x;} else {s->top[1]--; s->stack[s->top[1]]=x;} return (1); }}
数据结构(C语言版)第3章 栈和队列
typedef struct StackNode {
SElemType data;
S
栈顶
struct StackNode *next;
} StackNode, *LinkStack;
LinkStack S;
∧
栈底
链栈的初始化
S
∧
void InitStack(LinkStack &S ) { S=NULL; }
top
C
B
base A
--S.top; e=*S.top;
取顺序栈栈顶元素
(1) 判断是否空栈,若空则返回错误 (2) 否则通过栈顶指针获取栈顶元素
top C B base A
Status GetTop( SqStack S, SElemType &e) { if( S.top == S.base ) return ERROR; // 栈空 e = *( S.top – 1 ); return OK; e = *( S.top -- ); ??? }
目 录 导 航
Contents
3.1 3.2 3.3 3.4 3.5
栈和队列的定义和特点 案例引入 栈的表示和操作的实现 栈与递归 队列的的表示和操作的实现
3.6
案例分析与实现
3.2 案例引入
案例3.1 :一元多项式的运算
案例3.2:号匹配的检验
案例3.3 :表达式求值
案例3.4 :舞伴问题
目 录 导 航
top B base A
清空顺序栈
Status ClearStack( SqStack S ) { if( S.base ) S.top = S.base; return OK; }
ch3-队列课件PPT
根据任务的优先级进行调度,优先 处理优先级高的任务,以提高队列 的整体处理效率。
队列的并发控制
锁机制
无锁数据结构
使用锁机制来控制多个线程对队列的 并发访问,确保队列操作的原子性和 一致性。
使用无锁数据结构来设计队列,以提 高队列的并发性能和可扩展性。
信号量机制
使用信号量机制来控制队列的并发访 问,避免因并发访问而导致的资源竞 争和死锁问题。
队列在图论中的应用
最短路径算法
Dijkstra算法和Bellman-Ford算法是两种常用的求解最短路径问题的算法。它 们都利用了队列来存储待处理的节点,以便按照距离进行优先处理。
拓扑排序
拓扑排序是针对有向无环图的一种排序算法,它将图中的节点按照一定的顺序 排列,使得对于任意一条有向边(u, v),u都在v的前面。拓扑排序利用队列来存 储待处理的节点。
THANKS
感谢观看
清空队列通常使用clear()函数实现,它将删除队列中的 所有元素。
获取队列的大小通常使用size()函数实现,它返回一个 整数表示队列中元素的数量。
03
队列的实现方式
数组实现队列
优点
数组实现队列时,由于数组的索引访 问速度较快,所以添加和删除操作的 时间复杂度为O(1)。
缺点
当队列的大小超过数组大小时,需要 重新分配更大的数组空间,并将原有 元素复制到新数组中,这会导致较大 的空间和时间开销。
ch3-队列课件
• 队列的定义与特点 • 队列的基本操作 • 队列的实现方式 • 队列的典型算法 • 队列的优化与改进
01
队列的定义与特点
队列的基本概念
01
队列是一种特殊的线性表,只允许 在表的前端(front)进行删除操 作,在表的后端(rear)进行插入 操作。
队列数据结构(c语言)
队列是一种特殊的线性表,队列中所有的插入均限定在表的一端进行,而所有的删除则限定在表的另一端进行。
允许插入的一端称为队尾,允许删除的一端称为队头。
队列的特点是先进先出。
下面在VC6环境中用纯C语言编程风格(主函数用int main() )编写小游戏贪吃蛇;蛇身增长数据用队列数据结构记录。
#include <windows.h>#include <stdio.h>#include <stdlib.h>#include <time.h>#define S_SIZE 16#define S_LEN 300#define MOVET 1#define MOVEB 2#define MOVEL 3#define MOVER 4#define MOVE_L_T 5#define MOVE_L_B 6#define MOVE_R_T 7#define MOVE_R_B 8#define MOVE_TB 9#define MOVE_LR 10#define TABLE_TX 80#define TABLE_TY 80#define TABLE_RX 560#define TABLE_RY 400typedef struct SNAKE{int x;int y;int m_state;int s_g;}m_snake;typedef struct GAMESNAKE{m_snake s_h;m_snake s_bn[S_LEN];m_snake s_bo[S_LEN];m_snake s_t;POINT s_H_h;int front;int rear;}Gamesnake;Gamesnake *tmp;typedef struct FOOD{int fx;int fy;int fs_g;int fk;}Food;Food *ft;//-----------头部数据列表--------//向上数据POINT H_top[11]={4,1,2,3,2,12,3,14,3,16,13,16,13,14,14,12,14,3,12,1,4,1}; POINT H_te1[5]={4,3,4,5,6,5,6,3,4,3};POINT H_te2[5]={10,3,10,5,12,5,12,3,10,3};//向左数据POINT H_left[11]={1,4,1,12,3,14,12,14,14,13,16,13,16,3,14,3,12,2,3,2,1,4}; POINT H_le1[5]={3,4,3,6,5,6,5,4,3,4};POINT H_le2[5]={3,10,3,12,5,12,5,10,3,10};//向右数据POINT H_right[11]={0,3,0,13,2,13,4,14,13,14,15,12,15,4,13,2,4,2,2,3,0,3}; POINT H_re1[5]={11,4,11,6,13,6,13,4,11,4};POINT H_re2[5]={11,10,11,12,13,12,13,10,11,10};//向下数据POINT H_bottom[11]={3,0,3,2,2,4,2,13,4,15,12,15,14,13,14,4,13,2,13,0,3,0}; POINT H_be1[5]={4,11,4,13,6,13,6,11,4,11};POINT H_be2[5]={10,11,10,13,12,13,12,11,10,11};//-------------身体数据列表------------//上下数据POINT B_tb[5]={3,0,3,16,13,16,13,0,3,0};//左右数据POINT B_lr[5]={0,3,0,13,16,13,16,3,0,3};//左上数据POINT B_lt[8]={3,8,3,16,13,16,13,13,16,13,16,3,8,3,3,8};//左下数据POINT B_lb[8]={3,0,3,8,8,13,16,13,16,3,13,3,13,0,3,0};//右上数据POINT B_rt[8]={0,3,0,13,3,13,3,16,13,16,13,8,8,3,0,3};//右下数据POINT B_rb[8]={0,3,0,13,8,13,13,8,13,0,3,0,3,3,0,3};//-------------尾部数据列表---------------//向上数据POINT T_top[9]={3,0,3,16,6,16,6,8,10,8,10,16,13,16,13,0,3,0};//向左数据POINT T_left[9]={0,3,0,13,16,13,16,10,8,10,8,6,16,6,16,3,0,3};//向右数据POINT T_right[9]={0,3,0,6,8,6,8,10,0,10,0,13,16,13,16,3,0,3};//向下数据POINT T_bottom[9]={3,0,3,16,13,16,13,0,10,0,10,8,6,8,6,0,3,0};//-------------食物数据列表----------------//食用果数据POINT F_H[9]={4,6,4,10,6,12,10,12,12,10,12,6,10,4,6,4,4,6};//毒果数据POINT S_H[9]={5,7,5,9,7,12,9,12,11,9,11,7,9,4,7,4,5,7};HWND hwnd;static HFONT mFont=CreateFont(-12,0,0,0,400,0,0,0,GB2312_CHARSET,0,0,0,FF_MODERN,"宋体");LRESULT CALLBACK WndProc(HWND hwnd, UINT message,WPARAM wparam,LPARAM lparam){switch(message){case WM_DESTROY:PostQuitMessage(0);break;}return DefWindowProc(hwnd,message,wparam,lparam);}HWND initgraph(int width,int height){HINSTANCE hist=0;WNDCLASS wc;wc.style=CS_HREDRAW|CS_VREDRAW;wc.lpfnWndProc=(WNDPROC)WndProc;wc.cbClsExtra=0;wc.cbWndExtra=0;wc.hInstance=hist;wc.hIcon=LoadIcon(NULL,IDI_WINLOGO);wc.hCursor=LoadCursor(NULL,IDC_ARROW);wc.hbrBackground=(HBRUSH)(COLOR_WINDOW+2);wc.lpszMenuName=NULL;wc.lpszClassName="tm1";RegisterClass(&wc);hwnd=CreateWindow("tm1","贪吃蛇游戏(C语言数据描述——队列)",WS_OVERLAPPEDWINDOW,0,0,width,height,HWND_DESKTOP,NULL,hist,NULL);ShowWindow(hwnd,1);UpdateWindow(hwnd);return hwnd;}int getkeystate(int vk){if(GetAsyncKeyState(vk)&0x8000)return true;elsereturn false;}void ploy(POINT pt[],int ncount){HPEN hp;hp=CreatePen(PS_SOLID,1,RGB(255,255,255));HDC hdc;hdc=GetDC(hwnd);SelectObject(hdc,hp);Polyline(hdc,pt,ncount);DeleteObject(hp);::DeleteDC(hdc);}void drawploy(int x,int y,POINT p[],int ncount){POINT tmp[11];int i;for(i=0;i<ncount;i++){tmp[i].x=p[i].x+x;tmp[i].y=p[i].y+y;}ploy(tmp,ncount);}void bar(int lx,int ty,int rx,int by){HBRUSH hb;HDC hdc;hdc=GetDC(hwnd);hb=CreateSolidBrush(RGB(0,0,0));SelectObject(hdc,hb);HPEN hp;hp=CreatePen(PS_SOLID,1,RGB(255,255,255));SelectObject(hdc,hp);Rectangle(hdc,lx,ty,rx,by);DeleteObject(hb);DeleteObject(hp);::DeleteDC(hdc);}void setfont(int size,char *style){mFont=CreateFont(size,0,0,0,400,0,0,0,GB2312_CHARSET,0,0,0,FF_MODERN,style); }void outtextxy(int x,int y,char *string){HDC hdc;hdc=GetDC(hwnd);SelectObject(hdc,mFont);SetBkMode(hdc,TRANSPARENT);SetTextColor(hdc,RGB(255,255,255));TextOut(hdc,x,y,string,strlen(string));::DeleteDC(hdc);}void initsnake(Gamesnake *t){int sx,sy;sx=320;sy=240;t->rear=0;t->s_h.m_state=MOVET;t->s_h.x=sx;t->s_h.y=sy;t->s_h.s_g=MOVET;t->s_H_h.x=t->s_h.x;t->s_H_h.y=t->s_h.y;t->s_bn[t->rear].m_state=MOVET;t->s_bn[t->rear].x=sx;t->s_bn[t->rear].y=sy+S_SIZE;t->s_bn[t->rear].s_g=MOVE_TB;t->s_t.m_state=MOVET;t->s_t.s_g=MOVET;t->s_t.x=sx;t->s_t.y=t->s_bn[t->rear].y+S_SIZE;t->s_bo[t->rear].m_state=MOVET;t->s_bo[t->rear].x=sx;t->s_bo[t->rear].y=sy+S_SIZE;t->s_bo[t->rear].s_g=MOVE_TB;}void drawsnake(Gamesnake *t){bar(TABLE_TX-2,TABLE_TY-2,TABLE_RX+2,TABLE_RY+2);switch(t->s_h.s_g){case MOVET:drawploy(t->s_h.x,t->s_h.y,H_top,11);drawploy(t->s_h.x,t->s_h.y,H_te1,5);drawploy(t->s_h.x,t->s_h.y,H_te2,5);break;case MOVEB:drawploy(t->s_h.x,t->s_h.y,H_bottom,11);drawploy(t->s_h.x,t->s_h.y,H_be1,5);drawploy(t->s_h.x,t->s_h.y,H_be2,5);break;case MOVEL:drawploy(t->s_h.x,t->s_h.y,H_left,11);drawploy(t->s_h.x,t->s_h.y,H_le1,5);drawploy(t->s_h.x,t->s_h.y,H_le2,5);break;case MOVER:drawploy(t->s_h.x,t->s_h.y,H_right,11);drawploy(t->s_h.x,t->s_h.y,H_re1,5);drawploy(t->s_h.x,t->s_h.y,H_re2,5);break;}for(t->front=0;t->front<=t->rear;t->front++){switch(t->s_bn[t->front].s_g){case MOVE_L_T:drawploy(t->s_bn[t->front].x,t->s_bn[t->front].y,B_lt,8);break;case MOVE_L_B:drawploy(t->s_bn[t->front].x,t->s_bn[t->front].y,B_lb,8);break;case MOVE_R_T:drawploy(t->s_bn[t->front].x,t->s_bn[t->front].y,B_rt,8);break;case MOVE_R_B:drawploy(t->s_bn[t->front].x,t->s_bn[t->front].y,B_rb,8);break;case MOVE_TB:drawploy(t->s_bn[t->front].x,t->s_bn[t->front].y,B_tb,5);break;case MOVE_LR:drawploy(t->s_bn[t->front].x,t->s_bn[t->front].y,B_lr,5);break;}}switch(t->s_t.s_g){case MOVET:drawploy(t->s_t.x,t->s_t.y,T_top,9);break;case MOVEB:drawploy(t->s_t.x,t->s_t.y,T_bottom,9);break;case MOVEL:drawploy(t->s_t.x,t->s_t.y,T_left,9);break;case MOVER:drawploy(t->s_t.x,t->s_t.y,T_right,9);break;}}void move(int x,int y,int mstate,int s_g,Gamesnake *t){t->s_bn[0].x=x;t->s_bn[0].y=y;t->s_bn[0].m_state=mstate;t->s_bn[0].s_g=s_g;for(t->front=1;t->front<=t->rear;t->front++){t->s_bn[t->front].m_state=t->s_bo[t->front-1].m_state;t->s_bn[t->front].s_g=t->s_bo[t->front-1].s_g;t->s_bn[t->front].x=t->s_bo[t->front-1].x;t->s_bn[t->front].y=t->s_bo[t->front-1].y;}t->s_t.m_state=t->s_bo[t->rear].m_state;t->s_t.x=t->s_bo[t->rear].x;t->s_t.y=t->s_bo[t->rear].y;t->s_t.s_g=t->s_t.m_state;for(t->front=0;t->front<=t->rear;t->front++){t->s_bo[t->front].m_state=t->s_bn[t->front].m_state;t->s_bo[t->front].s_g=t->s_bn[t->front].s_g;t->s_bo[t->front].x=t->s_bn[t->front].x;t->s_bo[t->front].y=t->s_bn[t->front].y;}}void movesnake(Gamesnake *t){switch(t->s_h.m_state){case MOVET:if(t->s_H_h.y>TABLE_TY){move(t->s_h.x,t->s_h.y,MOVET,9,t);t->s_h.y-=S_SIZE;t->s_H_h.y=t->s_h.y;}break;case MOVEB:if(t->s_H_h.y<TABLE_RY){move(t->s_h.x,t->s_h.y,MOVEB,9,t);t->s_h.y+=S_SIZE;t->s_H_h.y+=S_SIZE;}break;case MOVEL:if(t->s_H_h.x>TABLE_TX){move(t->s_h.x,t->s_h.y,MOVEL,10,t);t->s_h.x-=S_SIZE;t->s_H_h.x-=S_SIZE;}break;case MOVER:if(t->s_H_h.x<TABLE_RX){move(t->s_h.x,t->s_h.y,MOVER,10,t);t->s_h.x+=S_SIZE;t->s_H_h.x+=S_SIZE;}break;}drawsnake(t);}void selectmove(Gamesnake *t){if(t->s_h.m_state!=MOVEL&&t->s_h.m_state!=MOVER){if(getkeystate(VK_LEFT)){if(t->s_h.m_state==MOVET)move(t->s_h.x,t->s_h.y,MOVEL,MOVE_R_T,t);if(t->s_h.m_state==MOVEB)move(t->s_h.x,t->s_h.y,MOVEL,MOVE_R_B,t);t->s_h.m_state=MOVEL;t->s_h.s_g=MOVEL;t->s_h.x-=S_SIZE;t->s_H_h.x-=S_SIZE;t->s_H_h.y=t->s_h.y;}if(getkeystate(VK_RIGHT)){if(t->s_h.m_state==MOVET)move(t->s_h.x,t->s_h.y,MOVER,MOVE_L_T,t);if(t->s_h.m_state==MOVEB)move(t->s_h.x,t->s_h.y,MOVER,MOVE_L_B,t);t->s_h.m_state=MOVEL;t->s_h.m_state=MOVER;t->s_h.s_g=MOVER;t->s_h.x+=S_SIZE;t->s_H_h.x=t->s_h.x+S_SIZE;t->s_H_h.y=t->s_h.y;}}if(t->s_h.m_state!=MOVET&&t->s_h.m_state!=MOVEB){if(getkeystate(VK_UP)){if(t->s_h.m_state==MOVEL)move(t->s_h.x,t->s_h.y,MOVET,MOVE_L_B,t);if(t->s_h.m_state==MOVER)move(t->s_h.x,t->s_h.y,MOVET,MOVE_R_B,t);t->s_h.m_state=MOVET;t->s_H_h.y-=S_SIZE;t->s_h.y-=S_SIZE;t->s_H_h.x=t->s_h.x;t->s_h.s_g=MOVET;}if(getkeystate(VK_DOWN)){if(t->s_h.m_state==MOVEL)move(t->s_h.x,t->s_h.y,MOVEB,MOVE_L_T,t);if(t->s_h.m_state==MOVER)move(t->s_h.x,t->s_h.y,MOVEB,MOVE_R_T,t);t->s_h.m_state=MOVEB;t->s_h.y+=S_SIZE;t->s_H_h.x=t->s_h.x;t->s_h.s_g=MOVEB;t->s_H_h.y=t->s_h.y+S_SIZE;}}drawsnake(t);}void setfood(Gamesnake *t,Food *f){int i,j,w,h,pos[20][30];time_t st;st=time(NULL);if(st%10==0){for(i=0;i<20;i++)for(j=0;j<30;j++)pos[i][j]=0;w=(t->s_h.x-TABLE_TX)/S_SIZE;h=(t->s_h.y-TABLE_TY)/S_SIZE;pos[h][w]=1;w=(t->s_t.x-TABLE_TX)/S_SIZE;h=(t->s_t.y-TABLE_TY)/S_SIZE;pos[h][w]=1;for(i=0;i<=t->rear;i++){w=(t->s_bn[i].x-TABLE_TX)/S_SIZE;h=(t->s_bn[i].y-TABLE_TY)/S_SIZE;pos[h][w]=1;}srand(time(NULL));while(1){w=rand()%30;h=rand()%20;if(pos[h][w]==0){f->fk=1;f->fs_g=rand()%2;f->fx=w*S_SIZE+TABLE_TX;f->fy=h*S_SIZE+TABLE_TY;break;}}}if(f->fk){if(f->fs_g)drawploy(f->fx,f->fy,F_H,9);elsedrawploy(f->fx,f->fy,S_H,9);}}void add_s_bn(Gamesnake *t){t->rear++;if(t->rear>S_LEN-1){setfont(-24,"宋体");outtextxy(150,220,"蛇太长!");}else{t->s_bn[t->rear].m_state=t->s_t.m_state;t->s_bn[t->rear].x=t->s_t.x;t->s_bn[t->rear].y=t->s_t.y;if(t->s_t.m_state==MOVET){t->s_bn[t->rear].s_g=MOVE_TB;t->s_t.y+=S_SIZE;}if(t->s_t.m_state==MOVEB){t->s_bn[t->rear].s_g=MOVE_TB;t->s_t.y-=S_SIZE;}if(t->s_t.m_state==MOVEL){t->s_bn[t->rear].s_g=MOVE_LR;t->s_t.x+=S_SIZE;}if(t->s_t.m_state==MOVER){t->s_bn[t->rear].s_g=MOVE_LR;t->s_t.x-=S_SIZE;}t->s_bo[t->rear].m_state=t->s_bn[t->rear].m_state;t->s_bo[t->rear].s_g=t->s_bn[t->rear].s_g;t->s_bo[t->rear].x=t->s_bn[t->rear].x;t->s_bo[t->rear].y=t->s_bn[t->rear].y;}}void OutScore(Gamesnake *t){char s[100];sprintf(s,"%d",t->rear*100);bar(250,30,350,60);setfont(-16,"宋体");outtextxy(260,35,s);}void getfood(Gamesnake *t,Food *f){if(f->fk&&f->fs_g){if(t->s_h.x==f->fx&&t->s_h.y==f->fy){add_s_bn(t);OutScore(t);f->fk=0;}}}void delay(int val){int i,vk=0;while(1){vk++;for(i=0;i<100000;i++);;if(vk>val)break;}}int gameover(Gamesnake *t,Food *f){if(t->s_H_h.x==TABLE_TX||t->s_H_h.x==TABLE_RX)return true;if(t->s_H_h.y==TABLE_TY||t->s_H_h.y==TABLE_RY)return true;for(t->front=0;t->front<=t->rear;t->front++){if(t->s_h.m_state==MOVET){if(t->s_bn[t->front].x==t->s_H_h.x&&t->s_bn[t->front].y+S_SIZE==t->s_H_h.y) return true;if(t->s_t.x==t->s_H_h.x&&t->s_t.y+S_SIZE==t->s_H_h.y)return true;if(f->fk&&f->fs_g==0)if(t->s_H_h.x==f->fx&&t->s_H_h.y==f->fy+S_SIZE)return true;}if(t->s_h.m_state==MOVEL){if(t->s_bn[t->front].x+S_SIZE==t->s_H_h.x&&t->s_bn[t->front].y==t->s_H_h.y) return true;if(t->s_t.x+S_SIZE==t->s_H_h.x&&t->s_t.y==t->s_H_h.y)return true;if(f->fk&&f->fs_g==0)if(t->s_H_h.x==f->fx+S_SIZE&&t->s_H_h.y==f->fy)return true;}if(t->s_h.m_state==MOVEB||t->s_h.m_state==MOVER){if(t->s_bn[t->front].x==t->s_H_h.x&&t->s_bn[t->front].y==t->s_H_h.y)return true;if(t->s_t.x==t->s_H_h.x&&t->s_t.y==t->s_H_h.y)return true;if(f->fk&&f->fs_g==0)if(t->s_H_h.x==f->fx&&t->s_H_h.y==f->fy)return true;}}if(f->fk&&f->fs_g==0)if(t->s_h.x==f->fx&&t->s_h.y==f->fy)return true;return false;}void g_draw(){if(!gameover(tmp,ft)){movesnake(tmp);selectmove(tmp);setfood(tmp,ft);getfood(tmp,ft);delay(2000);}else{setfont(-24,"宋体");outtextxy(270,430,"游戏结束!");}}void DrawFunc(void draw()){MSG msg;BOOL fmsg;PeekMessage(&msg,NULL,0U,0U,PM_NOREMOVE);while(msg.message!=WM_QUIT){fmsg=PeekMessage(&msg,NULL,0U,0U,PM_REMOVE);if(fmsg){TranslateMessage(&msg);DispatchMessage(&msg);}elsedraw();}}int main(){initgraph(640,520);tmp=(Gamesnake *)malloc(sizeof(Gamesnake));ft=(Food *)malloc(sizeof(Food));initsnake(tmp);setfont(-16,"宋体");outtextxy(200,35,"分数:");DrawFunc(g_draw);return 0;}关于贪吃蛇游戏:(1)、蛇的组合:头部、身体和尾巴组成。
C语言基础——队列详细讲解!
C语⾔基础——队列详细讲解!队列(Queue)⼀般的顺序队列:由于这种结构会有假溢出的情况,所以⼀般不选择这种队列,⽽更多的使⽤循环队列。
循环队列:判断队列满的情况:1、count来计数;通常使⽤countCount等于队列的MAXSIZE2、Flag标志 int⼊队列 flag=1 出队列flag=0Front=rear&&flag==03、把⼀个存储单元空出来,不存放数据Rear 1==front注意事项:(不要)顺序结构,SeqQueue myQueue;链式:malloc(C语⾔C 交流学习群560655063)初始化://(1)初始化void SeqQueueInit(SeqQueue *Q){Q->front = 0;Q->rear = 0;Q->count = 0;}//(2)⼊队int SeqQueueIn(SeqQueue *Q, intdata){if (Q->count > 0 && Q->rear == Q->front){printf('队列满!\n');return 0;}else{Q->data[Q->rear] = data; //把数据赋给队尾元素Q->rear = (Q->rear 1) % MAXSIZE; //让对位移动⼀个位置 1Q->count ; //计数器 1return 1;}}//(3)出队列int SeqQueueOut(SeqQueue *Q,int *data){if (Q->count == 0){printf('队列空\n');return 0;}else{*data = Q->data[Q->front];Q->front = (Q->front 1) % MAXSIZE;Q->count--;}}//释放:不要,数组是连续的存储空间,队列的⼤⼩10,队列⾥⾯有没有内容,都是10个⼤⼩。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
原因:
被删除元素的空间没有再被使用
每次出队时向前移一位置。 解决: 大量移动元素 循环队列
11
采用循环队列克服“假上溢”
sq->r
MAXNUM-1
。 。 。
0 1
sq->f
指针移动方向
12
4.5.1 顺序队列
采用循环队列克服“假上溢” 入队:if (sq->r+1>=MAXNUM) sq->r=0; else sq->r++;
3
4.5 队列的实现
4.5.1. 顺序队列 4.5.2. 链队列
4
4.5.1 顺序队列
队列的顺序存储结构简称为顺序队列。顺序队 列实际上是运算受限的顺序表。
由于队列的队头和队尾的位置均是变化的,因
而要设置两个指针,分别指示当前队头元素和队尾 元素在向量空间中的位置。
5
4.5.1 顺序队列
顺序队列的定义
进队列
EnQueue(int value) { //要先判断队列是否已满 if ((tail + 1) % QUEUE_SIZE == head) { printf("队列已满,无法从队尾插入元素\n"); } else { queue[tail] = value; tail = (tail + 1) % QUEUE_SIZE; } }
29
2. 判队空
int isEmptyQueue_seq( PSeqQueue sq ) { return (sq->f == sq->r); }
30
3. 取队头元素
DataType frontQueue_seq( PSeqQueue sq ) /* 对非空队列,求队列头部元素 */ { return (sq->q[sq->f]); }
r
k4
k5 k6 k7 k8 ③队列满
4
5 6 7 ②约定
f r
k7 k8
r
①队列空
④队列数组越界
4.5.1 顺序队列
顺序队列的入队和出队 开;data[sq->r]=x; sq->r++;
出队: sq->f++;
8
4.5.1 顺序队列
元素个数(队列长度):(sq->r) - (sq->f)
* */ int IsFull(){ if ((tail + 1) % QUEUE_SIZE == head) { printf("队列已满\n"); return 1; } printf("队列未满\n"); return 0;
}
/打印出队列元素 void PrintQueue(){ for (int i = head; i < tail; i++) { printf("%d ",queue[i]); } printf("\n"); }
39
2. 判队空(算法4.22)
int isEmptyQueue_link( PLinkQueue plqu ) {
return (plqu->f == NULL);
}
40
3. 取队头结点数据(算法4.25)
DataType frontQueue_link( PLinkQueue plqu ) /* 在非空队列中求队头元素 */ { return (plqu->f->info); }
#include<stdio.h> #define QUEUE_SIZE 200 int queue[QUEUE_SIZE]; int head=0;//头指针 int tail=0;//尾指针
int main() { EnQueue(4);EnQueue(1);EnQueue( 2);EnQueue(9);EnQueue(8); PrintQueue(); DeQueue();DeQueue(); PrintQueue(); return 0;
若(sq->r) - (sq->f)=0 ,则队列长度 为0,即空队列。再出队会“下溢”
若 (sq->r)-(sq->f)=MAXNUM,则队满。 队满时再入队会“上溢”
9
顺序队列
f r
0 1 2 3
f
k1 k2 k3
r
4
5 6 7
f r
k5 k6
队列空
队列数组越界
4.5.1 顺序队列
假上溢:当前队列并不满,但不能入队。
利用模运算 sq->r=(sq->r+1)%MAXNUM
出队: sq->f=(sq->f+1)%MAXNUM
13
4.5.1 顺序队列
判断队空和队满
某一元素出队后,若头指针已从后面追上尾指针, 则当前队列为空: sq->f=sq->r
某一元素入队后,若尾指针已从后面追上头指针, 则当前队列为满:
sq->f=sq->r
4.4 队列 队列的概念及运算(逻辑结构)
1
队列的概念
队列 只允许在表的一端进行插入,而在另一端 进行删除。 队头 队尾 允许删除的一端 允许插入的一端
队列是先进先出表
出队
a1
队头
a2
...
an
队尾
入队
2
队列的运算
队列的基本运算:
•
• • • •
创建一个空队列 Queue createEmptyQueue ( void ) 判队列是否为空队列 int isEmptyQueue ( Queue qu ) 往队列中插入一个元素 void enQueue ( Queue qu, DataType x ) 从队列中删除一个元素 void deQueue ( Queue qu ) 求队列头部元素的值 DataType frontQueue ( Queue qu )
an-3 . .
n-3
rear= n-1
front=n-3
an-2 n-2 . . 1 0 rear= n-1
插入元素0:1 rear 顺时针移动一位 MaxQsize-1 2
…… an-3 an-2 x
rear=0 an-3 . .
n-3
front=n-3 front=n-3
an-2 n-2 . . 1 x rear = (rear+1) MOD MaxQSize n-1
队列的链接表示
struct Node; typedef struct Node *pNode; struct Node { DataType info; pNode link; }; struct LinkQueue { PNode f; PNode r; }; typedef struct LinkQueue, *PLinkQueue;
32
5. 出队
void deQueue_seq( PSeqQueue sq ) /* 删除队列头部元素 */ { if( sq->f == sq->r ) printf( "Empty Queue.\n" ); else sq->f = (sq->f + 1) % MAXNUM;
}
33
4.5.2 链队列
31
4. 入队
void enQueue_seq( PSeqQueue sq, DataType x ) /* 在队列中插入一元素x */ { if( (sq->r + 1) % MAXNUM == sq->f ) printf( "Full queue.\n" ); else { sq->q[sq->r] = x; sq->r = (sq->r + 1) % MAXNUM; } }
k2 k3 k4 k5 k6 k1
sq.front
sq.rear
k7
图(a) 空队列
图(b) 队列满
图4.9
循环队列
4.5.1 顺序队列
在循环队列上实现五种基本运算: 1.置空队
2.判队空
3.取队头元素 4.入队 5.出队
17
循环队列
0
1 2
front= n-3
MaxQsize-1
…… an-3 an-2
/判断队列是否为空 int IsEmpty() { if (head == tail) { printf("队列为空\n"); return 1; }
printf("队列不为空\n"); return 0;
}
判断队列是否已满
/** * 我这里判断队满的的方法:
牺牲一个单元来区分队空和队满,入队时少 用一个队列单元。如果数组的大小为Size,那 么实际只能存放(Size-1)个元素。(这是比 较常用的判满的方式)
队列的链式存储结构简称为链队列,它是限制仅在 表头删除和表尾插入的单链表。
显然仅有单链表的头指针不便于在表尾做插入操作, 为此再增加一个尾指针,指向链表上的最后一个结点。 于是,一个链队列由一个头指针和一个尾指针唯一地确
定。
34
plqu f r
k0 k1 k2
….
kn-1
图4.10 队列的链接表示
0 rear=0
删除元素:front顺时针移动一位
front = (front+1) MOD MaxQSize;
. .
..
D
C
0
删除C
front=9
. .
.. 1
D rear
1 rear