数据结构——队列

相关概念

1.定义:队列是限定仅能在表头进行删除,表尾进行插入的线性表。

2.特点:先进先出

3.队列类型的实现

链队列、循环队列

真上溢:队列真正满时入队

假上溢:rear已指向队尾,但队列前端仍有空位置

解决假上溢方法:循环队列,利用“模运算”表示循环的含义

入队:Q.rear = (Q.rear+1) % MAXQSIZE

出队:Q.front = (Q.front+1)% MAXQSIZE

5.循环队列队空,队满条件

队空: Q.front ==Q.rear

队满

1)设置标志位

2)设置计数器

3)少用一个单元

Q.front=(Q.rear +1)%MAXQSIZE

队列实现

1.循环队列实现

循环队列的存储结构: 存储空间的基地址(base)头指针(int型 front)尾指针(int型 ,rear)

算法

初始化

1.为队列分配长度为MAXQSIZE的数组空间,base指针指向数组空间的首地址

2.front和rear置为0,表示队空

求队列长度

对于循环队列,front和rear差值可能小于0,所以求队列长度时,需要将两者差值 + MAXQSIZE 再 % MAXQSIZE.

入队

1.判断队是否已满,若队满则返回error

2.将新元素插入队尾

3.队尾指针加1

出队

1.判断是否队空,队空则返回error

2.保存队头元素

3.队头指针加1

取队头元素

若队非空时,返回队头元素,队头指针保持不变

#include <iostream>
using namespace std;

#define qElemType int
#define MAXSIZE 5

//结构体描述循环队列 
typedef struct sqList{
	qElemType *base; //存储空间的基地址 
	int front;  //头指针 
	int rear;	//尾指针 
};

//初始化 
void initSqQueue( sqList &Q ){
	
	Q.base = new qElemType[MAXSIZE];
	Q.front = Q.rear = 0;
	
	
}

int isFull( sqList Q ){
	
	
	return Q.front == (Q.rear + 1) % MAXSIZE;//少用一个单元
	
}
//入队
void enQueue( sqList &Q, qElemType val ){
	
	if( isFull( Q ) ){
		cout << "队满了,无法入队!" << endl;
		return;
	}
	
	Q.base[ Q.rear ] = val;
	Q.rear = (Q.rear + 1) % MAXSIZE;
	
}

void queueTraverse( sqList Q ){
	
	for( int i = Q.front; i  % MAXSIZE != Q.rear ; i = (i + 1) % MAXSIZE )
		cout << Q.base[i] << endl;
		
	
}
//出队
void deQueue( sqList &Q, qElemType &val ){
	
	val = Q.base[ Q.front ];
	Q.front= (Q.front+ 1) % MAXSIZE;
	
}
//取队头元素
qElemType getHead(sqQueue Q){
	if( Q.front != Q.rear){
		return Q.base[Q.front];
	}
}

2.链队实现

链队为什么需要队头指针和队尾指针:因为队列需要从队头和队尾进行操作,因此需要头结点队头队尾指针。跟链栈不同,栈只需在栈顶操作

链队的存储结构: 结点结构数据域next域

队列结构队头指针队尾指针

算法

初始化

1.生成头结点,队头队尾指针指向头结点

2.头结点指针域置空

入队

1.为入队元素创建新的结点,指针p指向该结点

2.将新结点的数据域赋值为e

3.将新结点插入到队列中

4.将队尾指针改为p

出队

1.判断是否队空,队空则返回error

2.临时保存队头指针

3.修改队头指针指针域使其指向下一个结点

4.判断出队元素是否为最后一个元素,若是,将队尾指针重新赋值,指向头结点

5.释放临时保存的队头指针

取队头元素

若队列非空,返回队头元素的值,队头指针保持不变

实现代码

#include <iostream>
using namespace std;

#define qElemType int

//结构体:描述结点 
typedef struct queueNode{
	qElemType data;
	queueNode *next;
	
} *queueNodePtr ;

//结构体:描述链队 
typedef struct linkQueue{
	
	queueNodePtr front;
	queueNodePtr rear;
	
};

//初始化 
void initLinkQueue( linkQueue &Q ){
	
	queueNodePtr newNode = new queueNode;//生成头结点 
	Q.front = Q.rear = newNode;
	newNode->next = NULL;
	
}

//入队 
void enQueue( linkQueue &Q, qElemType val ){
	
	queueNodePtr newNode = new queueNode;
	newNode->data = val;
	newNode->next = NULL;
	Q.rear->next = newNode;//将新结点插入队尾 
	Q.rear = newNode;     //修改队尾指针 
}
 
void queueTraverse( linkQueue Q ){
	
	Q.front = Q.front->next;
	while( Q.front ){
		
		cout << Q.front->data << endl;
		
		Q.front = Q.front->next;
		
	}
	
}

