题目描述
队列的运算特性是先进先出。队列是一种重要的数据类型,队列在各种类型的系统中应
用广泛。讨论队列的结构特征与操作实现特点,有着重要的意义。实现了循环队列存储空间
的动态增长。但是存储空间在开辟并使用后若闲置, 并且用户不能确定在之后的操作中用
到这些闲置空间时,需要想出一种办法将这部分空间回收。设置循环队列闲置空间达到
QUEUE_FREESIZE 时,按 50%的比例回收大小为 UEUE_FREESIZE*50%的这部分空间。
下面给出了部分的初始定义供设计时参考。
# define QUEUE_INIT_SIZE 5 //队列存储空间的初始分配量
# define QUEUE_INCREMENT 5 //队列存储空间的分配增量
# define QUEUE_FREESIZE 10 //队列存储空间的回收预定值
# define PERCENT 0.5 //队列闲置空间的回收比例**
typedef struct //循环队列类型
{
ElementType *element; //初始化的动态分配存储空间
int front; //队头指针, 若队列非空,指向队列头元素
int rear; //队尾指针, 若队列非空,指向队尾元素的下一个位置
int QueueSize; //当前分配的存储空间(以 sizeof(ElementType)为单位)
}SeqQueue;
源代码
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string>
#include <windows.h>
# define QUEUE_INIT_SIZE 5 //队列存储空间的初始分配量
# define QUEUE_INCREMENT 5 //队列存储空间的分配增量
# define QUEUE_FREESIZE 10 //队列存储空间的回收预定值
# define PERCENT 0.5 //队列闲置空间的回收比例
#define ElementType int
using namespace std;
typedef struct //循环队列类型
{
ElementType* element = NULL; //一个的数组头指针
int front; //队头指针,若队列非空,指向队列头元素
int rear; //队尾指针,若队列非空,指向队尾元素的下一个位置
int QueueSize; //当前分配的存储空间(以sizeof(ElementType)为单位) ,队列中多余空出来的空间?
int QueueLength; //队列长度(有数据的)
}SeqQueue;
bool InitQueue(SeqQueue* Q) //构造一个空队列Q
{
free(Q->element);
Q->element = (ElementType*)malloc(QUEUE_INIT_SIZE * sizeof(ElementType));//相当于int element[5];
if (!Q->element)
return false; //内存开辟失败,报告错误并退出程序
Q->front = Q->rear = 0;
Q->QueueSize = QUEUE_INIT_SIZE; //给队列一个初始空间
Q->QueueLength = 0;
return true;
}
//int QueueLength(SeqQueue* Q) //求队列的长度
//{
// int n = ((abs((Q->rear) - (Q->front))) % Q->QueueSize) ;
int n = (Q->rear-Q->front+Q->QueueSize)%Q->QueueSize;
// return n;
//}
int ENQueue(SeqQueue* Q, ElementType e)//入队
{
ElementType* New_Base;// = (ElementType*)malloc(QUEUE_INIT_SIZE * sizeof(ElementType))
// if (((Q->rear + 1) % Q->QueueSize) == Q->front) //判断是否队满
if(Q->QueueSize <= Q->QueueLength )//判断是否队满
{
New_Base = (int*)malloc( (Q->QueueSize + QUEUE_INCREMENT) * sizeof(ElementType));
if (!New_Base)
return -1;
for(int i=0;i<Q->QueueSize;i++){ //把值复制过去
New_Base[i] = Q->element[i];
}
Q->element = New_Base;
Q->QueueSize += QUEUE_INCREMENT;
if (Q->rear < Q->front) // section 3 ,右边部分往右移,修改front的值
{
int i = Q->QueueSize -QUEUE_INCREMENT - 1; //
int j = Q->QueueSize - 1;
for (; i >= Q->front; i--, j--)
Q->element[j] = Q->element[i];
}
// cout<<"Q->QueueLength"<<Q->QueueLength<<" Q->QueueSize"<<Q->QueueSize<<endl;
if(Q->QueueLength == Q->QueueSize - QUEUE_INCREMENT) // 队列满了
{
Q->rear = Q->QueueLength;
}
}
// cout<<"###rear:"<<Q->rear<<endl;
Q->element[Q->rear] = e; //真正的入队
Q->QueueLength++; //队列长度加1
Q->rear = (Q->rear + 1) % Q->QueueSize; //rear向下移一位
// cout<<"front:"<<Q->front<<" rear:"<<Q->rear<<endl;
return 0;
}
//循环队列中元素的出队操作,出队操作按上面分析结果,实现算法如下:
bool DeleteQueue(SeqQueue* Q)//出队操作的实现算法
{
int i, j, cnt;
int hsgs = int(QUEUE_FREESIZE * PERCENT); //回收个数为限定值QUEUE_FREESIZE的50% , 5
ElementType* newbase;
if (Q->QueueLength<=0) //Q->rear == Q->front =-============================!!!!!!!!!!!!
return false; //队列为空则报告错误并退出程序
Q->front = (Q->front + 1) % Q->QueueSize;//队头出队
Q->QueueLength--;
if ( Q->QueueSize - Q->QueueLength >= QUEUE_FREESIZE ) //判断闲置空间是否达到定值 ,Q->QueueSize - LEN >= QUEUE_FREESIZE -1
{
if (Q->front > Q->rear) //判断队头指针与队尾指针的相对位置,情形3
{
for (i = Q->QueueSize - hsgs - 1, j = Q->QueueSize - 1; j >= Q->front; i--, j--)
Q->element[i] = Q->element[j]; //移动Q->front开始到Q->QueueSize结束的cnt个元素
cnt = Q->QueueSize - Q->front; // 情况三下,右边部分有多少个
Q->front = Q->QueueSize - hsgs - cnt; //修改队头指针
}
else{
if (Q->QueueSize -(Q->rear )< hsgs) //判断队尾指针后的闲置空间是否不够回收,情形2 ,Q->QueueSize - (Q->rear + 1) < hsgs
{
for (i = 0, j = Q->front; j < Q->rear; i++, j++)
Q->element[i] = Q->element[j]; //移动所有元素的位置
Q->front = 0; //令队头指针指向队列首位置
Q->rear = Q->front + Q->QueueLength; //队尾指针指向最后一个元素的后一个位置
}
}
newbase = (ElementType*)realloc(Q->element, (Q->QueueSize - hsgs) * sizeof(ElementType)); //回收空闲空间
if (!newbase)
return false; //内存分配失败,报告错误并退出程序
Q->element = newbase;
Q->QueueSize = Q->QueueSize - hsgs; //修改存储空间的大小
}
return true;
}
void meun(){
cout<<"==========================="<<endl
<<"| 1. 入队 |"<<endl
<<"| 2. 出队 |"<<endl
<<"| 3. 查看队列 |"<<endl
<<"| 4. 重置队列 |"<<endl
<<"| 0. 退出 |"<<endl
<<"==========================="<<endl;
}
int main()
{
int n ;
ElementType x;
SeqQueue Q;
InitQueue(&Q); // 初始化循环队列,并且分配空间
while(true){
int select;
system("Cls");
meun();
cout<<"请选择: ";
cin>>select;
switch(select){
case 1:
cout<<"你要入队几个数据: ";
cin>>n; // 11
cout<<"请输入这些数据: ";
for (int i = 0; i < n; i++)// 入队
{
cin >> x;
ENQueue(&Q, x);
}
cout<<"* 初始:"<<endl;
cout << "队列长度:" << Q.QueueLength << endl; //11-7
cout << "空闲空间长度:" << Q.QueueSize - Q.QueueLength << endl; //
system("pause");
break;
case 2:
cout<<"你要出队几个数据:";
cin>>n;
for(int i=0;i<n;i++){
DeleteQueue(&Q);
cout<<"======================"<<endl;
cout<<"* 出队"<<i+1<<"个后:"<<endl;
cout << "队列长度:" << Q.QueueLength << endl; //
cout << "空闲空间长度:" << Q.QueueSize - Q.QueueLength << endl; //
}
system("pause");
break;
case 3:
cout<<"//tips: 有效数据外显示@"<<endl;
cout<<"front:"<<Q.front<<" rear:"<<Q.rear<<endl;
cout<<"QueueLength:"<<Q.QueueLength<<" QueueSize:"<<Q.QueueSize<<endl;
if(Q.QueueLength<Q.QueueSize){ // 如果队列没满
if(Q.front<= Q.rear)
for(int i=0;i<Q.QueueSize;i++){
if(i>=Q.front && i<=Q.rear-1)
cout<<Q.element[i]<<" ";
else cout<<"@ ";
}
else
for(int i=0;i<Q.QueueSize;i++){
if(i >= Q.rear && i < Q.front )
cout<<"@ ";
else cout<<Q.element[i]<<" ";
}
}
else
for(int i=0;i<Q.QueueSize;i++){
cout<<Q.element[i]<<" ";
}
cout<<endl;
// for(int i=0;i<Q.QueueSize;i++)
// cout<<Q.element[i]<<" ";
system("pause");
break;
case 4:
InitQueue(&Q);
cout<<"重置完毕!"<<endl;
system("pause");
break;
case 0:
return 0;
default:
cout<<"error! 请重新选择!"<<endl;
system("pause");
break;
}
}
}
最后
在某些频繁入队又出队又入队出队等情况的多种组合下,功能3还是会有bug存在,以后有空再改吧。。。