datawhale算法与数据结构(上)day4-队列

datawhale算法与数据结构(上)day4-队列

理论部分

一、队列

  1. 定义
    和栈相反,队列是一种先进先出(FIFO)的线性表。只允许在表的一端进行插入,而在另一端删除元素。在队列中,允许插入的一端叫做队尾,允许删除的一段则称队头。

队列在程序设计中经常出现。一个最典型的例子就是操作系统中的作业排队。在允许多道程序运行的计算机系统中,同时有几个作业运行。如果运行的结果都需要通过通道输出,那就要按请求输出的先后次序排队。
在这里插入图片描述
2.用数组实现一个顺序队列

#说明sq.h

#ifndef _SQ_H_
#define _SQ_H_
 
typedef int dataType;
#define maxSize 100
 
class sq
{
public:
	sq();
	//~sq();
	void push(dataType var);
	void pop();
	dataType front();
	bool isEmpty();
	bool isFull();
 
private:
	dataType queue[maxSize];
	int head;
	int tail;
};
 
#endif

#顺序队列类的定义
#include <iostream>
#include "sq.h"
using namespace std;
 
sq::sq()
{
	head = -1;   
	tail = -1;
}
 
void sq::push(dataType var)
{
	queue[++tail] = var;
 
	if(tail == 0) 
	{
		head = 0;
	}
}
 
void sq::pop()
{
	++head;
}
 
dataType sq::front()
{
	return queue[head];
}
 
bool sq::isEmpty()
{
	bool flag = head > tail;     //当head和tail不为-1时
 
	if(head == -1 && tail == -1) //当head=tail=-1时
	{
		flag = true;
	}
 
	if(flag)
	{
		head = tail = -1;
	}
 
	return flag;
}
 
bool sq::isFull()
{
	return tail == maxSize-1;
}

#main.cpp

#include <iostream>
#include "sq.h"
using namespace std;
 
int main()
{
	sq exp;
	int i = 0;
 
	for(i=0;i<maxSize+10;++i)
	{
		if(!exp.isFull())
		{
			exp.push(i);
		}
	}
	
 
	for(i=0;i<maxSize+20;++i)
	{
		if(!exp.isEmpty())
		{
			cout<<exp.front()<<endl;
			exp.pop();
		}
	}
 
	if(exp.isEmpty())
	{
		cout<<"队列已空!"<<endl;
	}
 
	return 0;
}

  1. 数组实现一个循环队列
#include 
using namespace std;
template 
class queue
{
private:
	int front;//对尾的下标
	int rear;
	int Maxsize;
	T *q;
public:
	queue(int Msize) :Maxsize(Msize)//:作用是MAXSZE变量的初始化
	{
		q = new T[Maxsize];//q指向分配的数组首地址,也就是数组名
		front = rear = 0;
	}
	~queue(){ delete q; }
	int size(){ return (rear - front + Maxsize) % Maxsize; }
 
	bool enqueue(const T& v)
	{
		if (size() == Maxsize)
		{
			cout << "队列已满" << endl;
			return false;
		}
		else
		{
			q[rear] = v;//这里有一些别扭,指针竟然可以作为数组的下标
			rear = (rear + 1) % Maxsize;
			return true;
		}
	}
 
	int  dequeue(T v)
	{
		if (size() == 0)
		{
			cout << "队列空" << endl;
			return 0;
		}
		else
		{
			v=q[front];
			q[front] = NULL;
			front = (front + 1) % Maxsize;//因为是数组所以不需要释放,只需令其值为Null
			return v;
		}
	}
};
 
int main()
{ 
	char m;
	queue  q1(20);
	cout << "输入a入队,b出队,c退出!" << endl;
	cin >> m;
	while (m != 'c')
	{
		if (m == 'a')
		{
			int i,j;
			cout << "输入20以下的数字,即需要入队的个数:";
			cin >> i;
			for (j = 0; j < i; j++)
			{
				int k;
				cin >> k;
				q1.enqueue(k);
				cout << "这是当前队列中的元素个数:" << q1.size() << endl;
			}
			cout << "队满,请输入b进行出队操作或输入c退出!" << endl;
			cin >> m;//为了使操作连续
		}
		if (m == 'b')
		{
			while (q1.size() != 0)
			{
			    int n;
				cout << "请输入你要出队元素赋给哪个数字(注:队列中必须存在)" << endl;
				cin >> n;
				cout <<" 出队元素赋给输入的数字,即n=" << q1.dequeue(n) << endl;
				cout << "这是当前队列中的元素个数" << q1.size() << endl;
			}
			cout << "请先输入a:入队一些元素,或输入c退出操作!" << endl;
			cin >> m;//为了使操作连续
		}
	}
}
  1. 数组实现一个链式队列

