您的位置:首页 > 理论基础 > 数据结构算法

数据结构之队列

2016-10-10 21:26 204 查看
队列是另一种顺序存取的线性表,他不同于栈,是先进先出的,就像排队一样,先来的先走。他的插入是在队列的对尾实现,删除是在对头实现

队列的存储表示有两种,基于数组的和基于链表的

顺序队列

基于数组表示的是顺序队列,用elements[maxSize]来表示队列元素的存储结构,用front和rear指示队头和队尾指针

队列建立时要初始化,即front=rear=0,每当新元素加进来就填到rear指示的位置,再让rear+1,实际上rear指的是队尾元素的下一个空元素的位置,不是队尾元素,而front指向的是队头元素,所以要退出队头元素要把front的值记录下来在使front+1,这样就指到了下一个元素那了

为了充分利用空间,防止假溢出,可以用循环队列,可以用取余运算来实现,当front进一时:front = (front +1)%maxSize; 当rear进一时 :rear = (rear+1)%maxSize; 

这样的话判断队空和队满都是front==rear,不好判断了,所以可以当front= =rear时是队空,当(rear+1)%maxSize==front,当队尾元素再进一时到达队头说明队满了

还可以通过设置一个标志tag来表示队空和队满,tag=0,队空,tag=1,队满

bool enQueue(const T& x){
if(IsFull == true) return fasle;	//插入先判断队满情况
elements[rear] = x;
rear = (rear+1)%maxSize;
return true;
}
bool deQueue(T& x){
if(IsEmpty == true) return false;	//删除先判断队空
x = elements[front];
front = (front+1)%maxSize;
return true;
}


链式队列

链式队列是基于链表表示的队列,队头指针指向第一个节点,队尾指针指向最后一个节点,如果使用多个队列或者多个栈的情况下,最好是使用链式队列

 

bool enQueue(const T& x){
if(front == null){
front = rear = new LinkNode<T>(x);	//空队列时,插入的结点是第一个也是最后一个
if(front == null) return false;
}else{
rear->link = new LinkNode<T>(x);
if(rear->link == null) renturn false;
rear = rear->link;
}
return true;
}
bool deQueue(T& x){
if(IsEmpty == true) return false;	//删除先判断队空
LinkNode<T> *p = front;
x = front->data;
front = front->link;
delete p;
return true;
}


优先队列

优先队列指的是每次取出来的是优先级最高的而不是按照入队的次序取得,数字越小,优先权越高,在最小优先级队列中查找是找优先级最小的元素,删除也是删除最小的元素,在最大优先级队列中,查找和删除都是优先级最大的操作

</pre><pre name="code" class="plain">bool Insert(const T& x){
if(count == maxSize) renturn false;
pqelements[count++] = x;
adjust();	//按照优先级进行调整
return true;
}

bool RemoveMin(T& x){
if(count == 0) return false;
x = pqelements[0];
for(int i=1;i<count;i++){
pqelements[i-1] = pqelements[i];
}
count--;
return true;
}

void Adjust(){	//将队尾元素按照优先级大小进行调整,使其从小到大有序
T temp = pqlements[count-1];//队尾元素
for(int j=count-2;j>=0;j--){
if(pqelements[j]<= temp) break;	//有更小的跳出
else pqelements[j+1] = pqelements[j];
}
pqelements[j+1] = temp;
}


在adjust()函数中,前面都是排好序的,新插进来的队尾元素和前面一个一个比,要是有更小的直接跳出,则j+1的位置就是队尾元素的位置,要是元素比队尾元素大的话,就向后挪一个,直到有比他小的出现,空出来j+1的位置放队尾元素

双端队列(Deque)

双端队列是可以在两端进行插入和删除操作的

双端队列的数组表示继承了Deque和SeqQueue,别的还是一样,只是新添了getTail()获得队尾元素,EnQueueHead()在 队头插入,DeQueueTail()在队尾删除三个函数

getTail(T& x)const{
if(front == rear) renturn false;
x = elements[(rear-1+maxSize)%maxSize];<span style="white-space:pre">	</span>//rear前一个就是最后队尾元素位置
return true;
}

bool EnQueueHead(const T& x){
if((rear+1)%maxSize == front) renturn false;
front = (front-1)%maxSzie;	//往前挪一个位置
elements[front] = x;
return true;
}

bool DeQueueTail(T& x){
if(front == rear) return false;
rear = (rear-1)%maxSize;
x = elements[rear];
return true;
}


双端队列的链表表示

getTail(T& x)const{
if(front == null) renturn false;
x = rear->data;
return true;
}

bool EnQueueHead(const T& x){
LinkNode<T> *p = new LinkNode<T>(x);
if(p == null) renturn false;
p->link = front;
front = p;
return true;
}

bool DeQueueTail(T& x){
if(front == null) return false;
LinkNode<T> *p = front;
while(p->link != rear) p = p->link;
x = rear->data;
delete rear;
p->link = null;
rear = p;
return true;

双端队列有输入受限和输出受限,输入受限指只能在一端输入,但是可以两端输出,同理输出受限也是一样,两端输入尾端输出

在双端循环队列插入或者删除一个元素时,要考虑输入输出的方向,如果不是受限队列,两端都可以输入输出的话,end1表示顺时针进队,end2表示逆时针进队,可以把end1这端当做是单端队列的队头部分,end2这端当做是队尾部分,当然end1和end2还是指向两端队尾的位置,在end1插入时要指针加一在插入,end1指向实际队尾的位置,end2要先插入在减一,end2指向实际队尾的下一位置,删除时,end1要先获值在减一,end2要减一在获值,这是因为他两不同的位置含义造成的,一定要注意加减和获值插入的顺序
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息