收藏 分享(赏)

算法与数据结构第3章 栈和队列.ppt

上传人:dzzj200808 文档编号:2172664 上传时间:2018-09-03 格式:PPT 页数:94 大小:814.50KB
下载 相关 举报
算法与数据结构第3章 栈和队列.ppt_第1页
第1页 / 共94页
算法与数据结构第3章 栈和队列.ppt_第2页
第2页 / 共94页
算法与数据结构第3章 栈和队列.ppt_第3页
第3页 / 共94页
算法与数据结构第3章 栈和队列.ppt_第4页
第4页 / 共94页
算法与数据结构第3章 栈和队列.ppt_第5页
第5页 / 共94页
点击查看更多>>
资源描述

1、第3章 栈和队列,3.1 栈 3.2 队列,3.1 栈,3.1.1 栈的定义栈作为一种限定性线性表,是将线性表的插入和删除运算限制为仅在表的一端进行,通常将表中允许进行插入、删除操作的一端称为栈顶(Top),因此栈顶的当前位置是动态变化的,它由一个称为栈顶指针的位置指示器指示。同时表的另一端被称为栈底(Bottom)。当栈中没有元素时称为空栈。栈的插入操作被形象地称为进栈或入栈,删除操作称为出栈或退栈。,图3.1 栈,ADT Stack数据元素: 可以是任意类型的数据,但必须属于同一个数据对象。 关系: 栈中数据元素之间是线性关系。 基本操作: (1) InitStack(S) 操作前提: S

2、为未初始化的栈。 操作结果: 将S初始化为空栈。 (2) ClearStack(S) 操作前提: 栈S已经存在。 操作结果: 将栈S置成空栈。,(3) IsEmpty(S) 操作前提:栈S已经存在。 操作结果:判栈空函数,若S为空栈,则函数值为TRUE,否则为FALSE。 (4) IsFull(S) 操作前提: 栈S已经存在。 操作结果: 判栈满函数,若S栈已满,则函数值为TRUE, 否则为FALSE。 ,(5) Push(S,x) 操作前提:栈S已经存在。 操作结果:在S的顶部插入(亦称压入)元素x;若S栈未满,将x插入栈顶位置,若栈已满,则返回FALSE,表示操作失败,否则返回TRUE。

3、(6) Pop(S, x) 操作前提:栈S已经存在。 操作结果:删除(亦称弹出)栈S的顶部元素,并用x带回该值;若栈为空,返回值为FALSE,表示操作失败,否则返回TRUE。(7) GetTop(S, x) 操作前提: 栈S已经存在。 操作结果:取栈S的顶部元素。与Pop(S, x)不同之处在于GetTop(S,x)不改变栈顶的位置。 ,3.1.2 栈的表示和实现,1. 顺序栈顺序栈是用顺序存储结构实现的栈,即利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素,同时由于栈的操作的特殊性, 还必须附设一个位置指针top(栈顶指针)来动态地指示栈顶元素在顺序栈中的位置。通常以top=-1表示

4、空栈。顺序栈的存储结构可以用C语言中的一维数组来表示。 栈的顺序存储结构定义如下:,define TRUE 1 define FALSE 0 define Stack-Size 50 typedef struct StackElementType elemStack-Size; /*用来存放栈中元素的一维数组*/ int top; /*用来存放栈顶元素的下标*/ SeqStack;,图3.2 顺序栈中的进栈和出栈,顺序栈基本操作的实现如下: (1) 初始化。,void InitStack(SeqStack *S) /*构造一个空栈S*/S-top= -1; (2) 判栈空。 int IsEmp