#include 
using namespace std;
template 
class queue
{
private:
	int front;//对尾的下标
	int rear;
	int Maxsize;
	T *q;
public:
	queue(int Msize) :Maxsize(Msize)//:作用是MAXSZE变量的初始化
	{
		q = new T[Maxsize];//q指向分配的数组首地址,也就是数组名
		front = rear = 0;
	}
	~queue(){ delete q; }
	int size(){ return (rear - front + Maxsize) % Maxsize; }
 
	bool enqueue(const T& v)
	{
		if (size() == Maxsize)
		{
			cout << "队列已满" << endl;
			return false;
		}
		else
		{
			q[rear] = v;//这里有一些别扭,指针竟然可以作为数组的下标
			rear = (rear + 1) % Maxsize;
			return true;
		}
	}
 
	int  dequeue(T v)
	{
		if (size() == 0)
		{
			cout << "队列空" << endl;
			return 0;
		}
		else
		{
			v=q[front];
			q[front] = NULL;
			front = (front + 1) % Maxsize;//因为是数组所以不需要释放,只需令其值为Null
			return v;
		}
	}
};
 
int main()
{ 
	char m;
	queue  q1(20);
	cout << "输入a入队,b出队,c退出!" << endl;
	cin >> m;
	while (m != 'c')
	{
		if (m == 'a')
		{
			int i,j;
			cout << "输入20以下的数字,即需要入队的个数:";
			cin >> i;
			for (j = 0; j < i; j++)
			{
				int k;
				cin >> k;
				q1.enqueue(k);
				cout << "这是当前队列中的元素个数:" << q1.size() << endl;
			}
			cout << "队满,请输入b进行出队操作或输入c退出!" << endl;
			cin >> m;//为了使操作连续
		}
		if (m == 'b')
		{
			while (q1.size() != 0)
			{
			    int n;
				cout << "请输入你要出队元素赋给哪个数字(注:队列中必须存在)" << endl;
				cin >> n;
				cout <<" 出队元素赋给输入的数字,即n=" << q1.dequeue(n) << endl;
				cout << "这是当前队列中的元素个数" << q1.size() << endl;
			}
			cout << "请先输入a:入队一些元素,或输入c退出操作!" << endl;
			cin >> m;//为了使操作连续
		}
	}
}

练习题

模拟银行服务完成程序代码。

目前,在以银行营业大厅为代表的窗口行业中大量使用排队(叫号)系统,该系统完全模拟了人群排队全过程,通过取票进队、排队等待、叫号服务等功能,代替了人们站队的辛苦。

排队叫号软件的具体操作流程为:

  • 顾客取服务序号
    当顾客抵达服务大厅时,前往放置在入口处旁的取号机,并按一下其上的相应服务按钮,取号机会自动打印出一张服务单。单上显示服务号及该服务号前面正在等待服务的人数。

  • 服务员工呼叫顾客
    服务员工只需按一下其柜台上呼叫器的相应按钮,则顾客的服务号就会按顺序的显示在显示屏上,并发出“叮咚”和相关语音信息,提示顾客前往该窗口办事。当一位顾客办事完毕后,柜台服务员工只需按呼叫器相应键,即可自动呼叫下一位顾客。

编写程序模拟上面的工作过程,主要要求如下:

  • 程序运行后,当看到“请点击触摸屏获取号码:”的提示时,只要按回车键,即可显示“您的号码是:XXX,您前面有YYY位”的提示,其中XXX是所获得的服务号码,YYY是在XXX之前来到的正在等待服务的人数。
  • 用多线程技术模拟服务窗口(可模拟多个),具有服务员呼叫顾客的行为,假设每个顾客服务的时间是10000ms,时间到后,显示“请XXX号到ZZZ号窗口!”的提示。其中ZZZ是即将为客户服务的窗口号。
