标签:
(java版)
(C版)
队列也是表,使用队列时,插入在一端进行,而删除在另一端进行。
常用的操作:
Queue.c
Queue接口与List、Set同一级别,都是继承了Collection接口。LinkedList实现了Queue接 口。Queue接口窄化了对LinkedList的方法的访问权限(即在方法中的参数类型如果是Queue时,就完全只能访问Queue接口所定义的方法 了,而不能直接访问 LinkedList的非Queue的方法),以使得只有恰当的方法才可以使用。BlockingQueue 继承了Queue接口。
队列是一种数据结构.它有两个基本操作:在队列尾部加人一个元素,和从队列头部移除一个元素就是说,队列以一种先进先出的方式管理数据,如果你试图向一个 已经满了的阻塞队列中添加一个元素或者是从一个空的阻塞队列中移除一个元索,将导致线程阻塞.在多线程进行合作时,阻塞队列是很有用的工具。工作者线程可 以定期地把中间结果存到阻塞队列中而其他工作者线线程把中间结果取出并在将来修改它们。队列会自动平衡负载。如果第一个线程集运行得比第二个慢,则第二个 线程集在等待结果时就会阻塞。如果第一个线程集运行得快,那么它将等待第二个线程集赶上来。下表显示了jdk1.5中的阻塞队列的操作:
add 增加一个元索 如果队列已满,则抛出一个IIIegaISlabEepeplian异常
remove 移除并返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
element 返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
offer 添加一个元素并返回true 如果队列已满,则返回false
poll 移除并返问队列头部的元素 如果队列为空,则返回null
peek 返回队列头部的元素 如果队列为空,则返回null
put 添加一个元素 如果队列满,则阻塞
take 移除并返回队列头部的元素 如果队列为空,则阻塞
remove、element、offer 、poll、peek 其实是属于Queue接口。
阻塞队列的操作可以根据它们的响应方式分为以下三类:aad、removee和element操作在你试图为一个已满的队列增加元素或从空队列取得元素时 抛出异常。当然,在多线程程序中,队列在任何时间都可能变成满的或空的,所以你可能想使用offer、poll、peek方法。这些方法在无法完成任务时 只是给出一个出错示而不会抛出异常。
注意:poll和peek方法出错进返回null。因此,向队列中插入null值是不合法的。
还有带超时的offer和poll方法变种,例如,下面的调用:
boolean success = q.offer(x,100,TimeUnit.MILLISECONDS);
尝试在100毫秒内向队列尾部插入一个元素。如果成功,立即返回true;否则,当到达超时进,返回false。同样地,调用:
Object head = q.poll(100, TimeUnit.MILLISECONDS);
如果在100毫秒内成功地移除了队列头元素,则立即返回头元素;否则在到达超时时,返回null。
最后,我们有阻塞操作put和take。put方法在队列满时阻塞,take方法在队列空时阻塞。
java.ulil.concurrent包提供了阻塞队列的4个变种。默认情况下,LinkedBlockingQueue的容量是没有上限的(说的不准确,在不指定时容量为Integer.MAX_VALUE,不要然的话在put时怎么会受阻呢),但是也可以选择指定其最大容量,它是基于链表的队列,此队列按 FIFO(先进先出)排序元素。
ArrayBlockingQueue在构造时需要指定容量, 并可以选择是否需要公平性,如果公平参数被设置true,等待时间最长的线程会优先得到处理(其实就是通过将ReentrantLock设置为true来 达到这种公平性的:即等待时间最长的线程会先操作)。通常,公平性会使你在性能上付出代价,只有在的确非常需要的时候再使用它。它是基于数组的阻塞循环队 列,此队列按 FIFO(先进先出)原则对元素进行排序。
PriorityBlockingQueue是一个带优先级的 队列,而不是先进先出队列。元素按优先级顺序被移除,该队列也没有上限(看了一下源码,PriorityBlockingQueue是对 PriorityQueue的再次包装,是基于堆数据结构的,而PriorityQueue是没有容量限制的,与ArrayList一样,所以在优先阻塞 队列上put时是不会受阻的。虽然此队列逻辑上是无界的,但是由于资源被耗尽,所以试图执行添加操作可能会导致 OutOfMemoryError),但是如果队列为空,那么取元素的操作take就会阻塞,所以它的检索操作take是受阻的。另外,往入该队列中的元 素要具有比较能力。
最后,DelayQueue(基于PriorityQueue来实现的)是一个存放Delayed 元素的无界阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部是延迟期满后保存时间最长的 Delayed 元素。如果延迟都还没有期满,则队列没有头部,并且poll将返回null。当一个元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一个小于或等于零的值时,则出现期满,poll就以移除这个元素了。此队列不允许使用 null 元素。 下面是延迟接口:
放入DelayQueue的元素还将要实现compareTo方法,DelayQueue使用这个来为元素排序。
下面的实例展示了如何使用阻塞队列来控制线程集。程序在一个目录及它的所有子目录下搜索所有文件,打印出包含指定关键字的文件列表。从下面实例可以看出,使用阻塞队列两个显著的好处就是:多线程操作共同的队列时不需要额外的同步,另外就是队列会自动平衡负载,即那边(生产与消费两边)处理快了就会被阻塞掉,从而减少两边的处理速度差距。下面是具体实现:
/*******公用的一个报警配置类*******************************************************/
public class AlarmConfig {//AlarmConfig 报警配置类
public static final boolean FIND_ENABLE = true;//FINDENABLE 启用检测
public static final boolean FIND_UNABLE = false;//FINDUNABLE 关闭检测 当发生线程开启时,侦测线程是关闭的。
public static boolean ReceiveFind = FIND_UNABLE ;//ReceiveFind 接收检测 初始状态是关闭的
public static QueueArray queueArray = new QueueArray();//QueueArray 类里放这一个循环队列
public AlarmConfig() {
}
}
/***********循环队列类****************************************************/
public class QueueArray {//队列
private Object[] obj; //初始化储存空间
private int front; //头指针,若队列不为空,指向队列头元素
private int rear; //尾指针,若队列不为空,指向队列尾元素的下一个位置
public QueueArray() {
this(10);
}
public QueueArray(int size){
//队列进行初始化
obj=new Object[size];
front=0;
rear=0;
}
public Object dequeue(){//出队
if(rear==front){
return null;
}
Object ob=obj[front];
front=(front+1)%obj.length;
return ob;
}
public boolean enqueue(Object obje){//入队
if((rear+1)%obj.length==front){
return false;
}
obj[rear]=obje;
rear=(rear+1)%obj.length;
return true;
}
public static void main(String[] args) {
QueueArray d=new QueueArray(10);
for(int i=0;i<=20;i++){
System.out.println(i+" "+ d.enqueue(i));
if(i>8){
System.out.println(i+" "+d.dequeue());
}
}
}
}
/*********侦测线程****************************************************************/
public class MonitorThread implements Runnable{ //MonitorThread 是 侦测线程
private Thread thread; // 分配新的 线程 对象。
private boolean stop = true;
public void strat() {//开启方法
if (stop) {//如果stop等于true 那么就给stop赋值false,然后开启一个线程
thread = new Thread(this);// this 是其 run 方法被调用的对象
stop = false;
thread.start(); // 开始一个线程
}
}
public void stop() {//停止方法
stop = true;//给stop 赋值为true
thread = null;
}
public void run() {
while (!stop) {
if (AlarmConfig.ReceiveFind) {
Object num=AlarmConfig.queueArray.dequeue();
System.out.println("检测接收:"+num);
look(num);
AlarmConfig.ReceiveFind = AlarmConfig.FIND_UNABLE;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void look(Object ob){
if(ob.equals(2)||ob.equals(12)){
System.out.println("报警! 发现错误报告! ======");
}
}
}
/********发生器线程********************************************************************/
public class ThreadA implements Runnable {
private Thread thread;// 分配新的 线程 对象。
private boolean stop = true;
private int num = 1;
public ThreadA() {// 无参的构造方法
//自动生成构造函数存根
}
public void strat() {//开启方法
if (stop) {//如果stop等于true 那么就给stop赋值false,然后开启一个线程
thread = new Thread(this);// this 是其 run 方法被调用的对象
stop = false;
thread.start(); // 开始一个线程
System.out.println("**当前stop为*******" + stop);
}
}
public void stop() {//停止方法
stop = true;//给stop 赋值为true
System.out.println(" stop true");
thread = null;
}
public void run() {
System.out.println("*test**");
while (!stop) {
if (!AlarmConfig.ReceiveFind) {
System.out.println(num + " 发生器: "+ AlarmConfig.queueArray.enqueue(num));
AlarmConfig.ReceiveFind = AlarmConfig.FIND_ENABLE;
num++;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/*************测试类******************************************************/
public class TestMainThread {
public TestMainThread() {
// TODO Auto-generated constructor stub
}
public static void main(String[] args) {
ThreadA treadA = new ThreadA();
treadA.strat();
//treadA.stop();
MonitorThread monitorThread=new MonitorThread();
monitorThread.strat();
//monitorThread.stop();
}
}
实验要求:
(1)编写链接队列的基本操作函数
1.进队函数 EnQueue(LinkQueue *Q,QElemType e)
2.出队函数 ,队空 DeQueue(LinkQueue *Q,QElemType e)
3.输出队列中元素 OutputQueue(LinkQueue *Q)
(2)调用上述函数实现下列操作,操作步骤如下
1.调用进队函数建立一个队列
2.读取队列中的第一个元素
2.从队列中删除元素
4.输出队列中的所有元素
(3)编写环形队列的基本操作函数
1.进队函数 EnQueue(SqQueue *Q,QElemType e)
2.出队函数 ,队空 DeQueue(SqQueue *Q,QElemType e)
3.输出队列中元素 OutputQueue(SqQueue *Q)
(4)调用上述函数实现下列操作,操作步骤如下
1.调用进队函数建立一个队列
2.读取队列中的第一个元素
2.从队列中删除元素
4.输出队列中的所有元素
1.链接队列:
#include<stdio.h>
#include<malloc.h>
typedef struct node
{int data;
struct node *next;
};
typedef struct
{struct node *front;
struct node *rear;
}LinkQueue;
InitQueue(LinkQueue *Q)
{ Q->front=(struct node *)malloc(sizeof( struct node));
Q->rear=Q->front;
Q->front->next=NULL;
}
EnQueue(LinkQueue *Q,int e)
{struct node *p;
p=(struct node *)malloc(sizeof(struct node ));
p->data=e;
p->next=NULL;
Q->rear->next=p;
Q->rear=p;
}
DeQueue(LinkQueue *Q,int e)
{ struct node *p;
if(Q->front==Q->rear)
return 0;
else{
p=Q->front->next;
Q->front->next=p->next;
if(p->next=NULL)Q->rear=Q->front;
return(p->data);
free(p);
}
}
OutputQueue(LinkQueue *Q)
{ struct node *p;
p=Q->front->next;
while(p!=NULL)
{ printf("%d ",p->data);
p=p->next;
}
}
GetFront(LinkQueue *Q)
{ struct node *p;
p=Q->front->next;
printf("%d",p->data);
}
void main()
{ LinkQueue s;
int i,max,e,item;
InitQueue(&s);
printf("put a max:");
scanf("%d",&max);
printf("shu ru yuan su");
for(i=0;i<max;i++){
scanf("%d",&e);
EnQueue(&s,e);}
OutputQueue(&s);
printf("\n");
printf("di yi ge yuan su wei:");
GetFront(&s);
printf("\n");
printf("shu ru shan chu yuan su :");
scanf("%d",&item);
DeQueue(&s,item);
OutputQueue(&s);
printf("\n");
}
2.环形队列:
#define MAXQSIZE 100
#include<stdio.h>
#include<malloc.h>
typedef struct{
int *base;
int front;
int rear;
}SqQueue;
InitQueue(SqQueue *Q)
{ Q->base=(int *)malloc(MAXQSIZE * sizeof(int));
if(!Q->base)exit(1);
Q->front=Q->rear=0;
}
EnQueue(SqQueue *Q,int e)
{ Q->base[Q->rear]=e;
Q->rear=(Q->rear+1)%MAXQSIZE;
}
DeQueue(SqQueue *Q,int *e)
{ if(Q->front==Q->rear)return 0;
e=Q->base[Q->front];
Q->front=(Q->front+1)%MAXQSIZE;
}
GetFront(SqQueue *Q)
{ if(Q->front==Q->rear)return 0;
else printf("%d",Q->base[(Q->front)%MAXQSIZE]);
}
OutputQueue(SqQueue *Q)
{ int i;
i=Q->front;
if(!(Q->front==Q->rear))
{
while((i%MAXQSIZE)!=Q->rear)
{ printf("%d ",Q->base[i%MAXQSIZE]);
i++;
}
}
}
void main()
{ SqQueue *s;
int i,max,e,item;
InitQueue(&s);
printf("put a max:");
scanf("%d",&max);
printf("shu ru yuan su :");
for(i=0;i<max;i++){
scanf("%d",&e);
EnQueue(&s,e);}
OutputQueue(&s);
printf("\n");
printf("di yi ge yuan su wei :");
GetFront(&s);
printf("\n");
printf("shu ru shan chu yuan su:");
scanf("%d",&item);
DeQueue(&s,item);
OutputQueue(&s);
}
#include<iostream.h>
#include<malloc.h>
#include<stdlib.h>
#define MAXSIZE 100
#define TRUE 1
#define FALSE 0
typedef int DataType;
typedef struct
{
DataType data[MAXSIZE];
int front; //头指针指示器
int rear; //为指针指示器
}SeqQueue;
//初始化操作
void InitQueue(SeqQueue *Q)
{//将*Q初始化为一个空的循环队列
Q->front=Q->rear=0;
}
//判断队列是否为空或满
void IsEmpty_full(SeqQueue *Q)
{
if(Q->front==Q->rear)
cout<<"该队列为空"<<endl;
else if((Q->rear+1)%MAXSIZE==Q->front)
cout<<"该队列为满"<<endl;
else
cout<<"该队列既不为空也不为满"<<endl;
}
//入队操作
int EnterQueue(SeqQueue *Q,DataType x)
{//将元素x入队
if((Q->rear+1)%MAXSIZE==Q->front) //队列已经满了
return(FALSE);
Q->data[Q->rear]=x;
Q->rear=(Q->rear+1)%MAXSIZE; //重新设置队尾指针
return(TRUE); //操作成功
}
//出队操作
int DeleteQueue(SeqQueue *Q,DataType *x)
{//删除队列的队头元素,用x返回其值
if(Q->front==Q->rear) //队列为空
return(FALSE);
*x=Q->data[Q->front];
Q->front=(Q->front+1)%MAXSIZE; //重新设置队头指针
return(TRUE); //操作成功
}
//清空元素
void ClearQueue_Sq(SeqQueue &Q)
{
Q.front=Q.rear=0;
}
//构造队列,数据元素由键盘输入
void CreateQueue_Sq(SeqQueue &Q)
{
DataType temp;
cout<<"输入数据元素(按-1结束)"<<endl;
cin>>temp;
while(temp!=-1)
{
if((Q.rear+1)%MAXSIZE == Q.front) cout<<"队列已经满了";
else
{
Q.data[Q.rear]=temp;
Q.rear=(Q.rear+1)%MAXSIZE;
cin>>temp;
}
}
}
//队列的长度
int QueueLength_Sq(SeqQueue Q)
{
return (Q.rear-Q.front+MAXSIZE) % MAXSIZE;
}
//由头到尾依次输出队列的数据元素
void OutputQueue_Sq(SeqQueue Q)
{
if(Q.front==Q.rear) cout<<"空队列,没有元素"<<endl;
else
{
cout<<"该循环队列各元素依次为:";
for(int k=0; k<=QueueLength_Sq(Q)-1; k++)
cout<<Q.data[(Q.front+k)%MAXSIZE]<<" ";
cout<<endl;
}
}
void main()
{
int flag=1,select;
cout<<" ☆☆☆☆循环队列的基本操作☆☆☆☆"<<endl;
cout<<" ☆1.请输入循环队列元素:☆ "<<endl;
cout<<" ☆2.判断队列是否为空或是否为满☆"<<endl;
cout<<" ☆3.当前队头元素出队并将其输出循环队列的各元素☆ "<<endl;
cout<<" ☆4.将x入队并输出循环队列的各元素☆ "<<endl;
cout<<" ☆5.当前循环队列的长度☆ "<<endl;
cout<<" ☆6.清空队列☆ "<<endl;
cout<<" ☆7.退出☆ "<<endl;
while(flag)
{
cout<<"请选择: ";
cin>>select;
SeqQueue Q;
int x,a,e;
switch(select)
{
case 1:
InitQueue(&Q);
CreateQueue_Sq(Q);
OutputQueue_Sq(Q);
break;
cout<<"请选择: ";
case 2:
IsEmpty_full(&Q);
break;
cout<<"请选择: ";
case 3:
DeleteQueue(&Q,&a);
OutputQueue_Sq(Q);
break;
cout<<"请选择: ";
case 4:
cout<<"请输入入队的元素x:";
cin>>x;
EnterQueue(&Q,x);
OutputQueue_Sq(Q);
break;
cout<<"请选择: ";
case 5:
cout<<"当前循环队列的长度是:"<<(Q.rear-Q.front+MAXSIZE) % MAXSIZE<<endl;
break;
cout<<"请选择: ";
case 6:
ClearQueue_Sq(Q);
cout<<"该循环队列已清空, ";
break;
case 7:
flag=0;
break;
}
}
}
队列是先进先出的数据结构,出队的一端叫队首,入队的一端叫队尾,就像是日常生活中排队买火车票一样,下面是队列的基本操作
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef int QElemType;
typedef struct QNode
{
QElemType data;
struct QNode *next;
}QNode,*QueuePtr;
typedef struct
{
QueuePtr front;
QueuePtr rear;
}LinkQueue;
int InitQueue(LinkQueue *Q);
int DestroyQueue(LinkQueue *Q);
int ClearQueue(LinkQueue *Q);
int QueueEmpty(LinkQueue Q);
int QueueLength(LinkQueue Q);
int GetHead(LinkQueue Q,QElemType *e);
int InsertQueue(LinkQueue *Q,QElemType e);
int DelQueue(LinkQueue *Q,QElemType *e);
int PrintQueue(LinkQueue Q);
int InitQueue(LinkQueue *Q)
{
Q->front = Q->rear = (QueuePtr )malloc(sizeof(QNode));
if(!Q->front)
{
perror("malloc error\n");
return -1;
}
Q->front->next = NULL;
Q->front->data = 0;
return 0;
}
int DestroyQueue(LinkQueue *Q)
{
while(Q->front)
{
Q->rear = Q->front->next;
free(Q->front);
Q->front = Q->rear;
}
Q = NULL;
return 0;
}
int ClearQueue(LinkQueue *Q)
{
return 0;
}
int QueueEmpty(LinkQueue Q)
{
if(Q.front == Q.rear)
{
return 1;
}
else
{
return 0;
}
}
int QueueLength(LinkQueue Q)
{
return Q.front->data;
}
int GetHead(LinkQueue Q,QElemType *e)
{
if(Q.front->next == NULL)
{
perror("Queue is empty!\n");
*e = -1;
return -1;
}
*e = Q.front->next->data;
return 0;
}
int InsertQueue(LinkQueue *Q,QElemType e)
{
QueuePtr p = (QueuePtr )malloc(sizeof(QNode));
if(p == NULL)
{
perror("malloc error!\n");
return -1;
}
p->data = e;
p->next = NULL;
(Q->rear)->next = p;
Q->rear = p;
Q->front->data++;
return 0;
}
int DelQueue(LinkQueue *Q,QElemType *e)
{
if(Q->front == Q->rear)
{
perror("The queue is empty!");
return -1;
}
QueuePtr p = (QueuePtr )malloc(sizeof(QNode));
p = Q->front->next;
*e = p->data;
Q->front->next = p->next;
if(Q->rear == p)
{
Q->rear = Q->front;
}
free(p);
Q->front->data--;
return 0;
}
int PrintQueue(LinkQueue Q)
{
Q.front = Q.front->next;
while(Q.front != NULL)
{
printf("%d-----",Q.front->data);
Q.front = Q.front->next;
}
return 0;
}
1.链式队列
//队列结点结构体
typedef struct QNode
{ QElemType data;
QNode *next;
}*Queueptr;
------------------------------
//指向结点的指针
struct LinkQueue
{ Queueptr front,rear;
}
2.顺序队列---循环队列
性质如下:
1.头指针指向对头元素,尾指针指向队尾的下一个位置。(这里的指针都是为指针,实际是数组序号)
2.为了区分队满与对空,则定义一个存储空间为MAX_QSIZE大小的队列只允许存放MAX_QSIZE-1个数据。
3.判空条件为:if(Q.front ==Q.rear) return true;
判满条件为:if((Q.rear+1)%MAX_QSIZE==Q.front) return true;
4.循环队列的长度为:(Q.read-Q.front+MAX_SIZE)%MAX_QSIZE
5.当删除对头元素或者在对尾插入元素时指针均需向后移动。操作为:
Q.rear=(Q.rear+1)%MAX_QSIZE;
Q.front=(Q.front+1)%MAX_QSIZE;
结构体定义如下:
struct SqQueue
{QElemType *base;//指向开辟的空间的首地址
int front;
int rear;
}
#include<iostream.h>
#include <stdlib.h>
#include <malloc.h>
#include<stdio.h>
#define FALSE 0
#define TRUE 1
#define OK 1
#define ERROR 0
#define MAXSIZE 100
typedef int QueueElementType;
typedef struct
{
QueueElementType element[MAXSIZE];
int front;
int rear;
}SeqQueue;
//初始化
int InitQueue(SeqQueue *Q)
{
Q->front=Q->rear=0;
return(TRUE);
}
//入队
int EnterQueue(SeqQueue *Q,QueueElementType x)
{
if((Q->rear+1)%MAXSIZE==Q->front)
return(FALSE);
Q->element[Q->rear]=x;
Q->rear=(Q->rear+1)%MAXSIZE;
return(TRUE);
}
//出队
int DeleteQueue(SeqQueue *Q,QueueElementType *x)
{
if(Q->front==Q->rear)
return(FALSE);
*x=Q->element[Q->front];
Q->front=(Q->front+1)%MAXSIZE;
return(TRUE);
}
//求长度
int LengthQueue(SeqQueue *Q)
{
printf("%d",(Q->rear-Q->front+MAXSIZE) % MAXSIZE);
printf("\n");
return(TRUE);
}
//输出链表
void PrintfQueue(SeqQueue *Q)
{
int j;
if(Q->front==Q->rear)
cout<<"队列为空"<<endl;
else
{
j=((Q->rear-Q->front+MAXSIZE) % MAXSIZE)-1;
for(int i=0; i<=j; i++)
printf("%d",Q->element[(Q->front+i)%MAXSIZE]);
printf("\n");
}
}
//判断循环队列是否为空或为满
void JudgeQueue(SeqQueue *Q)
{
if(Q->front==Q->rear)
{
printf("该队列为空");
printf("\n");
}
else if((Q->rear+1)%MAXSIZE==Q->front)
{
printf("该队列为满");
printf("\n");
}
else
{
printf("该队列既不为空也不为满");
printf("\n");
}
}
//销毁队列
void DestroyQueue(SeqQueue *Q)
{
Q->front=Q->rear=0;
}
void main()
{
SeqQueue Q;
InitQueue(&Q);
int flag=1;
printf(" ************^^^^^^^循环队列功能菜单^^^^^^^************");
printf("\n");
printf("请选择操作:");
printf("\n");
printf("1.入队操作");
printf("\n");
printf("2.出队操作");
printf("\n");
printf("3.判断队列空或满");
printf("\n");
printf("4. 求队列长度");
printf("\n");
printf("5.销毁队列");
printf("\n");
printf("6.退出");
printf("\n");
while(flag)
{
int x,e;
cin>>e;
switch(e){
case 1:printf("请输入要入队的整型值:(限一个)");
printf("\n");
cin>>x;
EnterQueue(&Q,x);
printf("队列为:");
PrintfQueue(&Q);
break;
case 2: DeleteQueue(&Q,&x);
printf("队列为:");
PrintfQueue(&Q);
break;
case 3:JudgeQueue(&Q);
break;
case 4:printf("链表长度为:");
LengthQueue(&Q) ;
break;
case 5:DestroyQueue(&Q);
printf("销毁成功!");
break;
case 6:flag=0;
break;
}
}
}
(C版之双端队列)
用数组实现栈,循环队列,双端队列的方法其实非常简单。
deque双端队列容器
一、基本原理
deque的元素数据采用分块的线性结构进行存储,如图所示。deque分成若干线性存储块,称为deque块。块的大小一般为512个字节,元素的数据类型所占用的字节数,决定了每个deque块可容纳的元素个数。
所有的deque块使用一个Map块进行管理,每个Map数据项记录各个deque块的首地址。Map是deque的中心部件,将先于deque块,依照deque元素的个数计算出deque块数,作为Map块的数据项数,创建出Map块。以后,每创建一个deque块,都将deque块的首地址存入Map的相应数据项中。
在Map和deque块的结构之下,deque使用了两个迭代器M_start和M_finish,对首个deque块和末deque块进行控制访问。迭代器iterator共有4个变量域,包括M_first、M_last、M_cur和M_node。M_node存放当前deque块的Map数据项地址,M_first和M_last分别存放该deque块的首尾元素的地
址(M_last实际存放的是deque块的末尾字节的地址),M_cur则存放当前访问的deque双端队列的元素地址。
二、应用
1、创建
(1)deque()
创建一个没有任何元素的deque对象。此构造函数的更一般形式是“deque(const A& a = A())”,A是一个内存分配器,可缺省。如deque<int> d;
(2)deque(size_type n)
创建一个具有n个元素的deque对象,每个元素采用它的类型下的默认值。deque<int> d(10); //默认值为0
(3)deque(size_type n, const T& value)
创建一个具有n个元素的deque对象,这些元素的初始值为value。
(4)deque(const deque&)
deque的拷贝构造函数,通过拷贝一个deque对象的元素值,创建一个新的deque对象。此时,新旧deque对象具有相同块数的deque块,各自内部的元素也对应相等。
deque<char> d1(5,‘k‘);
deque<char> d2(d1);
(5)deque(const InputIterator first, const InputIterator last, const A& a=A())
将迭代器区间[first,last)所指的元素拷贝到一个新创建的deque对象中,其中内存分配器可缺省。
//利用int数组iArray,创建了一个deque对象d
int iArray [] = {11, 13, 19, 23, 27};
deque<int> d(iArray, iArray + 5);
2、初始化
利用deque提供的push_back()函数,可在尾部压入新元素value,常用作deque容器的初始化赋值。
3、访问
deque的元素同样可采用数组和迭代器方式进行访问,用“d[i]”取得deque对象d的第i个元素(0≤i<d.size()),或用迭代器i的“*”操作“*i”取得i所指向的元素。
(1)iterator begin()
(2)iterator end()
可反向遍历deque双端队列中元素迭代器:
(1)reverse_iterator rbegin()
(2)reverse_iterator rend()
4、插入
1)deque 具有高效的头部插入元素的函数push_front()。
void push_front(const T&)
2)将在pos位置之前,插入新元素x。
iterator insert(iterator pos, const T& x)
5、删除
(1)void pop_front()
删除deque的第一个元素。
(2)void pop_back()
删除deque的最后一个元素。
(3)iterator erase(iterator pos)
删除pos所指向的元素。
(4)iterator erase(iterator first, iterator last)
删除迭代器区间[first,last)所指向的所有元素。
(5)void clear()
删除所有元素。
6、交换
void swap(deque&)
如d1.swap(d2);
7、其它
(1)bool empty()
判断deque容器是否已有元素,是则返回true,否则返回false。
(2)size_type size()
当前deque容器的元素个数。
(3)size_type max_size()
系统所支持的deque容器的最大元素个数。
(4)reference front()
deque容器的首元素(引用返回),要求deque不为空。
(5)reference back()
deque容器的末元素(引用返回),要求deque不为空。
(C++版双端队列)
(python版之双端队列)
什么是双端队列
deque,全名double-ended queue)是一种具有队列和栈的性质的数据结构。双端队列中的元素可以从两端弹出,其限定插入和删除操作在表的两端进行。
下面简单的介绍一下python中双端队列的操作函数;
from collections import deque #首先从collections 模块中导入deque类
下来我们定义一个双端队列
1.A=deque([]) #创建一个空的双队列
2.A.append(n) #从右边像队列中增加元素 ,n表示增加的元素
3.A.appendleft(n) #从左边像队列中增加元素,n表示增加的元素
4.A.clear() #清空队列
5.A.count(n) #在队列中统计元素的个数,n表示统计的元素
6.A.extend(n) #从右边扩展队列,n表示扩展的队列
7.A.extendleft(n) #从左边扩展队列,n表示扩展的队列
8.A.pop() #从队列的右边删除元素,并且返回删除值
9.A.popleft() #从队列的左边删除元素,并且返回删除值
10.A.remove(n) #从队列中删除指定的值
11.A.reverse() #翻转队列
12.A.rotate(n) #旋转队列,默认时值为1,由右边开始旋转,负值代表左边旋转,n代表从队列的第一个元素开始,n从1开始计数
双端队列旋转演示图
(C++之两个普通队列和一个优先权队列)
#ifndef QUEUE_H_
#define QUEUE_H_
#include "Chain.h"
#include <cassert>
#include <cstddef>
#include <stdexcept>
//固定事务数的队列
//用数组实现
template <class Type>
class FixQueue {
public:
FixQueue( size_t sz );
virtual ~FixQueue();
bool EnQueue( const Type& item);
Type DeQueue();
Type GetFront();
void MakeEmpty() { m_ifront = m_irear = 0; }
bool IsEmpty() const { return m_ifront == m_irear; }
bool IsFull() const { return (m_irear+1)%m_uiMaxSize == m_ifront; }
size_t Length() const { return (m_irear+m_uiMaxSize-m_ifront)%m_uiMaxSize; }
private:
int m_irear, m_ifront;
Type* m_pElement;
size_t m_uiMaxSize;
};
//--------------------------------------
//FixQueue template implementation
//
template <class Type>
FixQueue<Type>::FixQueue( size_t sz = 15) : m_uiMaxSize(sz)
{
m_pElement = new Type[m_uiMaxSize];
assert( m_pElement != 0); //其实这样做没有作用
m_ifront = m_irear = 0;
}
template <class Type>
FixQueue<Type>::~FixQueue()
{
delete []m_pElement;
}
template <class Type>
bool FixQueue<Type>::EnQueue( const Type& item )
{
//队列不满则加入元素
if(IsFull()) return false;
m_irear = (m_irear+1) % m_uiMaxSize; //计算队尾值
m_pElement[m_irear] = item;
return true;
}
template <class Type>
Type FixQueue<Type>::DeQueue()
{
if(IsEmpty())
{
MakeEmpty();
throw std::out_of_range("Out Of bounds of Queue!/n");
}
else
{
m_ifront = (m_ifront+1) % m_uiMaxSize;
return m_pElement[m_ifront];
}
}
template <class Type>
Type FixQueue<Type>::GetFront()
{
//返回队列头元素的值
if(IsEmpty())
{
MakeEmpty();
throw std::out_of_range("Out Of bounds of Queue!/n");
}
else
{
return m_pElement[(m_ifront+1) % m_uiMaxSize];
}
}
//FixQueue Over!
//ChainQueue
//链式队列,虽然链式队列从抽象意义上来说"is a Chain"
//但是仔细分析,很容易发现链式队列只不过是能够在"链头删除元素","链尾添加元素"的普通链表
//更好的表示是: 链式队列"has a general Chain for specific use"
template <class Type>
class ChainQueue {
public:
ChainQueue();
virtual ~ChainQueue();
virtual void EnQueue( const Type& item);
virtual Type DeQueue();
Type GetFront();
void MakeEmpty();
bool IsEmpty() const;
size_t Length() const ;
private:
Chain<Type> chain;
};
template <class Type>
ChainQueue<Type>::ChainQueue() {}
template <class Type>
ChainQueue<Type>::~ChainQueue() {}
template <class Type>
void ChainQueue<Type>::EnQueue( const Type& item)
{
//新加元素
try
{
chain.Appen(item);
}
catch (...)
{ throw; }
}
template <class Type>
Type ChainQueue<Type>::DeQueue()
{
Type tmp;
try
{
chain.Delete(1,tmp);
}
catch(...)
{
throw;
}
return tmp;
}
template <class Type>
Type ChainQueue<Type>::GetFront()
{
Type tmp;
if(!chain.Find(1,tmp)) throw std::out_of_range("Out Of bounds of Queue!/n");
return tmp;
}
template <class Type>
void ChainQueue<Type>::MakeEmpty()
{
chain.Erase();
}
template <class Type>
bool ChainQueue<Type>::IsEmpty() const
{
return (chain.Length() == 0);
}
template <class Type>
size_t ChainQueue<Type>::Length() const
{
return (size_t)chain.Length();
}
//============================================================
//PRQueue 实现一个按优先权重操作的队列
//显然,无需重新实现完整的优先权队列
//优先权队列只不过是一个特殊的队列罢了,优先级队列插入元素方式不同,
//要overwrite EnQueue();
//这里采用继承链式队列(考虑到元素插入的效率因素,链表划算)
//一个更好的方法是利用交叉链表实现优先级队列,优先级别为行列表,同优先级的任务放到列链表中,这里只是重新实现按权重插入元素
//=============================================================
//定义一个带优先权的结构
template <class Type>
typedef struct PRItem
{
int priority; //优先权
Type item; //元
//只需要重载一个 <=就行了,这样刚好能够实现
//1:先按照优先级处理
//2:同优先级的FIFO方式处理
bool operator<=( const PRItem& item) {
return priority <= item.priority;
}
};
template <class Type>
class PRQueue : public ChainQueue< PRItem<Type> > //郁闷,模板中模板类型
{
public:
PRQueue();
~PRQueue();
void EnQueue( const PRItem<Type>& item) //overwrite
{
typedef PRItem<Type> PRITEM;
typename Chain<PRITEM>::iterator iter = Chain<PRITEM>::chain.begin();
int x=1;
//按优先权插入寻找插入位置
while(iter != Chain<PRITEM>::chain.end() && iter.current() <= item)
{
x++;
iter++;
}
Chain<PRITEM>::chain.Insert(x, item);
}
void EnQueue( const Type& item, int priority) //overload
{
PRItem<Type> tmp;
tmp.item = item;
tmp.priority = priority;
EnQueue(tmp);
}
};
#endif /*QUEUE_H_*/
标签:
原文地址:http://www.cnblogs.com/tangtang-123/p/4436882.html