5、ty(SeqStack *S) /*判栈S为空栈时返回值为真, 反之为假*/ return(S-top=-1?TRUE:FALSE); ,(3) 判栈满。 int IsFull(SeqStack *S) return(S-top = Stack-Size?TRUE:FALSE); (4) 进栈。 int Push(SeqStack *S, StackElementType x) if(S-top= Stack-Size) return(FALSE); /*栈已满*/ S-top+; S-elemS-top=x; return(TRUE); ,(5) 出栈。 int Pop(SeqStack *

6、 S, StackElementType *x) /* 将栈S的栈顶元素弹出, 放到x所指的存储空间中 */ if(S-top=-1) /*栈为空*/return(FALSE); else *x= S-elemS-top;S-top-; /* 修改栈顶指针 */return(TRUE); ,(6) 取栈顶元素。 int GetTop(SeqStack S, StackElementType *x) /* 将栈S的栈顶元素弹出, 放到x所指的存储空间中, 但栈顶指针保持不变 */ if(S-top=-1) /*栈为空*/ return(FALSE); else *x = S-elemS-top;

7、return(TRUE); ,在栈的共享技术中最常用的是两个栈的共享技术: 它主要利用了栈“栈底位置不变,而栈顶位置动态变化”的特性。首先为两个栈申请一个共享的一维数组空间SM,将两个栈的栈底分别放在一维数组的两端,分别是0, M-1。 由于两个栈顶动态变化,这样可以形成互补,使得每个栈可用的最大空间与实际使用的需求有关。由此可见,两栈共享比两个栈分别申请M/2的空间利用率高。 两栈共享的数据结构定义如下:,define M 100 typedef struct StackElementType StackM; StackElementType top2; /*top0和top1分别为两个栈顶

8、指示器*/ DqStack;,图3.3 共享栈,初始化操作。 void InitStack(DqStack *S) S-top0=-1; S-top1=M; ,(2) 进栈操作算法。 int Push(DqStack *S, StackElementType x, int i) /*把数据元素x压入i号堆栈*/ if(S-top0+1=S-top1) /*栈已满*/return(FALSE); switch(i) case 0: S-top0+;,S-StackS-top0=x; break; case 1: S-top1-; S-StackS-top1=x; break; default:

9、/*参数错误*/ return(FALSE) return(TRUE); ,(3) 出栈操作算法。 int Pop(DqStack *S, StackElementType *x, int i) /* 从i 号堆栈中弹出栈顶元素并送到x中 */ switch(i) case 0: if(S-top0=-1) return(FALSE); *x=S-StackS-top0; S-top0-; break;case 1: if(S-top1=M) return(FALSE); *x=S-StackS-top1; S-top1+; break;default: return(FALSE); retu