#include<iostream>
#include <stdlib.h>
#include <time.h>
#include<windows.h>
using namespace std;
int K,N;   //定义银行服务窗口个数和一天的客户人数 

//定义链表节点
template<class T>
struct chainNode
{
  //数据成员
  T element;
  chainNode<T> *next;
  //方法
  chainNode(){}
  chainNode(const T& element){
    this->element=element;
  }
  chainNode(const T& element,chainNode<T> *next){
    this->element=element;
    this->next=next;
  } 
};

//定义队列
template<class T>
class queue{
    public:
        queue();       //初始化队列 
        ~queue(){};    //析构函数 
        bool empty(){  //判断队列是否为空 
          return queueSize==0;
        }
        int size(){    //返回队列中元素的个数 
          return queueSize;
        }    
        T& front(){    //返回队列首元素
          return queueFront->element;
        }    
        T& back(){     //返回队列尾元素 
          return queueBack->element;
        }
        chainNode<T> * begin(){
          return queueFront;
        }
        void pop();    //删除首元素 
        void push(const T& theElement);
    private:
        int queueSize;        //队列长度 
        chainNode<T> *queueFront;  //指向队列第一个元素的指针
        chainNode<T> *queueBack;   //指向队列最后一个元素的指针
};
template<class T>
queue<T>::queue(){
    queueFront=queueBack=NULL;
    queueSize=0;
}

template<class T>
void queue<T>::pop(){
    if(queueFront==NULL) {
        cout<<"you queue is empty!";
        return;
    }
    chainNode<T> *nextNode=queueFront->next;
    delete queueFront;
    queueFront=nextNode;
    queueSize--;
}

template<class T>
void queue<T>::push(const T& theElement){
    //申请新元素节点
    chainNode<T> *newNode=new chainNode<T>(theElement,NULL);
    //把新节点插入队尾
    if(queueSize==0)  queueFront=newNode; //队空 
    else  queueBack->next=newNode;        //队非空 
    queueBack=newNode;
    queueSize++;
}

//定义时间 
struct thetime{
    int h;  //时 
    int m;  //分 
};
//定义每个客户的到达银行时间,等待时间,开始办理业务时间,业务处理时间,结束业务时间(离开银行时间)
struct customers{
    struct thetime arrive_time;     //到达银行时间 
    struct thetime wait_time;       //等待时间 
    struct thetime start_time;      //开始办理业务时间 
    int business_time;              //业务处理时间(假设业务处理时间为整数,且处理时间范围为10-40min) 
    struct thetime end_time;        //结束办理业务时间
    int in_bank_number;             //客户进入银行的序号     
}; 
//展示窗口服务情况
void show_queue(queue<customers> cus_queue[]){
    Sleep(1000); 
    for(int i = 0;i < K;i++) {
        cout<<"窗口"<<i+1<<": ";
        chainNode<customers> *m = cus_queue[i].begin();
        while(m != NULL) {
            cout<<"客户"<<m->element.in_bank_number<<" ";
            m = m -> next;
        }
        cout<<endl; 
    }
    cout<<endl;
} 

//用户到达银行时间表函数 
void customers_time(struct customers &c){
    //随机产生客户到达银行时间 
    c.arrive_time.h=9+rand()%8;
    c.arrive_time.m=rand()%60;
    //随机产生客户业务处理时间
    //c.business_time=10+rand()%31; 
}
//按用户的到达时间将用户的先后顺序进行排序(由于用户的到达时间是随机产生的) 
void customer_sort(customers customer[]){
    int max_time_index;   //记录客户到达的最晚时间对应的下标 
    customers max_time_cus,swap_cus;
    //采用选择排序进行排序 
    for(int i=N-1;i>0;i--)
    {
        max_time_cus=customer[i];
        max_time_index=i;
        //找出到达时间最晚的 
        for(int j=0;j<i;j++)
        {
          if((customer[j].arrive_time.h)*60+customer[j].arrive_time.m > (max_time_cus.arrive_time.h)*60+max_time_cus.arrive_time.m)
          {
            max_time_cus=customer[j];
            max_time_index=j;   
          }
        }
        if(i!=max_time_index){
          //swap部分
          swap_cus=customer[i];
          customer[i]=max_time_cus;
          customer[max_time_index]=swap_cus;            
        } 
    }

} 

