目录
1 队列
1.1 队列的概念
像栈一样,队列也是一种线性表。它允许在表的一端插入数据,在另一端删除元素。
插入元素的这一端称之为队尾。删除元素的这一端我们称之为队首。
队列的特性:
- 在队尾插入元素,在队首删除元素。
- 先进先出(排队一样)
1.2 队列的基本操作
InitQueue(&Q):初始化队列,构造一个空队列Q。
DestroyQueue(&Q):销毁队列。销毁并释放队列Q所占用的内存空间。
EnQueue(&Q,x):入队,若队列Q未满,将x加入,使之成为新的队尾。
DeQueue(&Q,&x):出队,若队列Q非空,删除队头元素,并用x返回。
GetHead(Q,&x):读队头元素,若队列Q非空,则将队头元素赋值给x。 其他常用操作:
QueueEmpty(Q):判队列空,若队列Q为空返回true,否则返回false。
2.循环队列
2.1 循环队列概念
设立两个指针:
一个队首指针front ,指向队首元素
一个队尾指针rear ,指向队尾元素的后一个位置(下一个应该插入的位置)·
-
注意事项:
1.入队可能会越界?
如果是在普通的队列中,那么插入元素,直接将tail + 1即可,但是可能会出现“假溢出现象”,即队尾满了,队头有空却无法插入,所以采用循环队列。可是在长度为n的循环队列中,元素插入的位置可能是原来队首的位置,这样如果直接用tail + 1就会造成越界。所以我们计算数组下标的时候要进行取模。使用( tail + 1 ) % n。同理,删除元素也是类似。
2.如何判断队列是否为空,队列是否为满呢?
从上面的图可以看出当tail == head的时候,这个是否队列是即可以为空,又可以为满。那么我们不妨将队列最后一个元素的位置空出来,少用一个存储空间。
这样的话当tail == head的时候,队列为空。当队列的tail + 1 == head,就认为队列已经满了,因为是循环队列,所以计算tail + 1 == head应该算上偏移量即 ( tail + 1 ) % n = head % n。
2.2 循环队列基本操作
-
2.2.1 定义循环队列
#define MaxSize 100 //最大队列长度 typedef int ElemType;//ElemType根据实际情况而定,这里假设为int typedef struct { ElemType *base; //初始化动态分配空间 int front; int rear; } SqQueue;
-
2.2.2 初始化
bool InitQueue(SqQueue &Q) { //构造一个空队列 Q.base=(ElemType *)malloc(MaxSize * sizeof(ElemType)); if (! Q.base) return false; Q.front=Q.rear=0; return true; } //InitQueue
-
2.2.3 判空
bool EmptyQueue(SqQueue Q)//判队空 { if(Q.front==Q.rear) return true; else return false; }
-
2.2.4 求循环队列的长度
int QueueLength(SqQueue &Q) { return (Q.rear+MaxSize-Q.front)%MaxSize; }
-
2.2.5 入队
bool EnQueue(SqQueue &Q,ElemType e) { //插入元素e为Q的新的队尾元素 if ((Q.rear+1)%MaxSize==Q.front)//判断队列有没有满 return false; Q.base[Q.rear]=e; Q.rear=(Q.rear+1)%MaxSize; }
-
2.2.6 出队
bool DeQueue(SqQueue &Q,ElemType &e) {// 删除Q的队头元素,并用e返回其值 if(Q.front==Q.rear) return false; e=Q.base[Q.front]; Q.front=(Q.front+1) % MaxSize; }
-
2.2.7 取队头元素
bool GetHead(SqQueue Q,ElemType &e) { if(Q.rear==Q.front) return false; e=Q.base[Q.front]; return true; }
2.3 其他建立方法
2.3.1 不浪费队列最后一个存储空间
队列元素个数=(rear+MaxSize-front+1)%MaxSize
2.3.2 队尾指针指向队尾元素
初始化时rear=MaxSize-1;
若牺牲队列最后一个存储空间:
- 判空:(Q.rear+1)%MaxSize==Q.front
- 判满:(Q.rear+2)%MaxSize==Q.front
若不浪费队列最后一个存储空间,增加辅助变量判断是满是空,同上
3 链队列
3.1 链队列概念
队列的链式存储结构,其实就是线性表的单链表
只不过它只能尾进头出而已,我们把它简称为链队列
注意队列next指针的指向,与链栈不同:
如果插入一个元素,栈末尾的next指针是指向前一个已经在栈中的元素的
而队列则是,插入一个元素,其next指针是往外指,指向空。
同样分为带头结点和不带头结点:
带头结点:
- 队头指针指向链队列的头结点(链队列front没有值,而循环队列的front是有值的)
- 队尾指针指向队尾结点
- 当队列为空时,front和rear都指向头结点。
不带头结点:
- 队头指针指向队首结点
- 队尾指针指向队尾结点
- 当队列为空时,front和rear都指向NULL。
链队列示意图:
3.2 链队列的基本操作
-
3.2.1 链队列定义
///队列 typedef struct QNode { ElemType data; struct QNode *next; }QNode,*QueuePtr; typedef struct { QueuePtr Front;///队头指针 QueuePtr Rear;///队尾指针 }LinkQueue;
-
3.2.2 初始化
//1.带头结点 bool InitQueue(LinkQueue &Q) { Q.Front=Q.Rear=(QNode *)malloc(sizeof(QNode));///生成新结点作为头结点,队头和队尾指针指向此结点 if(!Q.Front) return false; Q.Front->next=NULL;///头结点的指针域置空 return true; } //2.不带头结点 bool InitQueue(LinkQueue &Q) { Q.Front=NULL;//指针域置空 Q.Rear=NULL; return true; }
-
3.2.3 判空
//1.带头结点 bool QueueEmpty(LinkQueue Q) { if(Q.Front==Q.Rear) return true; else return false; } //2.不带头结点 bool QueueEmpty(LinkQueue Q) { if(Q.Front==NULL) return true; else return false; }
-
3.2.4 入队
//1.带头结点 void EnQueue(LinkQueue &Q,ElemType e) { QNode *s=(QNode *)malloc(sizeof(QNode)); s->data=e; s->next=NULL; Q.Rear->next=s;///将新结点插入到队尾 Q.Rear=s;///修改队尾指针 } //2.不带头结点 void EnQueue(LinkQueue &Q,ElemType e) { QNode *s=(QNode *)malloc(sizeof(QNode)); s->data=e; s->next=NULL; if(Q.Rear==NULL)//在空队列插入第一个元素 { Q.Front=s; Q.Rear=s; } else { Q.Rear->next=s;///将新结点插入到队尾 Q.Rear=s;///修改队尾指针 } }
-
3.2.5 出队
//1.带头结点 bool DeQueue(LinkQueue &Q,ElemType &e) { if(Q.Front==Q.Rear) return false; QNode *p=Q.Front->next; //p指向队头 e=p->data;//回收 Q.Front->next=p->next; if(Q.Rear==p) Q.Rear=Q.Front; //最后一个元素被删,队尾指针指向头结点 free(p); return true; } //2.不带头结点 bool DeQueue(LinkQueue &Q,ElemType &e) { if(Q.Front==NULL) return false; QNode *p=Q.Front; //p指向队头 e=p->data;//回收 Q.Front=p->next; if(Q.Rear==p) { Q.Front=NULL; Q.Rear=NULL; //最后一个元素被删,队头队尾指针指向NULL } free(p); return true; }
-
3.2.6 取队头元素
//1.带头结点 bool GetHead(LinkQueue Q,ElemType &e) { if(Q.Rear==Q.Front) return false; e=Q.front->next->data; return true; } //2.不带头结点 bool GetHead(LinkQueue Q,ElemType &e) { if(Q.Front==NULL) return false; e=Q.front->data; return true; }