3.10队列应用
队列的应用举例:
1.打印杨辉三角
【算法思想】
由上图可看出杨辉三角形的特点:即每一行的第一个元素和最后一个元素均为 1,其他位置上的数字是其上一行中与之相邻的两个整数之和。
所以第 i 行上的元素要由第 i-1 行中的元素来生成。可以利用循环队列实现打印杨辉三角形的过程:在循环队列中依次 存放第 i-1 行上的元素,然后逐个出队并打印,同时生成第 i 行元素并入队。
在整个过程中, 杨辉三角形中元素的入队顺序如下图所示。
下面以用第 6 行元素生成第 7 行元素为例说明具体过程。
- ⑴ 第 7 行的第一个元素 1 入队。 element[rear]=1; rear=(rear +1 )% MAXSIZE;
- ⑵ 循环做以下操作,产生第 7 行的中间 5 个元素并入队。 element[rear]=element[front]+element[(front+1) %MAXSIZE]; rear=(rear +1 )% MAXSIZE; front=(front+1)%MAXSIZE;
- ⑶ 第 6 行的最后一个元素 1 出队。 front=(front+1)%MAXSIZE;
- ⑷ 第 7 行的最后一个元素 1 入队。 element[rear]=1; rear=(rear +1 )% MAXSIZE;
下面给出打印杨辉三角形的前 N 行元素的具体算法。
void YangHuiTriangle( )
{
SeqQueue Q;
InitQueue (&Q);
EnterQueue (&Q,1); /* 第一行元素入队*/
for(n=2;n<=N;n++) /* 产生第 n 行元素并入队,同时打印第 n-1 行的元素*/
{
EnterQueue (&Q,1); /* 第 n 行的第一个元素入队*/
for(i=1;i<=n-2;i++) /* 利用队中第 n-1 行元素产生第 n 行的中间 n-2 个元素 并入队*/
{
DeleteQueue (&Q,&temp);
Printf(“%d”,temp); /* 打印第 n-1 行的元素*/
GetHead(Q,&x); temp=temp+x; /*利用队中第 n-1 行元素产生第 n 行元素*/
EnterQueue (&Q,temp);
}
DeleteQueue (&Q, &x);
printf(“%d”, x); /* 打印第 n-1 行的最后一个元素 */
EnterQueue (&Q, 1) /* 第 n 行的最后一个元素入队 */
}
while(!IsEmpty(Q)) /* 打印最后一行元素 */
{
DeleteQueue (&Q, &x);
print(“%d”, x);
}
}
上面的算法只是逐个打印出了杨辉三角形前 N 层中的数据元素,并没有按三角形的形式输 出,读者可以自己加入坐标数据,然后在屏幕上打印出杨辉三角形。
2.键盘输入循环缓冲区问题
在操作系统中,循环队列经常用于实时应用程序。
例如,当程序正在执行其他任务时,用户可以从键盘上不断键入所要输入的内容。系统在利用这种分时处理方法时,用户键入的内容不能在屏幕上立刻显示出来,直到当前正在工作的那个进程结束为止。
但在这个进程执行时, 系统是在不断地检查键盘状态,如果检测到用户键入了一个新的字符,就立刻把它存到系统缓冲区中,然后继续运行原来的进程。
当当前工作的进程结束后,系统就从缓冲区中取出键 入的字符,并按要求进行处理。
这里的键盘输入缓冲区采用了循环队列。
队列的特性保证了 输入字符先键入、先保存、先处理的要求,循环结构又有效地限制了缓冲区的大小,并避免 了假溢出问题。
【问题描述】
有两个进程同时存在于一个程序中。其中第一个进程在屏幕上连续显示字符“A”,与此同时,程序不断检测键盘是否有输入,如果有的话,就读入用户键入的字符并保存到输入缓冲区中。在用户输入时,键入的字符并不立即回显在屏幕上。当用户键入一个逗号(,)或分号(;)时,表示第一个进程结束,第二个进程从缓冲区中读取那些已键入的字符并显示在屏幕上。第二个进程结束后,程序又进入第一个进程,重新显示字符“A”,同时用户又可以继续键入字符,直到用户输入一个分号(;)键,才结束第一个进程,同时也 结束整个程序。
#include “stdio.h”
#include “conio.h”
#include “queue.h”
main()
{/*模拟键盘输入循环缓冲区*/
char ch1, ch2;
SeqQueue Q;
int f;
InitQueue (&Q); /* 队列初始化 */
for(;;)
{
for(;;) /*第一个进程*/
{
printf(“A”);
if(kbhit())
{
ch1= getch( ); /* 读取键入的字符,但屏幕上不显示 */
if(ch1==’;’||ch1==’,’)
break; /* 第一个进程正常中断 */
f= EnterQueue (&Q, ch1);
if(f==FALSE)
{
printf(“循环队列已满\n”);
break; /* 循环队列满时,强制中断第一个进程*/
}
}
}
while (!IsEmpty(Q)) /*第二个进程*/
{
DeleteQueue (&Q, &ch2);
putchar(ch2); /*显示输入缓冲区的内容*/
}
if(ch1==’.’)
break; /*整个程序结束*/
}
}