int isEmptyLinkQueue( linkQueue Q ){
	
	
	return Q.front == Q.rear;
	
}

//出队
void deQueue( linkQueue &Q, qElemType &val ){
 	
	if( isEmptyLinkQueue(Q) ){
		
		cout << "当前队列为空,无法出队" << endl;
		return;
		
	}
	
	queueNodePtr p = Q.front->next;//指向队头元素
	e = p->data;
	Q.front->next = p->next;

	if( !Q.front->next )  //最后一个元素被删,队尾指针指向头结点 
		Q.rear = Q.front;
	delete p;   //释放对头元素的空间 	
}

//取队头元素
qElemType getHead(linkQueue Q){
	if(Q.front != Q.rear){
		return Q.front->next->data;
	}

}

应用案例:模拟银行排队

1.顾客进入银行的间隔时间:介于1-5的随机时间间隔

2.顾客排队接受银行服务的时间:1-30的随机时间间隔

3.每个银行窗口对应一个队列

4.队伍选取规则:顾客进入银行后,自动排到人数最少的队伍里

​ 0:表示客户到达类型

变量定义:

1.事件链表: 有序的事件列表,保存到达或离开的事件

2.银行窗口队列:队列的结点结构包括:客户到达时间、接受服务时间

事件链表orderList

#include <iostream>
using namespace std;

typedef struct orderListNode{
	
	int occurTime; //事件发生时间:即客户到达或者离开时间 
	int type; //事件的类型 
	orderListNode *next;//指针域 
	
} *orderList ;

void initOrderList( orderList &L ){
	
	L = new orderListNode;//定义头结点 
	L->next = NULL;
	
}

int isEmptyOrderList(orderList L){
	
	return L->next == NULL;
	
}

//出队、输出事件队列的信息。没有删除 
void delFirstOrderList( orderList L, int &occurTime,	int &type ){
	
	if( isEmptyOrderList(L) ){
		cout << "当前有序表为空!" << endl;
		return;
	}
	occurTime = L->next->occurTime;
	type = L->next->type;
	L->next = L->next->next;
	
}

//入队,插入顾客到达或者离开的信息 
void insertOrderList( orderList L, 	int occurTime,	int type ){
	
	orderList newNode = new orderListNode;
	newNode->occurTime = occurTime;
	newNode->type = type;
	
	orderList ptr, prePtr = L;
	ptr = L->next;
	//有序插入事件队列的元素 
	while( ptr && ptr->occurTime < newNode->occurTime ){
		
		ptr = ptr->next;
		prePtr = prePtr->next;
		
	}
	
	newNode->next = prePtr->next;
	prePtr->next = newNode;
	
}

void orderListTraverse( orderList L  ){
	
	L = L->next;
	while( L ){
		
		cout << "occurTime is : " << L->occurTime << "  "
		     << "type is : " << L->type << endl;
		L = L->next;
		
	}
	
}

银行窗口队列 linkQueue

#include "orderList(1).cpp"

//结构体描述银行窗口结点结构 
typedef struct queueNode{
	int arrivalTime; //顾客到达银行的时间 
	int duringTime;  //顾客接受窗口服务花费的时间 
	queueNode *next;
	
	
} *queueNodePtr ;

//结构体描述银行窗口队列 
typedef struct linkQueue{
	
	queueNodePtr front;
	queueNodePtr rear;
	int length;
	
};


void initLinkQueue( linkQueue &Q ){
	
	queueNodePtr newNode = new queueNode;//生成头结点、队头队尾元素均指向头结点 
	Q.front = Q.rear = newNode;
	newNode->next = NULL;
	Q.length = 0;
	
}

void enQueue( linkQueue &Q, int arrivalTime, int duringTIme ){
	
	queueNodePtr newNode = new queueNode;
	newNode->arrivalTime = arrivalTime;
	newNode->duringTime = duringTIme;
	newNode->next = NULL;//将新结点插入 
	Q.rear->next = newNode;
	Q.rear = newNode;//修改队尾指针 
	Q.length++;
}

void queueTraverse( linkQueue Q ){
	
	Q.front = Q.front->next;
	while( Q.front ){
		
		cout << "arrivalTime is : " << Q.front->arrivalTime 
		<< "   " << "duringTime is : " << Q.front->duringTime << endl;
		
		Q.front = Q.front->next;
		
	}
	
	cout << "队列的长度是: " << Q.length << endl; 
	
	
}

int isEmptyLinkQueue( linkQueue Q ){
	
	
	return Q.front == Q.rear;
	
}


int getQueueFrontDuringTime(linkQueue Q){
	
	return Q.front->next->duringTime;
	
}