//判断客户需要去哪个窗口排队,即算出等待时间最少的队列 
int judge_queue_in(queue<customers> cus_queue[],customers &customer,int each_queue_cus_number[]) {
    //将用户在每个队列需要等待的时间放在一个数组里
    int each_queue_wait_time[K];
    for(int i=0;i<K;i++) {
        //客户的等待时间取决于他队伍最后一个人的结束办理时间 
        int wait_h=cus_queue[i].back().end_time.h-customer.arrive_time.h;
        each_queue_wait_time[i]=wait_h*60+cus_queue[i].back().end_time.m-customer.arrive_time.m;
    }
    //找出需要时间最少的队列
    int min_time_queue_index=0;
    for(int j=1;j<K;j++) {
        if(each_queue_wait_time[j] < each_queue_wait_time[min_time_queue_index])
          min_time_queue_index=j;
    }
    //定义客户的各项数据
    customer.business_time=10+rand()%31;  
    customer.wait_time.h=each_queue_wait_time[min_time_queue_index]/60;
    customer.wait_time.m=each_queue_wait_time[min_time_queue_index]%60;
    customer.start_time.h=cus_queue[min_time_queue_index].back().end_time.h;
    customer.start_time.m=cus_queue[min_time_queue_index].back().end_time.m;
    customer.end_time.h=customer.start_time.h+(customer.start_time.m+customer.business_time)/60;
    customer.end_time.m=(customer.start_time.m+customer.business_time)%60;
    //将客户加入队列
    //对银行关门时间到了,还在办理的客户允许继续办理完业务再离开,还在排队的进马上离开
    if((customer.start_time.h)*60+customer.start_time.m < 17*60) {
         cus_queue[min_time_queue_index].push(customer);
         each_queue_cus_number[min_time_queue_index]++;
    }
    return min_time_queue_index;
} 

//判断下一个客户到来时哪个队列的队首客户是否已经办理完业务,并进行出队
void leave_queue(queue<customers> cus_queue[],customers customer){
    for(int i=0;i<K;i++) {
        while(!cus_queue[i].empty() && (cus_queue[i].front().start_time.h)*60+cus_queue[i].front().start_time.m+
        cus_queue[i].front().business_time <= (customer.arrive_time.h)*60+customer.arrive_time.m)  {
           cout<<"----------客户"<<cus_queue[i].front().in_bank_number<<"离开了窗口"<<i+1<<"----------"<<endl; 
           cus_queue[i].pop();  
        }       
    }
    //show_queue(cus_queue);    
}

//用户进入队列函数
void customers_in_queue(queue<customers> cus_queue[],customers customer[],int each_queue_cus_number[]) {
    //判断哪个窗口是否有空闲的
    int queue_number; 
    for(int i=0;i<N;i++) {
        bool queue_free=false;
        //每次进入队列判断各队首是否已经办理完业务
        leave_queue(cus_queue,customer[i]);
        for(int j=0;j<K;j++) {
          //窗口中有空闲的情况 
          if(cus_queue[j].empty())
          {
             //客户每进入一个队列都需要判断每个队首客户是否已经办理完业务
             customer[i].business_time=10+rand()%31;   
             customer[i].wait_time.h=0;
             customer[i].wait_time.m=0;
             customer[i].start_time.h=customer[i].arrive_time.h;
             customer[i].start_time.m=customer[i].arrive_time.m;
             customer[i].end_time.h=customer[i].start_time.h+(customer[i].start_time.m+customer[i].business_time)/60;
             customer[i].end_time.m=(customer[i].start_time.m+customer[i].business_time)%60;
             cus_queue[j].push(customer[i]);
             each_queue_cus_number[j]++;
             queue_free=true;
             cout<<"----------客户"<<customer[i].in_bank_number<<"到达了窗口"<<j+1<<"----------"<<endl;
             cout<<"客户"<<customer[i].in_bank_number<<"需等人数:0"<<endl; 
             break; 
          }
        }
        //窗口中没有空闲的情况
        if(queue_free==false){
            queue_number = judge_queue_in(cus_queue,customer[i],each_queue_cus_number);   //判断哪个队列的等待时间最少
            cout<<"----------客户"<<customer[i].in_bank_number<<"到达了窗口"<<queue_number<<"----------"<<endl;
            cout<<"客户"<<customer[i].in_bank_number<<"需等人数:"<<cus_queue[queue_number].size()-1<<endl; 
        }
        show_queue(cus_queue);                      
    }
    //展示最后客户的离开状态 
    leave_queue(cus_queue,customer[N]); 
    show_queue(cus_queue);
}