10、rn(TRUE); ,2. 链栈,图3.4 链栈示意图,链栈的结构可用C语言定义如下:,typedef struct node StackElementType data;struct node *next; LinkStackNode; typedef LinkStackNode *LinkStack;,(1) 进栈操作。,int Push(LinkStack top, StackElementType x) /* 将数据元素x压入栈top中 */ LinkStackNode * temp; temp=(LinkStackNode * )malloc(sizeof(LinkStackNode

11、); if(temp=NULL) return(FALSE); /* 申请空间失败 */ temp-data=x; temp-next=top-next; top-next=temp; /* 修改当前栈顶指针 */ return(TRUE); ,(2) 出栈操作。,int Pop(LinkStack top, StackElementType *x) /* 将栈top的栈顶元素弹出, 放到x所指的存储空间中 */ LinkStackNode * temp; temp=top-next; if(temp=NULL) /*栈为空*/ return(FALSE); top-next=temp-nex

12、t; *x=temp-data; free(temp); /* 释放存储空间 */ return(TRUE); ,3.1.3 栈的应用举例,1. 数制转换假设要将十进制数N转换为d进制数,一个简单的转换算法是重复下述两步, 直到N等于零: X = N mod d (其中mod为求余运算) N = N div d (其中div为整除运算),void Conversion(int N) /*对于任意的一个非负十进制数N, 打印出与其等值的二进制数*/ Stack S; int x; /* S为顺序栈或链栈 */ InitStack( ,2. 括号匹配问题假设表达式中包含三种括号:圆括号、 方括号和

13、花括号, 它们可互相嵌套, 如( ( ) )或( ( ( ) ) )等均为正确的格式, 而 ) 或 ( ) 或( 均为不正确的格式。 在检验算法中可设置一个栈, 每读入一个括号,若是左括号,则直接入栈, 等待相匹配的同类右括号;若读入的是右括号, 且与当前栈顶的左括号同类型,则二者匹配, 将栈顶的左括号出栈, 否则属于不合法的情况。另外,如果输入序列已读尽,而栈中仍有等待匹配的左括号,或者读入了一个右括号,而栈中已无等待匹配的左括号,均属不合法的情况。当输入序列和栈同时变为空时, 说明所有括号完全匹配。,void BracketMatch(char *str) = /* str中为输入的字符串

14、, 利用堆栈技术来检查该字符串中的括号是否匹配*/ = Stack S; int i; char ch; InitStack( i+) /*对字符串中的字符逐一扫描*/ switch(stri) case (: case : case :,Push( /*已匹配的左括号出栈*/,else printf(n对应的左右括号不同类!); return; /*switch*/ /*for*/ if(IsEmpty(S) printf(n括号匹配!); elseprintf(n左括号多余!); ,3. 表达式求值,表达式求值是高级语言编译中的一个基本问题, 是栈的典型应用实例。 任何一个表达式都是由操作

15、数(operand)、 运算符(operator)和界限符(delimiter)组成的。操作数既可以是常数, 也可以是被说明为变量或常量的标识符;运算符可以分为算术运算符、 关系运算符和逻辑运算符三类;基本界限符有左右括号和表达式结束符等。,1) 无括号算术表达式求值,表达式计算程序设计语言中都有计算表达式的问题, 这是语言编译中的典型问题。 (1) 表达式形式: 由运算对象、 运算符及必要的表达式括号组成; (2) 表达式运算: 运算时要有一个正确的运算形式顺序。 由于某些运算符可能具有比别的运算符更高的优先级,因此表达式不可能严格的从左到右, 见图3.5。,图3.5 表达式运算及运算符优先

16、级,图3.6 无括号算术表达式的处理过程,2) 算术表达式处理规则(1) 规定优先级表。(2) 设置两个栈: OVS(运算数栈)和OPTR(运算符栈)。(3) 自左向右扫描,遇操作数进OVS,遇操作符则与OPTR栈顶优先数比较:当前操作符OPTR栈顶, 当前操作符进OPTR栈当前操作符OPTR栈顶,OVS栈顶、次顶和OPTR栈顶,退栈形成运算T(i),T(i)进OVS栈。例: 实现A/BC+D*E的运算过程时栈区变化情况如图3.7所示。,图3.7 A/BC+D*E运算过程的栈区变化情况示意图,3) 带括号算术表达式假设操作数是整型常数,运算符只含加、减、乘、除等四种运算符, 界限符有左右括号和

17、表达式起始、结束符“”,如: (7+15)*(23-28/4)。 引入表达式起始、 结束符是为了方便。 要对一个简单的算术表达式求值, 首先要了解算术四则运算的规则, 即: (1) 从左算到右; (2) 先乘除, 后加减; (3) 先括号内, 后括号外。,运算符和界限符可统称为算符,它们构成的集合命名为OPS。根据上述三条运算规则,在运算过程中,任意两个前后相继出现的算符1和2之间的优先关系必为下面三种关系之一: 12, 1的优先权高于2。,表 3-1 算符之间的优先关系,实现算符优先算法时需要使用两个工作栈: 一个称作operator, 用以存放运算符;另一个称作operand,用以存放操作

18、数或运算的中间结果。 算法的基本过程如下:首先初始化操作数栈operand和运算符栈operator, 并将表达式起始符“”压入运算符栈;依次读入表达式中的每个字符,若是操作数则直接进入操作数栈operand, 若是运算符,则与运算符栈operator的栈顶运算符进行优先权比较,并做如下处理: ,(1) 若栈顶运算符的优先级低于刚读入的运算符, 则让刚读入的运算符进operator栈; (2) 若栈顶运算符的优先级高于刚读入的运算符,则将栈顶运算符退栈,送入,同时将操作数栈operand退栈两次,得到两个操作数a、b,对a、 b进行运算后, 将运算结果作为中间结果推入operand栈; (3)

19、 若栈顶运算符的优先级与刚读入的运算符的优先级相同,说明左右括号相遇,只需将栈顶运算符(左括号)退栈即可。,算法具体描述如下:,int ExpEvaluation() /*读入一个简单算术表达式并计算其值。 operator和operand分别为运算符栈和运算数栈, OPS为运算符集合*/ InitStack( while(ch!=|GetTop(operator)! =) /* GetTop()通过函数值返回栈顶元素*/,if(!In(ch,OPS) a=GetNumber(,Pop( ,3.1.4 栈与递归的实现,栈非常重要的一个应用是在程序设计语言中用来实现递归。 递归是指在定义自身的同

20、时又出现了对自身的调用。 如果一个函数在其定义体内直接调用自己,则称其为直接递归函数;如果一个函数经过一系列的中间调用语句, 通过其它函数间接调用自己,则称其为间接递归函数。,1. 递归特性问题,1) 递归函数 例如, 很多数学函数是递归定义的, 如二阶Fibonacci数列:,2) 递归结构,例:n阶Hanoi塔问题:假设有三个分别命名为X、Y和Z的塔座, 在塔座X上插有n个直径大小各不相同、依小到大编号为1, 2, , n的圆盘。现要求将X轴上的n个圆盘移至塔座Z上并仍按同样顺序叠排,圆盘移动时必须遵循下列原则: (1) 每次只能移动一个圆盘; (2) 圆盘可以插在X、 Y和Z中的任何一个

21、塔座上; (3) 任何时刻都不能将一个较大的圆盘压在较小的圆盘之上。,如何实现移动圆盘的操作呢?当n=1时,问题比较简单,只要将编号为1的圆盘从塔座X直接移动到塔座Z上即可;当n1时, 需利用塔座Y作辅助塔座, 若能设法将压在编号为n的圆盘上的n-1个圆盘从塔座X(依照上述原则)移至塔座Y上, 则可先将编号为n的圆盘从塔座X 移至塔座Z上,然后再将塔座Y上的n-1个圆盘(依照上述原则)移至塔座Z上。而如何将n-1个圆盘从一个塔座移至另一个塔座问题是一个和原问题具有相同特征属性的问题,只是问题的规模小个1,因此可以用同样方法求解。 由此可得如下算法所示的求解n阶Hanoi塔问题的函数。,void

22、 hanoi(int n,char x,char y,char z) /*将塔座X上按直径由小到大且至上而下编号为1至n的n个圆盘按规则搬到塔座Z上, Y可用作辅助塔座 */ if(n=1) move(x,1,z); /* 将编号为1的圆盘从X移动Z */else hanoi(n-1,x,z,y); /* 将X上编号为1至n-1的圆盘移到Y,Z作辅助塔 */ move(x,n,z); /* 将编号为n的圆盘从X移到Z */ hanoi(n-1,y,x,z); /* 将Y上编号为1至n-1的圆盘移动到Z, X作辅助塔 */ ,下面给出三个盘子搬动时hanoi(3, A, B, C) 递归调用过程

23、, 如图3.8所示。,hanoi(2,A,C,B):hanoi(1,A,B,C) move(A-C) 1号搬到Cmove(A-B) 2号搬到Bhanoi(1,C,A,B) move(C-B) 1号搬到Bmove(A-c) 3号搬到Chanoi(2,B,A,C):hanoi(1,B,C,A) move(B-A) 1号搬到Amove(B-c) 2号搬到Chanoi(1,A,B,C) move(A-C) 1号搬到C,图3.8 Hanoi塔的递归函数运行示意图,3) 递归问题的优点通过上面的例子可看出,递归既是强有力的数学方法, 也是程序设计中一个很有用的工具。其特点是对递归问题描述简捷,结构清晰,程

24、序的正确性容易证明。 4) 递归算法求解问题的要素递归算法就是算法中有直接或间接调用算法本身的算法。 递归算法的要点如下: (1) 问题具有类同自身的子问题的性质, 被定义项在定义中的应用具有更小的尺度。 (2) 被定义项在最小尺度上有直接解。,设计递归算法的方法是: (1) 寻找方法,将问题化为原问题的子问题求解(例n!=n*(n-1)!)。 (2) 设计递归出口,确定递归终止条件(例求解n!时,当n=1时,n! =1)。 ,5) 递归过程的实现递归进层(ii+1层)系统需要做三件事: (1) 保留本层参数与返回地址(将所有的实在参数、 返回地址等信息传递给被调用函数保存); (2) 给下层

25、参数赋值(为被调用函数的局部变量分配存储区); (3) 将程序转移到被调函数的入口。 ,而从被调用函数返回调用函数之前,递归退层(ii+1层)系统也应完成三件工作: (1) 保存被调函数的计算结果; (2) 恢复上层参数(释放被调函数的数据区); (3) 依照被调函数保存的返回地址, 将控制转移回调用函数。,2. 递归算法到非递归算法转换递归算法具有两个特性: (1) 递归算法是一种分而治之、把复杂问题分解为简单问题的求解问题方法,对求解某些复杂问题,递归算法的分析方法是有效的。 (2) 递归算法的时间效率低。,1) 消除递归的原因其一:有利于提高算法时空性能,因为递归执行时需要系统提供隐式栈

26、实现递归,效率低且费时。 其二: 无应用递归语句的语言设施环境条件,有些计算机语言不支持递归功能,如FORTRAN、 C语言中无递归机制 。 其三:递归算法是一次执行完,这在处理有些问题时不合适, 也存在一个把递归算法转化为非递归算法的需求。,2) 简单递归(尾递归和单向递归)消除在简单情况下, 将递归算法可简化为线性序列执行, 可直接转换为循环实现。,例:,n=最小尺度(由自然数1直接定义),n1,其递归算法如下,,int f(int n ) /*设n0 */ if n=0 then return(1) else return(n*f(n-1); ,图3.9 递归调用变化情况示意,递归进层三

27、件事: 保存本层参数、 返回地址; ;传递参数, 分配局部数据空间;控制转移。 递归退层三件事: 恢复上层;传递结果;转断点执行。,图3.10 f(3)递归调用流程变化示意,由图3.11可看出,整个计算包括自上而下递归调用进层和自下而上递归返回退层两个阶段,所有递归调用直接或间接依赖f(0),所以整个阶段分两步,计算顺序在第二阶段,先计算f(0)f(1)f(n),工作变量y记录中间结果。,例: 斐波那契数列,斐波那契数列的递归算法Fib(n)如下,,Fib(int n) if(n= =0|n= =1) return n; /* 递归出口 */ else return Fib(n-1)+Fib(

28、n-2); /* 递归调用 */,图3.11 Fib(5)递归调用过程示意,3-12 Fib(5)循环调用过程示意图,单向递归的一个典型例子是我们讨论过的计算斐波那契数列的算法Fib(n)。 其中,递归调用语句Fib(n-1)和Fib(n-2)只与主调用函数Fib(n)有关,相互之间参数无关,并且这些递归调用语句也和尾递归一样处于算法的最后。,int Fib(int n): int x,y,z; if(n=0|n=1) return n; /*计算 Fib(0) , Fib(1) */ else int x=0, y=1,z;,/ * x=Fib(0), y=Fib(1) */for( i=2

29、;i= n; i + ) z=y; /* z=Fib(i-1) */ =y=x+y; /* y=Fib(i-1)+Fib(i-2), 求Fib(i),形成第i项 */ x=z; /* x=Fib(i-1) */ return y ; ,尾递归 是指递归调用语句只有一个,而且是处于算法的最后。 我们以阶乘问题的递归算法Fact(n)为例讨论尾递归算法的运行过程。为讨论方便, 我们列出阶乘问题的递归算法Fact(n), 并简化掉参数n的出错检查语句, 改写递归调用语句的位置在最后,算法如下:,long Fact(int n) if(n=0) return 1; return n * Fact(n-

30、1); ,循环结构的阶乘问题算法Fact(n)如下:,long Fact(int n) int fac=1; for(int i=1;i=n;i+) /*依次计算f(1), , f(n)*/ fac=fac* i; /* f(i)= f(i) * i */ return fac; ,3.2 队 列,3.2.1 队列的定义队列 (Queue)是另一种限定性的线性表,它只允许在表的一端插入元素,而在另一端删除元素,所以队列具有先进先出(Fist In Fist Out, 缩写为FIFO)的特性。在队列中,允许插入的一端叫做队尾(rear),允许删除的一端则称为队头(front)。 假设队列为q=(

31、a1,a2,an),那么a1就是队头元素,an则是队尾元素。队列中的元素是按照a1,a2,an的顺序进入的, 退出队列也必须按照同样的次序依次出队,也就是说,只有在a1,a2,an-1都离开队列之后,an才能退出队列。,数据元素:可以是任意类型的数据,但必须属于同一个数据对象。 关系: 队列中数据元素之间是线性关系。 基本操作: (1) InitQueue(&Q): 初始化操作。 设置一个空队列。 (2) IsEmpty(Q): 判空操作。 若队列为空, 则返回TRUE, 否则返回FALSE。 (3)EnterQueue(&Q,x):进队操作。在队列Q的队尾插入x。 操作成功,返回值为TRUE

32、, 否则返回值为FALSE。 ,(4) DeleteQueue(&Q,&x): 出队操作。使队列Q的队头元素出队, 并用x带回其值。 操作成功,返回值为RUE, 否则返回值为FALSE。 (5) GetHead(Q,&x): 取队头元素操作。用x取得队元素的值。操作成功,返回值为TRUE,否则返回值为FALSE。 (6) ClearQueue(&Q): 队列置空操作。 将队列Q置为空队列。 (7) DestroyQueue(&Q): 队列销毁操作。 释放队列的空间。,3.2.2 队列的表示和实现,1. 链队列,图3.13 链队列,链队列可以定义如下:,define TRUE 1 define

33、FALSE 0 typedef struct Node QueueElementType data; /*数据域*/ struct Node next; /*指针域*/LinkQueueNode;typedef struct LinkQueueNode *front; LinkQueueNode *rear; LinkQueue;,(1) 初始化操作。 int InitQueue(LinkQueue *Q) /* 将Q初始化为一个空的链队列 */ Q-front=(LinkQueueNode *)malloc(sizeof(LinkQueueNode); if(Q-front! =NULL)

34、Q-rear=Q-front; Q-front-next=NULL; return(TRUE); else return(FALSE); /* 溢出!*/ ,(2) 入队操作。 int EnterQueue(LinkQueue *Q, QueueElementType x) /* 将数据元素x插入到队列Q中 */ LinkQueueNode *NewNode; NewNode=(LinkQueueNode * )malloc(sizeof(LinkQueueNode); if(NewNode! =NULL) NewNode-data=x; NewNode-next=NULL; Q-rear-n

35、ext=NewNode; Q-rear=NewNode; return(TRUE); else return(FALSE); /* 溢出!*/ ,(3) 出队操作。 int DeleteQueue(LinkQueue * Q, QueueElementType *x) /* 将队列Q的队头元素出队, 并存放到x所指的存储空间中 */ LinkQueueNode *p; if(Q-front=Q-rear)return(FALSE); p=Q-front-next; Q-front-next=p-next; /* 队头元素p出队 */ if(Q-rear=p) /* 如果队中只有一个元素p, 则

36、p出队后成为空队 */Q-rear=Q-front; *x=p-data; free(p); /* 释放存储空间 */ return(TRUE); ,2. 循环队列,图3.14 队列的基本操作,图3.15 循环队列,循环队列的类型定义: define MAXSIZE 50 /*队列的最大长度*/ typedef struct QueueElementType elementMAXSIZE; /* 队列的元素空间*/ int front; /*头指针指示器*/ int rear ; /*尾指针指示器*/ SeqQueue;,(1) 初始化操作。 void InitQueue(SeqQueue *

37、Q) /* 将*Q初始化为一个空的循环队列 */ Q-front=Q-rear=0; ,(2) 入队操作。 int EnterQueue(SeqQueue *Q, QueueElementType x) /*将元素x入队*/ if(Q-rear+1)%MAXSIZE=Q-front) /*队列已经满了*/return(FALSE); Q-elementQ-rear=x; Q-rear=(Q-rear+1)%MAXSIZE; /* 重新设置队尾指针 */ return(TRUE); /*操作成功*/ ,(3) 出队操作。 int DeleteQueue(SeqQueue *Q, QueueEle

38、mentType *x) /*删除队列的队头元素, 用x返回其值*/ if(Q-front=Q-rear) /*队列为空*/ return(FALSE); *x=Q-elementQ-front; Q-front=(Q-front+1)%MAXSIZE; /*重新设置队头指针*/ return(TRUE); /*操作成功*/,3.2.3 队列的应用举例,1. 打印杨辉三角,图3.16 杨辉三角形,图3.17 杨辉三角形元素入队顺序,(1) 第7行的第一个元素1入队。 elementrear=1; rear=(rear +1 )% MAXSIZE; (2) 循环做以下操作, 产生第7行的中间5个

39、元素并入队。 elementrear=elementfront+element(front+1) %MAXSIZE; rear=(rear +1 )% MAXSIZE; front=(front+1)%MAXSIZE;,(3) 第6行的最后一个元素1出队。 front=(front+1)%MAXSIZE; (4) 第7行的最后一个元素1入队。 elementrear1; rear=(rear +1 )% MAXSIZE;,下面给出打印杨辉三角形的前n行元素的具体算法:,void YangHuiTriangle( ) SeqQueue Q; InitQueue( /* 打印第n-1行的元素*/,

40、GetHead(Q, /* 打印第n-1行的最后一个元素*/EnterQueue(&Q,1) /* 第n行的最后一个元素入队*/ ,2. 键盘输入循环缓冲区问题,问题描述:有两个进程同时存在于一个程序中。 其中第一个进程在屏幕上连续显示字符“A”,与此同时,程序不断检测键盘是否有输入,如果有的话,就读入用户键入的字符并保存到输入缓冲区中。在用户输入时,键入的字符并不立即回显在屏幕上。 当用户键入一个逗号(,)时,表示第一个进程结束,第二个进程从缓冲区中读取那些已键入的字符并显示在屏幕上。第二个进程结束后,程序又进入第一个进程, 重新显示字符“A”,同时用户又可以继续键入字符,直到用户输入一个分

41、号(;),才结束第一个进程, 同时也结束整个程序。,define MAXSIZE 16 define QueueElementType char define TRUE 1 define FALSE 0 include stdio.h include conio.h include dos.h main() /*模拟键盘输入循环缓冲区*/ char ch1,ch2; SeqQueue Q; int f; InitQueue() ,for(;) /*第一个进程*/ printf(A); if(kbhit() ch1=bdos(7,0,0); /* 通过DOS命令读入一个字符*/ f= EnterQueue( /* 循环队列满时, 强制中断第一个进程*/ ,if(ch1=;|ch1=,) break; /*第一个进程正常结束*/ while(!IsEmpty(Q) /*第二个进程*/ DeleteQueue( /*置空ch1, 程序继续*/ ,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 高等教育 > 大学课件

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报