void deQueue( linkQueue &Q, int &arrivalTime, int &duringTime ){
	
	if( isEmptyLinkQueue(Q) ){
		
		cout << "当前队列为空,无法出队" << endl;
		return;  
		
	}
	
	arrivalTime = Q.front->next->arrivalTime;
	duringTime = Q.front->next->duringTime;

	queueNodePtr temp = Q.front->next;
	Q.front->next = Q.front->next->next;//删除元素 
	
	if( !Q.front->next )//最后元素被删除 
		Q.rear = Q.front;
	delete temp;
	Q.length--;
	
	
}

主要部分

#include "linkQueue.cpp"
#include <stdlib.h>
#include <time.h>


#define WINDOWS_NUM 5 //工作窗口 
#define BANK_OPEN 0   //开门时间 
#define BANK_CLOSE 20  //关门时间 
#define ARRIVAL_INTER_TIME 5 //客户达到时间范围 
#define DURING_TIME 30  //客户服务时间范围 


orderList evList;  //事件链表 
linkQueue queueWindow[WINDOWS_NUM + 1]; //银行窗口,从1开始,5个窗口 
int humanNum; //客户数量 
double spentTime; //花费总时间 
int occurTime, type; //事件时间和类型 

void initBank(){
	 
//	ev表示有序的事件列表,用来保存发生的到达或离开的事件 
	initOrderList( evList );
	for( int i = 1; i <= WINDOWS_NUM; i++ ) //银行窗口初始化 
		initLinkQueue(queueWindow[i]);
	humanNum = spentTime = 0;
	srand(time(0));//种下种子 
	
}

int generateRand( int interTime ){
	
	return rand() % interTime + 1;
	
}


int findMinLengthQueue( linkQueue queueWindow[] ){
	
	int minIndex = 1, minLength = queueWindow[1].length;
	for( int i = 2; i <= WINDOWS_NUM; i++ ){
		
		if( queueWindow[i].length < minLength ){
			
			minLength = queueWindow[i].length;
			minIndex = i;
			
		}
		
  	}
	
	return minIndex;
	
}

void customerArrive(){
	
	humanNum++;
	
//	产生下一个顾客到达的时间间隔 
	
	int newCustomerInterTime = generateRand( ARRIVAL_INTER_TIME );
//	产生一个新顾客到达的事件,并插入到事件列表里 
	insertOrderList( evList, occurTime + newCustomerInterTime,	0 );
	
	int minLengthQueue = findMinLengthQueue( queueWindow );
	
	int newCustomerServiceTime = generateRand( DURING_TIME );
     	enQueue( queueWindow[minLengthQueue], occurTime, newCustomerServiceTime );
	
//	如果顾客在排队之前队列为空,则可以马上计算出顾客出队的时间 
	if( 1 == queueWindow[minLengthQueue].length ){
		
		insertOrderList( evList, occurTime + newCustomerServiceTime, minLengthQueue ); 
		
	} 
	
	 
	
}


void customerLeave(){
	
	int customerLeaveIndex = type;
	int arrivalTime, duringTime;
	deQueue( queueWindow[customerLeaveIndex], arrivalTime, duringTime );
	
	spentTime += occurTime - arrivalTime;
	cout << "该顾客所花费的时间是: " << occurTime - arrivalTime << endl << endl << endl; 
	//如果顾客排队之前队列不为空,需要计算离开时间 
	if( !isEmptyLinkQueue(queueWindow[customerLeaveIndex]) )
		insertOrderList(evList, occurTime + getQueueFrontDuringTime(queueWindow[customerLeaveIndex]), customerLeaveIndex);
	//排队情况下的离开时间计算 
	
}

void bankOpen(){
	
	insertOrderList( evList, BANK_OPEN, 0 );
	
	
	while( !isEmptyOrderList(evList) ){
		
			
		delFirstOrderList(evList, occurTime, type);
		
		if( 0 == type ){
			
			/* TODO (#1#): 这是一个到达事件
 */
			if( occurTime <= BANK_CLOSE ){
				cout << "===============有一名新的顾客到达!===============" << endl;
				cout << "他的到达时间是: " << occurTime << endl << endl << endl; 
				customerArrive();
			}
				
			
			
		}
		else{
			
			cout << "当前有一个顾客从队伍 " << type << "离开" << endl;
			 
			/* TODO (#1#): 这是一个顾客离开的事件 */
			customerLeave();
			
		}
		
	}
	
	
	
}


int main(){
	
	initBank();
	
	bankOpen();
	
	cout << "总共有" << humanNum << "位顾客" << endl;
	cout << "总共花费了" << spentTime << "的时间" << endl;
	cout << "平均花费的时间是:" << spentTime / humanNum << endl; 
	
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值