int main(){
    //srand(time(0));
    srand((unsigned int)time(NULL));  //使每次编译完后产生的随机数不同 
    welcom();   //欢迎界面 
    cout<<"请输入银行服务窗口的个数:";
    cin>>K;
    cout<<"请输入银行一天的客户人数:";
    cin>>N;
    customers customer[N];
    queue<customers> cus_queue[K];
    int each_queue_cus_number[N];
    for(int i=0;i<N;i++){
        customers_time(customer[i]);       //初始用户时间 
        each_queue_cus_number[i]=0;        //初始窗口服务客户个数 
        cout<<i+1<<" arrive_time: "<<customer[i].arrive_time.h<<": ";
        cout<<customer[i].arrive_time.m<<endl; 
    }
    customer_sort(customer);  //按客户进入银行的先后顺序进行排序 
    cout<<"---------------------------after sort---------------------------"<<endl;
    for(int i=0;i<N;i++){
        //Sleep(2000);
        customer[i].in_bank_number = i + 1;
        cout<<i+1<<" arrive_time: "<<customer[i].arrive_time.h<<": ";
        cout<<customer[i].arrive_time.m<<endl; 
    }
    cout<<"---------------------------begin serve---------------------------"<<endl;
    customers_in_queue(cus_queue,customer,each_queue_cus_number);  //客户进队列 
    cout<<"---------------------------end serve---------------------------"<<endl;
    cout<<"---------------------------after customer in queue---------------------------"<<endl;
    for(int i=0;i<N;i++){
        cout<<i+1<<" start_time: "<<customer[i].start_time.h<<":"<<customer[i].start_time.m<<"\t";
        cout<<i+1<<" end_time: "<<customer[i].end_time.h<<":"<<customer[i].end_time.m<<"\t";
        cout<<i+1<<" bussiness_time: "<<customer[i].business_time<<"min\t";
        cout<<i+1<<"  wait_time: "<<(customer[i].wait_time.h)*60+customer[i].wait_time.m<<" "<<endl;
    }
    int max_cus_wait_time=(customer[0].wait_time.h)*60+customer[0].wait_time.m;
    int sum_cus_wait_time=max_cus_wait_time;
    for(int i=1;i<N;i++){
        if((customer[i].wait_time.h)*60+customer[i].wait_time.m > max_cus_wait_time)
            max_cus_wait_time=(customer[i].wait_time.h)*60+customer[i].wait_time.m;
        sum_cus_wait_time+=(customer[i].wait_time.h)*60+customer[i].wait_time.m;
    }
    int actual_cus_numbers=0;
    for(int i=0;i<K;i++){
        cout<<"窗口"<<i+1<<"服务顾客个数: "<<each_queue_cus_number[i]<<endl;
        actual_cus_numbers+=each_queue_cus_number[i];
    }
    cout<<"max_cus_wait_time: "<<max_cus_wait_time<<"min"<<endl;
    cout<<"avg_cus_wait_time: "<<(double)sum_cus_wait_time/actual_cus_numbers<<"min"<<endl; 
    return 0;
}

【来源】
[1] 数据结构
[2] https://blog.csdn.net/Lulipeng_cpp/article/details/10754495
[3] https://blog.csdn.net/jx232515/article/details/51483957
[4] https://blog.csdn.net/jx232515/article/details/51483957
[5] https://blog.csdn.net/Hachi_Lin/article/details/79774526

发布了6 篇原创文章 · 获赞 0 · 访问量 76

猜你喜欢

转载自blog.csdn.net/m0_37836661/article/details/103963314