Day5.队列总结——2020.3.12

这两天在看《算法导论》,大二的时候上过算法和数据结构的课,但是后来很长一段时间都没有练习算法方面的题目,有些生疏了。所以重拾旧识,顺便在leetcode上练练手。

队列的主要思想是FIFO(fist-in,first-out),队列的应用也非常广泛如:顺序队列,循环队列、阻塞队列、并发队列、优先级队列等。

1.顺序队列

顺序队列基于数组,是一块连续的内存空间,原理极为简单,简单写一下算法。

//--------------Queue---------------------
ENQUEUE(Q,x):
		if	tail=length(Q)
				{
				if head=0
				{输出“队列内存空间已满!”;return FALSE;}
				else{
						数据迁移;  //即把从head到length(Q)的数据全部往前挪head个 
						tail=tail-head;
						head=0;  //队头置为0
						}
			}
		end if;
		Q[tail]=x;
		tail=tail+1return TRUE
		
//--------------Dequeue---------------------
DEQUEUE(Q):
		if head=tail 
			return NUL;	//队列为空
		head=head+1;
		return Q[head-1];
		

但是缺点是,在ENQUEUE中,如果tail=length(Q)还是会进行一次数据迁移,性能有影响。因此,有了下面的循环队列。

2.循环队列

循环队列需要解决的问题是如何处理“假溢出”,但是会产生新问题,空队条件和满队条件都是head=tail,存在二义性。
最常用的解决办法是浪费一个单元。
空队判定条件还是head=tail;
而满队的判定条件则是head=(tail+1)%N;
算法如下:

//-------------ENQUEUE
Enqueue(Q,x):
		if((tail+1)%length(Q)==head) //队列已满
			{输出“队列已满”;
			return false;
			}
		Q[tail]=x;
		tail=(tail+1)%length(Q);
		return TRUE
//-------------DEQUEUE
Dequeue(Q):
		if(head==tail) return NULL;
		temp=Q[head];
		head=(head+1)%length(Q);
		return temp;

3.阻塞队列

总结而言,阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。:
1.支持阻塞的插入方法:队列满的时候,阻塞元素的插入流程,直到队列不满,则唤醒;
2.支持阻塞的移除过程:队列空的时候,阻塞获取元素的线程,直到队列里有元素了再唤醒。
阻塞队列常用于消费者和生产者场景,这两个操作提供了下面4个操作
在这里插入图片描述
抛出异常:当阻塞队列满时候,再往队列里插入元素,会抛出 IllegalStateException("Queue full")异常。当队列为空时,从队列里获取元素时会抛出NoSuchElementException 异常 。
返回特殊值:若插入成功,返回true,失败false;移除的时候,队列为空,返回null,否则true(功能类似于普通队列的Enqueue和Dequeue)
一直阻塞:列满时,如果生产者线程往队列里 put 元素,队列会一直阻塞生产者线程,直到拿到数据,或者响应中断退出。列空时,消费者线程试图从队列里 take 元素,队列也会阻塞消费者线程,直到队列可用。
超时退出:列满时,队列会阻塞生产者线程一段时间,如果超过一定的时间,生产者线程就会退出。

如果是无界阻塞队列,队列不可能会出现满的情况,所以使用put或offer方法永远不会被阻塞,而且使用offer方法时,该方法永远返回true

JDK7 提供了 7 个阻塞队列:(真真是五花八门啊)
ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。
LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列。
PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列。
DelayQueue:一个使用优先级队列实现的无界阻塞队列。
SynchronousQueue:一个不存储元素的阻塞队列。
LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列

下面有篇文章写的很好:
https://www.iteye.com/blog/wsmajunfeng-1629354

4.优先队列

又称优先级队列,这个队列在大二数据结构课程设计的时候,有一道题我偷过懒,直接用的某个库里的优先队列。(后面会放上当时的题目)
优先队列的特点:
最大优先队列:无论入队的顺序,当前最大的元素先出列
最小优先队列:无论入队的顺序,当前最小的元素先出列
借助的有力工具:二叉堆
1.入队操作
把要入队的那个元素插到队尾,做上浮操作
2.出队操作
取出首个元素,把最尾的元素提到首部,做下沉操作。

