相对于栈,队列(queue)是另外一种特殊的线性表。队列的逻辑设计是,删除运算限定在表的一端进行,插入运算则被限定在表的另一端进行。约定将允许插入的一端称为队尾(Rear),删除的那一端称为队首(Front)。这样的逻辑设计,就其实是现实生活里的排队嘛。因此,队列是先进先出表(First In Frist Out,FIFO)。
队列同样有顺式结构和链式结构(一种逻辑结构的两种物理结构)。顺式的长度必然受到限制,所以主要都是使用链式结构。队列的链式结构本质上是用·一个单链表来表示。但是,同上一节的,栈一样。因为top/front这一端是一直被取出来的,和链表的head地址不能变有冲突,所以top/front这一端其实一直都是设置在链表的第二个结点。
队列的分类或者注意点:
- 有(无)优先级队列
队列还分有,无优先级和有优先级(priority)两种。有优先级的,称为优先队列。优先队列的区别是:对每个进队的元素都规定有一个优先级,同时将队列分为若干个有各自优先级的子队列。当执行插入操作时,元素进入相应的优先级的子队列的队尾,而删除则是从优先级最高的一个子队列开始。
- 顺序队列的bug和弥补
对于顺序队列,因为设计的问题可能有bug:一开始front和rear是同一个地址嘛。进队rear后移(地址增大),出队front也后移(地址增大),那么划分的这一片物理区间,前面的地区其实就会因为front后移而变空了,,导致“虚溢出”。
对此,提出的两种解决方法是,
——平移元素,即是当一个元素出队时,将整个队列的元素都向前移动一个位置。但是效率太低,不适宜。
——将整个队列设计为循环队列(在物理结构上),这样子就可以处理了。不过要设置变量之类,判断到底是队列空了,还是队列满了(因为这个时候,rear的地址会等于front地址)。
以下提供的是自己的链式队列程序:
(其实理解了队列的逻辑结构后,写程序是很简单的)
链式队列的结构体:
typedef int elementype;
typedef struct node{
elementype data;
struct node * next;
}node;
typedef struct queuechain{
node * front;
node * rear;
elementype length;
} queuechain;
各个操作函数:
void insertNode(queuechain * QueueChain,elementype DatatoRear);
void getNode(queuechain * QueueChain,elementype * DatafromFront);
void printNode(queuechain * QueueChain);
void destroyQueueChain(queuechain * QueueChain);
进队函数:
void insertNode(queuechain * QueueChain,elementype DatatoRear)
{
node * tempnode = (node *)malloc(sizeof(node));
if(!tempnode){
printf("init node is falsed\n");
return;
}
tempnode->data = DatatoRear;
tempnode->next = NULL;
QueueChain->rear->next = tempnode;
QueueChain->rear = tempnode;
QueueChain->length++;
printf("insert %d to the rear\n",tempnode->data);
}
出队函数:
void getNode(queuechain * QueueChain,elementype * DatafromFront)
{
node * tempnode;
if(QueueChain->front == QueueChain->rear){
printf("the QueueChain is empty\n");
}
//由于链表的本身性质,头结点是不可能被删除,也就不能被作为真正意义上的front了
tempnode = QueueChain->front->next;
*DatafromFront = tempnode->data;
QueueChain->front->next = tempnode->next;
QueueChain->length--;
printf("get %d from the front\n",tempnode->data);
free(tempnode);
}
print函数
void printNode(queuechain * QueueChain)
{
node * tempnode;
int i = 1;
tempnode = QueueChain->front->next;
if(tempnode == NULL){
printf("the queuechain is empty\n");
return ;
}
while(tempnode->next != NULL){
printf("the data of the %d is %d\n",i++,tempnode->data);
tempnode = tempnode->next;
}
printf("the data of the %d is %d\n",i++,tempnode->data);
}
destroy函数:
void destroyQueueChain(queuechain * QueueChain)
{
while(QueueChain->front->next != NULL){
QueueChain->rear = QueueChain->front->next;
free(QueueChain->front);
QueueChain->front = QueueChain->rear;
}
//其实front这个还没有free,就是说,只剩下front这个点,才能给print函数,做一个判断
//free(QueueChain->front);
printf("destroy is finished\n");
}
全部程序:
#include<stdio.h>
#include<malloc.h>
/*****
功能设计、分part:
还是按照之前的,不做交互。
init那部分,在主函数那里做,不然总觉得有bug
(insert和get其实就已经是不止是读了,还是取出来的了)
先做的,init——insert——get—— print——length——clear
*****/
typedef int elementype;
typedef struct node{
elementype data;
struct node * next;
}node;
typedef struct queuechain{
node * front;
node * rear;
elementype length;
} queuechain;
void insertNode(queuechain * QueueChain,elementype DatatoRear);
void getNode(queuechain * QueueChain,elementype * DatafromFront);
void printNode(queuechain * QueueChain);
void destroyQueueChain(queuechain * QueueChain);
int main()
{
int DatafromFront = 0;
queuechain * QueueChain = (queuechain *)malloc(sizeof(queuechain));
if(QueueChain == NULL){
printf("init the queuechain is false\n");
return 0;
}
printf("init the queuechain is succeed\n");
QueueChain->front = (node *)malloc(sizeof(node));
if(QueueChain->front == NULL){
printf("init the queuechain front is false\n");
return 0;
}
printf("init the queuechain front is succeed\n");
QueueChain->rear = QueueChain->front;
QueueChain->length = 0;
QueueChain->front->next = NULL;
QueueChain->rear->data = 33;
insertNode(QueueChain, 23);
insertNode(QueueChain, 24);
insertNode(QueueChain, 25);
printNode(QueueChain);
getNode(QueueChain,&DatafromFront);
destroyQueueChain(QueueChain);
printNode(QueueChain);
return 0;
}
void insertNode(queuechain * QueueChain,elementype DatatoRear)
{
node * tempnode = (node *)malloc(sizeof(node));
if(!tempnode){
printf("init node is falsed\n");
return;
}
tempnode->data = DatatoRear;
tempnode->next = NULL;
QueueChain->rear->next = tempnode;
QueueChain->rear = tempnode;
QueueChain->length++;
printf("insert %d to the rear\n",tempnode->data);
}
void getNode(queuechain * QueueChain,elementype * DatafromFront)
{
node * tempnode;
if(QueueChain->front == QueueChain->rear){
printf("the QueueChain is empty\n");
}
//由于链表的本身性质,头结点是不可能被删除,也就不能被作为真正意义上的front了
tempnode = QueueChain->front->next;
*DatafromFront = tempnode->data;
QueueChain->front->next = tempnode->next;
QueueChain->length--;
printf("get %d from the front\n",tempnode->data);
free(tempnode);
}
void printNode(queuechain * QueueChain)
{
node * tempnode;
int i = 1;
tempnode = QueueChain->front->next;
if(tempnode == NULL){
printf("the queuechain is empty\n");
return ;
}
while(tempnode->next != NULL){
printf("the data of the %d is %d\n",i++,tempnode->data);
tempnode = tempnode->next;
}
printf("the data of the %d is %d\n",i++,tempnode->data);
}
void destroyQueueChain(queuechain * QueueChain)
{
while(QueueChain->front->next != NULL){
QueueChain->rear = QueueChain->front->next;
free(QueueChain->front);
QueueChain->front = QueueChain->rear;
}
//其实front这个还没有free,就是说,只剩下front这个点,才能给print函数,做一个判断
//free(QueueChain->front);
printf("destroy is finished\n");
}
附图·: