赞
踩
实验六 队列
一、实验目的与要求
1)熟悉C/C++语言(或其他编程语言)的集成开发环境;
2)通过本实验加深对队列的理解,熟悉基本操作;
3) 结合具体的问题分析算法时间复杂度。
二、实验内容
设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。
你的实现应该支持如下操作:
MyCircularQueue(k): 构造器,设置队列长度为 k 。
Front: 从队首获取元素。如果队列为空,返回 -1 。
Rear: 获取队尾元素。如果队列为空,返回 -1 。
enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
isEmpty(): 检查循环队列是否为空。
isFull(): 检查循环队列是否已满。
三、实验结果
1)请将调试通过的源代码粘贴在下面。(代码注意书写规范、主要模块要有功能注释)
源代码:
- #include <iostream>
- using namespace std;
-
- template <typename T>
- class MyCircularQueue{
- T * data;//当前位置的数据
- int front,rear,size;//头指针、尾指针、队列长度
- public:
- //MyCircularQueue(k): 构造器,设置队列长度为 k 。
- MyCircularQueue(int k=0){
- data=new T[k+1];//k+1 -> 区分isEmpty和isFull的判断条件
- front=rear=0;
- size=k+1;
- }
- //Front: 从队首获取元素。如果队列为空,返回 -1 。
- T Front(){
- if(isEmpty()){
- return -1;
- }
- else{
- return data[front];
- }
- }
- //Rear: 获取队尾元素。如果队列为空,返回 -1 。
- T Rear(){
- if(isEmpty()){
- return -1;
- }
- else{
- return data[rear-1];
- }
- }
- //enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
- bool enQueue(T value){
- if(isFull()){
- return 0;
- }
- else{
- data[rear]=value;
- rear=(rear+1)%size;
- return 1;
- }
- }
- //deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
- bool deQueue(){
- if(isEmpty()){
- return 0;
- }
- else{
- front=(front+1)%size;
- return 1;
- }
- }
- //isEmpty(): 检查循环队列是否为空。
- bool isEmpty(){
- if(rear==front){
- return 1;
- }
- else{
- return 0;
- }
- }
- //isFull(): 检查循环队列是否已满。
- bool isFull(){
- if((rear+1)%size==front){
- return 1;
- }
- else{
- return 0;
- }
- }
- };
-
- int main(){
- //初始化循环链表
- int len;
- cout<<"Please input the length of your queue"<<endl;
- cin>>len;
- MyCircularQueue <int> queue(len);
-
- //查看空表
- if(queue.isEmpty() ==1){
- cout<<"The current queue is empty"<<endl;
- }
- else{
- cout<<"The current queue is not empty"<<endl;
- }
- cout<<"The front now is "<<queue.Front() <<endl;
- cout<<"The rear now is "<<queue.Rear() <<endl;
- cout<<endl;
-
- //输入元素
- int times;
- cout<<"Please select the times you want to input"<<endl;
- cin>>times;
- int i=0;
- for(;i<times;i++){
- int value;
- cout<<"Please input your value"<<endl;
- cin>>value;
- int t=queue.enQueue(value);
- if(t==1){
- cout<<"Valid input"<<endl;
- }
- else{
- cout<<"Invalid input"<<endl;
- break;
- }
- }
- cout<<endl;
-
- //判断输入后的情况
- if(queue.isEmpty() ==1){
- cout<<"The current queue is empty"<<endl;
- }
- else{
- cout<<"The current queue is not empty"<<endl;
- }
- cout<<"The front now is "<<queue.Front() <<endl;
- cout<<"The rear now is "<<queue.Rear() <<endl;
- cout<<endl;
-
- //删除元素
- int dels;
- cout<<"Please select the times you want to delete"<<endl;
- cin>>dels;
- int ii=0;
- for(;ii<dels;ii++){
- int tt=queue.deQueue();
- if(tt==1){
- cout<<"Valid delete"<<endl;
- }
- else{
- cout<<"Invalid delete"<<endl;
- break;
- }
- }
- cout<<endl;
-
- //判断删除后的情况
- if(queue.isEmpty() ==1){
- cout<<"The current queue is empty"<<endl;
- }
- else{
- cout<<"The current queue is not empty"<<endl;
- }
- cout<<"The front now is "<<queue.Front() <<endl;
- cout<<"The rear now is "<<queue.Rear() <<endl;
- cout<<endl;
-
- return 0;
- }
结果展示:
2)请分析你程序中每个功能模块的算法时间复杂度。
构造循环队列,只需要设置队列长度为k+1并设置相应数组,同时初始头指针和尾指针为0即可。所以,时间复杂度为O(1)。
判断循环队列是否为空队列,只需要判断头指针是否与尾指针重合即可,即return(rear==front)。所以,时间复杂度为O(1)。
判断循环队列是否为空队列,只需要判断尾指针加一取余后是否与头指针重合即可,即return((rear+1)%size==front)。所以,时间复杂度为O(1)。
获取队首元素,只需要先判断循环队列是否为空队列,如果队列非空则直接返回头指针所对应的元素。所以,时间复杂度为O(1)。
获取队尾元素,只需要先判断循环队列是否为空队列,如果队列非空则直接返回尾指针所对应的元素。所以,时间复杂度为O(1)。
向循环队列插入一个元素,只需要先判断循环队列是否为满队列,如果队列非满则直接插入输入元素并重置尾指针。所以,时间复杂度为O(1)。
从循环队列中删除一个元素,只需要先判断循环队列是否为空队列,如果队列非空则直接改变头指针的位置,即可删除队首元素。所以,时间复杂度为O(1)。
其他:
- #include<stdlib.h>
- #include<iostream>
- using namespace std;
- #define SIZE 6
- #define Type char
- typedef struct{
- Type *elem;
- int front,rear,length;//注意,队列的所谓的指针不是指针,是int
- }Queue;
- bool isEmpty(Queue &Q)//: 检查循环队列是否为空。
- {
- if(Q.rear==Q.front)
- {
- return 1;
- }
- else
- {
- return 0;
- }
- }
- bool isFull(Queue &Q)//: 检查循环队列是否已满。
- {
- if((Q.rear+1)%Q.length==Q.front)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- void MyCircularQueue(Queue &Q,int k)//: 构造器,设置队列长度为 k 。
- {
- Q.length=k;
- Q.elem=new Type[Q.length];
- Q.front=Q.rear=0;
- cout<<"长度为k的队列构造完毕"<<endl;
- }
- int Front(Queue &Q,Type &e)//: 从队首获取元素。如果队列为空,返回 -1 。
- {
- if(isEmpty(Q))
- {
- cout<<"空队列"<<endl;
- return -1;
- }
- else
- {
- e=Q.elem[Q.front];
- cout<<"非空"<<endl;
- cout<<"队首元素"<<e<<"获取成功"<<endl;
- return 1;
- }
- }
- int Rear(Queue &Q,Type &e)//: 获取队尾元素。如果队列为空,返回 -1 。
- {
- if(isEmpty(Q))
- {
- cout<<"空队列"<<endl;
- return -1;
- }
- else
- {
- cout<<"非空"<<endl;
- if(Q.rear==0)
- {
- e=Q.elem[5];
- cout<<"队尾元素"<<e<<"获取成功"<<endl;
- return 1;
- }
- else
- {
- e=Q.elem[Q.rear-1];
- cout<<"队尾元素"<<e<<"获取成功"<<endl;
- return 1;
- }
- }
- }
- bool enQueue(Queue &Q,Type value)//: 向循环队列插入一个元素。如果成功插入则返回真。
- {
- if(!isFull(Q))
- {
- cout<<"非满"<<endl;
- Q.elem[Q.rear]=value;//因为初始front和rear都是0开头,所以与下标一致
- Q.rear=(1+Q.rear)%Q.length;
- cout<<value<<"已经插入"<<endl;
- return true;
- }
- else
- {
- cout<<"队列已满!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"<<value<<"无法入队"<<endl;
- return false;
- }
- }
- int deQueue(Queue &Q,Type &e)//: 从循环队列中删除一个元素。如果成功删除则返回真。
- {
- if(isEmpty(Q))
- {
- cout<<"已空"<<endl;
- return -1;
- }
- else
- {
- cout<<"非空"<<endl;
- e=Q.elem[Q.front];
- Q.front=(Q.front+1)%Q.length;
- cout<<"删除了"<<e<<endl;
- return 1;
- }
- }
- int getlength(Queue &Q)
- {
- int len;
- len=(Q.rear-Q.front+Q.length)%Q.length;
- return len;
- }
- int main()
- {
- Queue a;
- Type temp;
- Type e[11]={'a','b','c','d','e','f','g','h','i','j','k'};
- int length=SIZE;
- MyCircularQueue(a,length);//初始化
- enQueue(a,e[0]);//入队,到第一次满
- enQueue(a,e[1]);
- enQueue(a,e[2]);
- enQueue(a,e[3]);
- enQueue(a,e[4]);
- if(isFull(a))//判断是否已满
- {
- cout<<"队列已满!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"<<endl;
- }
- deQueue(a,temp);//删除队首
- Front(a,temp);//输出队首队尾元素
- Rear(a,temp);
- enQueue(a,e[5]);//插入两次,看看当队列已满,溢出时的效果 证明了程序在溢出时的插入无效
- enQueue(a,e[6]);//队列以满,试图插入的这个是g,查看满后队列是否可以阻止进入
- cout<<"该队列长度为"<<getlength(a)<<endl;
- Front(a,temp);//再次确定 1.队列确实是循环使用的,即0号位被再次利用 2.溢出的那一次插入无效
- Rear(a,temp);
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。