数组模拟单一队列(非循环)

本文介绍了一个简单的使用数组来模拟队列的数据结构实现方法。通过具体的Java代码示例,展示了队列的基本操作,包括数据的添加、取出及查看等功能。虽然这种方法存在一定的局限性,如空间浪费,但对于理解队列原理非常有帮助。

数组模拟单一队列(非循环)

代码如下:

import java.util.Scanner;

/*
    数组实现单一队列
 */
public class SimpleArrayQueuen {
    public static void main(String[] args){
        ArrQueue arrQueue = new ArrQueue(3);
        char c;
        boolean b = true;
        while (b){
            System.out.println("请输入字母操作");
            System.out.println("a(add),插入数据");
            System.out.println("s(show),查看数据");
            System.out.println("h(addHead),查看头部数据");
            System.out.println("g(get),取出数据");
            System.out.println("e(exit),退出");
            Scanner in = new Scanner(System.in);
            c = in.next().charAt(0);
            switch (c){
                case 'a':{
                    int n;
                    try{
                        System.out.println("请输入添加的数据:");
                        n = in.nextInt();
                        arrQueue.addQueuen(n);
                        System.out.println("添加成功!");

                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    break;
                }
                case 'h':{
                    try{
                        System.out.println("头部第一个数据为:"+arrQueue.showHead());
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                }
                case 's':{
                    try{
                        System.out.println("所有数据为:");
                        arrQueue.showAll();
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                }
                case 'g':{
                    try {
                        System.out.println("取出的数据为:"+arrQueue.getQueuen());
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                }
                case 'e':{
                    System.out.println("即将退出!!!");
                    b = false;
                }
            }
        }
    }
}
class ArrQueue{
    private int rear;//队列头
    private int front;//队列尾
    private int maxSize;//最大数据量
    private int[] arr;//存取数据的数组
    public ArrQueue(int n){
        maxSize = n;
        arr = new int[maxSize];//初始化数组大小
        rear = -1;
        front = -1;
    }
    //判断队列是否为空
    public boolean isEmpty(){
        return rear == front;
    }
    //判断队列是否满
    public boolean isFull(){
        return rear == maxSize-1;
    }
    //填入数据
    public void addQueuen(int n){
        if(isFull()){
            System.out.println("队列已满,无法插入新数据!");
            return;
        }
        rear++;
        arr[rear] = n;
    }
    //取数据
    public int getQueuen(){
        if(isEmpty()){
            throw new RuntimeException("队列为空,无数据!");
        }
        front++;
        return arr[front];
    }
    //展示所有数组
    public void showAll(){
        if(isEmpty()){
            throw new RuntimeException("队列为空,无数据!");
        }
        for(int i=0;i<arr.length;i++){
            System.out.printf("arr[%d]=%d\ns" +
                    "",i,arr[i]);

        }
    }
    //展示头数据
    public int showHead(){
        if(isEmpty()){
            throw new RuntimeException("队列为空,无数据!");
        }
        return arr[front+1];
    }
}

使用了数组实现队列的数据的添加/取出/查看三个基本功能,队列入门级别的,简单易懂。缺点是数组空间的浪费,不能重复使用数组空间,后续我会写一个数组模拟循环队列。

最新更新的另一篇:

使用数组实现循环队列。

https://blog.youkuaiyun.com/qq_43648564/article/details/108979496

<think>我们正在讨论银行排队模拟中的单队列算法实现方案。根据引用内容,单队列模拟通常使用队列数据结构来实现基本操作,如创建空队列、检查空/满状态、入队(队尾添加)、出队(队首删除)、获取队列长度等。引用[1]提到队列类的基本设计,引用[2]和[3]则分别提供了多队列找最短队列和离散事件模拟的思路。但用户现在要求单队列,所以主要关注一个队列模拟。单队列模拟算法框架可以有两种:1.时间步进模拟:将时间划分为小的时间单位(如分钟),在每个时间步中检查事件(顾客到达、服务完成)。2.离散事件模拟:按事件发生的顺序处理,事件包括顾客到达和顾客离开(服务完成)。事件按发生时间排序,使用优先队列管理事件。由于引用[3]提到了离散事件模拟,而且这是一种更高效的方式,我们采用离散事件模拟来设计单队列算法。单队列离散事件模拟主要组成部分:-事件:包括到达事件(顾客到达)和离开事件(顾客完成服务离开)。每个事件包含发生时间、事件类型(到达/离开)以及可能的顾客信息。-事件队列:按发生时间排序的事件优先队列(最小堆)。-一个队列(即单队列)用于表示排队中的顾客。-服务窗口状态(空闲或繁忙)。注意,单队列单窗口情况下,每次只能服务一个顾客;单队列多窗口时,可以同时服务多个顾客。由于问题是单队列,但未说明窗口数,这里先考虑单窗口(最典型)。步骤:1.初始化:-创建事件队列(优先队列),初始化当前时间(例如0)。-创建用于排队的队列(我们称为等待队列,FIFO)。-设置服务窗口状态为空闲。-生成第一个顾客的到达事件,加入事件队列。2.循环处理事件队列,直到事件队列为空或者模拟结束条件(如达到最模拟时间):-从事件队列中取出发生时间最早的事件。-如果事件是到达事件:设置当前时间为事件发生时间。然后,如果服务窗口空闲,则当前顾客立即开始接受服务,生成该顾客的离开事件(离开时间=当前时间+服务时长)并加入事件队列;同时将服务窗口状态置为忙。如果服务窗口忙,则将顾客加入等待队列(入队操作)。生成下一个顾客的到达事件(到达时间=当前时间+到达间隔)加入事件队列(除已经到达顾客数达到预设值)。-如果事件是离开事件:设置当前时间为事件发生时间。服务窗口置为空闲。如果等待队列不为空,则从等待队列中出队一个顾客,该顾客立即开始服务,生成其离开事件;服务窗口再次置为忙。3.需要记录的信息:每个顾客的等待时间、总顾客数、平均等待时间等性能指标。根据引用[3]的提示,在离开事件中,删除队头后(即服务完成),如果等待队列还有顾客,则要立即生成下一个顾客的离开事件,其离开时间等于当前时间(即刚完成的离开事件发生时间)加上新顾客的服务时间。这一点常重要。代码实现框架(伪代码):初始化事件队列eventQueue(优先队列,按发生时间排序)初始化等待队列waitQueue(普通FIFO队列)intcurrentTime=0;inttotalCustomer=0;//总顾客数inttotalWaitTime=0;//总等待时间窗口状态busy=false;//生成第一个到达事件eventQueue.push(Event{0,ARRIVAL,0});//假设0时刻第一个顾客到达,顾客编号0while(!eventQueue.empty()){Eventev=eventQueue.pop();currentTime=ev.occurTime;//推进当前时间if(ev.type==ARRIVAL){totalCustomer++;//生成下一个到达事件?(如果还有顾客需要到达)例如:nextArrivalTime=currentTime+到达间隔//这里假设到达间隔是随机的,比如指数分布,但也可以是指定分布。//注意:不能无限生成,可以设置最顾客数或者最时间if(!busy){//窗口空闲,立即服务busy=true;//随机生成该顾客的服务时长,然后生成离开事件intserviceTime=...;//随机服务时间eventQueue.push(Event{currentTime+serviceTime,DEPARTURE,ev.customerId});}else{//窗口忙,加入等待队列waitQueue.push(ev.customerId);//注意:这里也可以存储更多顾客信息}//生成下一个顾客的到达事件(假设还有下一个)intnextArrival=...;//下一个到达时间eventQueue.push(Event{nextArrival,ARRIVAL,totalCustomer});//注意顾客编号}elseif(ev.type==DEPARTURE){//离开事件:服务完成if(!waitQueue.empty()){//有顾客在等待,从队头取出一个顾客intnextCustomer=waitQueue.pop();//计算该顾客等待时间:当前时间-该顾客到达的时间?这里注意:我们在到达时加入队列,但队列中并没有存储到达时间//因此,需要改进:在顾客到达时,记录其到达时间,这样在开始服务时就能计算等待时间//所以,我们需要记录每个顾客的到达时间。可以设计一个顾客结构体,然后在事件中存储顾客信息(包含到达时间)或者单独存储。//假设我们有一个全局数组记录每个顾客的到达时间:arrivalTime[nextCustomer]=...?//在到达事件发生时,记录该顾客的到达时间。然后这里:intwaitTime=currentTime-arrivalTime[nextCustomer];totalWaitTime+=waitTime;//为该顾客生成离开事件intserviceTime=...;//该顾客的服务时间eventQueue.push(Event{currentTime+serviceTime,DEPARTURE,nextCustomer});}else{busy=false;//没有顾客在等待,窗口空闲}}}//计算平均等待时间:totalWaitTime/totalCustomer注意:上述代码中,关于顾客到达时间的记录需要单独管理。我们可以在生成到达事件时就创建顾客信息(包含到达时间),并保存到一个数组或映射中。在离开事件处理中,根据顾客编号来获取到达时间。改进:将事件类型定义好,顾客信息可以包含在事件中,但注意事件队列按时间排序。同时,在到达事件发生时,我们记录该顾客的到达时间(可以用一个数组customerArrivalTimes,索引为顾客编号)。另外,引用[3]中特别提到,在离开事件后立即为等待队列中的下一位顾客创建离开事件时,离开事件的发生时间等于当前事件发生时间(即刚结束服务的时间)加上新顾客的服务时间。这一点我们在上面的代码中已经体现。离散事件模拟需要全局的事件队列(优先队列)来管理事件,事件类型包括到达和离开。在模拟过程中,时间不是一步一步推进,而是跳跃到下一个事件发生的时间。由于用户需要实现方案,我们提供代码框架。这里我们用C++实现,参考引用[1]中的队列类,但是也可以使用STL的queue和priority_queue。完整离散事件模拟队列单窗口的代码框架(C++)如下:注意:我们使用STL,需要包含头文件<queue>和<vector>。事件类型定义:事件类(Event)包含:occurTime(发生时间)、type(类型,0到达,1离开)、customerId(顾客编号)。注意:优先队列(事件队列)需要自定义比较函数(按occurTime从小到)。另外,我们假设顾客到达时间间隔服从泊松分布(指数分布),服务时间也服从指数分布(实际中常用)。但也可以指定其他分布。代码示例:</think> ### 银行排队模拟:单队列算法实现方案 在银行排队模拟中,单队列算法是最基础的实现方式,所有顾客进入同一个队列排队,遵循"先进先出"(FIFO)原则。以下是基于队列数据结构的完整实现方案: #### **核心数据结构设计** ```cpp class BankQueue { private: int *items; // 存储队列元素的数组 int capacity; // 队列容量 int front; // 队首索引 int rear; // 队尾索引 int count; // 当前队列元素数量 public: // 构造函数(创建空队列) BankQueue(int size) { capacity = size; items = new int[size]; front = 0; rear = -1; count = 0; } // 检查队列是否为空 bool isEmpty() { return count == 0; } // 检查队列是否已满 bool isFull() { return count == capacity; } // 在队尾添加元素(入队) void enqueue(int customerID) { if (isFull()) throw "Queue full"; rear = (rear + 1) % capacity; items[rear] = customerID; count++; } // 在队首删除元素(出队) int dequeue() { if (isEmpty()) throw "Queue empty"; int customer = items[front]; front = (front + 1) % capacity; count--; return customer; } // 获取队列当前长度 int queueLength() { return count; } }; ``` #### **离散事件模拟流程** 基于引用[3]的离散事件模型: ```cpp void simulateSingleQueue() { // 初始化 BankQueue queue(100); // 创建容纳100人的队列 int currentTime = 0; int nextArrival = 0; // 下一个到达时间 int nextDeparture = -1;// 下一次离开时间 while (currentTime < SIMULATION_TIME) { // 处理到达事件 if (currentTime == nextArrival) { queue.enqueue(generateCustomerID()); nextArrival += generateInterval(); // 生成下个到达间隔 // 如果队列刚变空,设置服务结束时间 if (queue.queueLength() == 1) { nextDeparture = currentTime + generateServiceTime(); } } // 处理离开事件[^3] if (currentTime == nextDeparture) { int customer = queue.dequeue(); logService(customer, currentTime); // 如果队列空,立即开始服务下个客户 if (!queue.isEmpty()) { nextDeparture = currentTime + generateServiceTime(); } else { nextDeparture = -1; // 队列空时无离开事件 } } currentTime++; } } ``` #### **关键实现细节** 1. **时间推进机制** 采用**事件驱动**方式推进模拟时间: - 仅在有事件(到达/离开)发生时才推进时间 - 通过`nextArrival`和`nextDeparture`变量确定下一个事件时间点 2. **服务连续性保证** 当客户完成服务时,**立即从队列中取出下一个客户开始服务**(如引用[3]强调)[^3]: ```cpp if (!queue.isEmpty()) { nextDeparture = currentTime + generateServiceTime(); } ``` 3. **性能统计** 可扩展记录: ```cpp struct Statistics { int totalCustomers = 0; int totalWaitTime = 0; int maxWaitTime = 0; }; // 当客户开始服务时: int waitTime = currentTime - arrivalTime[customer]; stats.totalWaitTime += waitTime; stats.maxWaitTime = max(stats.maxWaitTime, waitTime); ``` #### **适用场景分析** 1. **传统窗口服务** 单一业务柜台(如:专用业务窗口) 2. **自动服务终端** 单一ATM机或自助服务设备队列 3. **流量稳定环境** 客户到达间隔和服务时间波动较小的情况
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值