import java.nio.file.Path;
import java.util.Arrays;

public class PriorityQueue{
    private int[] array;
    private  int size;

    public PriorityQueue(){
        this.array=new int[10];
    }
    public void Enqueue(int x){
        if(size>=array.length){
            reSize();//扩容
        }
        array[size]=x;
        size++;
        up_operate(size-1);
    }
    public int Dequeue(){
        if(size==0)  {return -32768;}
        else {
            int result_ret = array[0];
            array[0] = array[size - 1];
            size--;
            //下称操作
            down_operate(0);
            return result_ret;
        }
    }

    //扩容
    private void reSize(){
        int newsize=2*size;
        this.array= Arrays.copyOf(this.array,newsize);
    }
    private int Left(int x){
        return 2*x+1;
    }
    private int Right(int x){
        return 2*x+2;
    }
    private int Parent(int x){
        return (x-1)/2;
    }
    private  void up_operate(int index){
        int parent_index= Parent(index);
        int min;
        //index为奇数,即左孩子
if(index>0) {
    if (array[index] < array[Parent(index)]) {
        min = index;
    } else {
        min = Parent(index);
    }
    //index偶数,即右孩子
    if ((index % 2 == 0) && array[min] > array[index - 1]) {
        min = index - 1;
    }
    if (min != Parent(index)) {
        int temp = array[Parent(index)];
        array[Parent(index)] = array[min];
        array[min] = temp;
        up_operate(min);
    }
}

    }

    private void down_operate(int index){
        int min=index;
        if(Left(index)<size){//左孩子存在
            if(array[min]>array[Left(index)]){
                min=Left(index);

            }
        }
        if(Right(index)<size){
            if(array[min]>array[Right(index)]){
                min=Right(index);}
        }
        if(min!=index){
        int temp=array[index];
        array[index]=array[min];
        array[min]=temp;
        down_operate(min);}
    }

    public static void main(String[] args){
        PriorityQueue priorityQueue=new PriorityQueue();
        priorityQueue.Enqueue(5);
        priorityQueue.Enqueue(3);
        priorityQueue.Enqueue(6);
        priorityQueue.Enqueue(9);
        priorityQueue.Enqueue(8);
        priorityQueue.Enqueue(6);
        priorityQueue.Enqueue(7);
        int de;
        while(true) {
            de = priorityQueue.Dequeue();
            if (de != -32768) {
                System.out.println("堆顶数据:" + de+"arrays[]:"+Arrays.toString(priorityQueue.array)+"size:"+priorityQueue.size);
            }
            else{
                System.out.println("队列已空!");
                break;
            }
        }

    }

}

运行结果:
在这里插入图片描述

下面是之前数据结构老师给的题目,顺便贴上来,当时没有好好想优先队列怎么实现,用起来真爽啊哈哈哈。反思!!!

2、公共钥匙盒(必做)(线性表,栈,队列) [问题描述]
  有一个学校的老师共用N个教室,按照规定,所有的钥匙都必须放在公共钥匙盒里,老师不能带钥匙回家。每次老师上课前,都从公共钥匙盒里找到自己上课的教室的钥匙去开门,上完课后,再将钥匙放回到钥匙盒中。
  钥匙盒一共有N个挂钩,从左到右排成一排,用来挂N个教室的钥匙。一串钥匙没有固定的悬挂位置,但钥匙上有标识,所以老师们不会弄混钥匙。
  每次取钥匙的时候,老师们都会找到自己所需要的钥匙将其取走,而不会移动其他钥匙。每次还钥匙的时候,还钥匙的老师会找到最左边的空的挂钩,将钥匙挂在这个挂钩上。如果有多位老师还钥匙,则他们按钥匙编号从小到大的顺序还。如果同一时刻既有老师还钥匙又有老师取钥匙,则老师们会先将钥匙全还回去再取出。
  今天开始的时候钥匙是按编号从小到大的顺序放在钥匙盒里的。有K位老师要上课,给出每位老师所需要的钥匙、开始上课的时间和上课的时长,假设下课时间就是还钥匙时间,请问最终钥匙盒里面钥匙的顺序是怎样的?
[基本要求] 输入格式   输入的第一行包含两个整数N, K。   接下来K行,每行三个整数w, s,
c,分别表示一位老师要使用的钥匙编号、开始上课的时间和上课的时长。可能有多位老师使用同一把钥匙,但是老师使用钥匙的时间不会重叠。
  保证输入数据满足输入格式,你不用检查数据合法性。 输出格式
  输出一行,包含N个整数,相邻整数间用一个空格分隔,依次表示每个挂钩上挂的钥匙编号。 样例输入 5 2 4 3 3 2 2 7 样例输出
1 4 3 2 5 样例说明
  第一位老师从时刻3开始使用4号教室的钥匙,使用3单位时间,所以在时刻6还钥匙。第二位老师从时刻2开始使用钥匙,使用7单位时间,所以在时刻9还钥匙。
  每个关键时刻后的钥匙状态如下(X表示空):   时刻2后为1X345;   时刻3后为1X3X5;   时刻6后为143X5;
  时刻9后为14325。 课程设计要求: (1)要求从文本文件中输入;
(2)根据时间进程,将取走钥匙和归还钥匙分别视为事件,放入队列中,然后通过每个事件的先后发生对钥匙盒的状态进行变更;
(3)严格按照要求的输入输出格式进行数据的输入、输出(训练CSP考试中的格式化输入输出的正确性);
(4)选做:通过图形界面来显示钥匙盒的即时状态,以及事件队列的状态。

这是当时的代码

#include<stdio.h>
#include<stdlib.h>
#include<queue>
using namespace std;
#include<iostream>
using namespace std;
#include<fstream>


struct node{
int number;//钥匙编号
int situation;//状态,1表示上课前借钥匙,0表示下课后借钥匙
int time;//时间节点;

  bool operator <(const node &u) const///按时间从小到大排序//优先队列
  {  if(time>u.time)
       return true;
     else 
		 return false;
  }
};
priority_queue<node> q;
int a[10000];//钥匙盒
int main()
{   
	fstream File;
	File.open("C:\\Users\\THINKPAD\\Desktop\\数据结构实验\\课设\\file2.txt",ios::in|ios::binary);
	if(File.fail())
	{cout<<"cannot open file2\n"<<endl;
     exit(0);}
	int i;
	for(i=0;i<10000;i++)
    a[i]=i;//初始化;
	int n,k,w,s,c;
 //scanf("%d %d",&n,&k);
	File>>n>>k;
	cout<<n<<" ";
	cout<<k<<endl;
 node p;
 for(int j=0;j<k;j++)
 { //scanf("%d %d %d",&w,&s,&c);
	 File>>w;cout<<w<<" ";
	 File>>s;cout<<s<<" ";
	 File>>c;cout<<c<<endl;
   p.number=w;
   p.situation=1;//判断借钥匙
   p.time=s;
   q.push(p);
   p.number=w;
   p.situation=0;//判断还钥匙
   p.time=s+c;
   q.push(p);
 }

 while(!q.empty())
 {p=q.top();
  q.pop();
     if(p.situation==1)
	 {  for(i=1;i<=n;i++)
	    {if(p.number==a[i])
			{a[i]=-1;break;}
		}
	 }
	 else
	 { for(i=1;i<=n;i++)
	    {if(a[i]==-1)
		   {a[i]=p.number;break;}
		}//for
	 }//else
 }//while
 cout<<"<<钥匙盒的最终结果为:>>"<<endl;
for(i=1;i<=n;i++)
 printf("%d ",a[i]);
return 0;
}




这是JAVA中队列应用的一篇文章
https://www.cnblogs.com/yuansc/p/9087044.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值