队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表
进行插入操作的一端称为队尾(入队列)
进行删除操作的一端称为队头(出队列)
队列具有先进先出(FIFO)的特性
队列分类:
1.顺序队列
元素删除:
方式1:队头不动,出队列时队头后的所有元素向前移动
缺陷:操作时如果出队列比较多,要搬移大量元素
方式2:队头移动,出队列时队头向后移动一个位置
缺陷:容易造成队列假溢出假溢出:顺序队列因多次入队列和出队列操作后出现的尚有存储空间但不能再进行入队列操作的溢出
真溢出:顺序队列最大存储空间已经存满而又要求进行入队列操作所引起的溢出
2.循环队列(解决了假溢出问题)
常考面试题:循环队列如何判断队列空和满呢?
a.少用一个存储单元
b.设置一个标记位
c.设置一个计数器
3.链式队列(类似于链表)
4.优先级队列(带有优先级的队列称为优先级队列 )
队列具有先进先出的特性,即最先进入队列的元素将被最先出队列,有时也需要把进入队列中的元素分优先级(比如线程调度),出队列时首先选择优先级最高的元素出队列(优先级高先被服务VIP),对于优先级相同的元素则按照先进先出的原则出队列,即优先级队列的出队列操作不是直接将对头元素出队列,而是把队列中优先级最高的元素出队列。
队列的应用:
生产者消费者模型
消息队列
排队现象
网络数据传输
大家熟知的linux管道
/****************顺序队列******************/
#include <stdio.h>
#include <assert.h>
#include <sydlib.h>
#define MAX_SIZE 10
typedef int DataType;
typedef struct Queue
{
DataType _array[MAX_SIZE];
int _front;
int _back;
int _count;
}Queue;
void QueueInit(Queue* q);
void QueuePush(Queue* q,DataType data);
void QueuePop(Queue* q);
int QueueEmpty(Queue* q);
int QueueSize(Queue* q);
DataType QueueFront(Queue* q);
DataType QueueBack(Queue* q);
void QueueInit(Queue* q)
{
assert(q);
q->_front = q->_back = 0;
q->_count = 0;
}
void QueuePush(Queue* q, DataType data)
{
assert(q);
if (q->_count == MAX_SIZE)
return;
q->_array[q->_back++] = data;
if (q->_back == MAX_SIZE)
q->_back = 0;
q->_count++;
}
void QueuePop(Queue* q)
{
assert(q);
if (QueueEmpty(q))
return;
++(q->_front);
if (q->_front == MAX_SIZE)
q->_front = 0;
q->_count--;
}
int QueueEmpty(Queue* q)
{
assert(q);
return 0 == q->_count;
}
int QueueSize(Queue* q)
{
return q->_count;
}
DataType QueueFront(Queue* q)
{
return q->_array[q->_front];
}
DataType QueueBack(Queue* q)
{
if (0 != q->_back)
return q->_array[q->_back - 1];
else
{
return q->_array[MAX_SIZE - 1];
}
}
void TestQueue()
{
Queue q;
QueueInit(&q);
QueuePush(&q, 1);
QueuePush(&q, 2);
QueuePush(&q, 3);
QueuePush(&q, 4);
QueuePush(&q, 5);
QueuePush(&q, 6);
QueuePush(&q, 7);
QueuePush(&q, 8);
QueuePush(&q, 9);
QueuePush(&q, 10);
printf("size = %d\n", QueueSize(&q));
printf("front = %d\n", QueueFront(&q));
printf("back = %d\n", QueueBack(&q));
QueuePop(&q);
QueuePop(&q);
QueuePop(&q);
printf("size = %d\n", QueueSize(&q));
printf("front = %d\n", QueueFront(&q));
printf("back = %d\n", QueueBack(&q));
}
int main()
{
TestQueue();
return 0;
}
/******************链式队列*******************/
#include <stdio.h>
#include <malloc.h>
#include <assert.h>
#include <stdlib.h>
typedef int DataType;
typedef struct Node
{
struct Node* _pNext;
DataType _data;
}Node ,*PNode;
typedef struct Queue
{
PNode _pHead;
PNode _pTail;
}Queue;
void QueueInit(Queue* q);
void QueuePush(Queue* q, DataType data);
void QueuePop(Queue* q);
int QueueEmpty(Queue* q);
int QueueSize(Queue* q);
PNode QueueFront(Queue* q);
PNode QueueBack(Queue* q);
PNode BuyNode(DataType data);
void QueueDestroy(Queue* q);
void QueueInit(Queue* q)
{
assert(q);
q->_pHead = NULL;
q->_pTail = NULL;
}
void QueuePush(Queue* q, DataType data)
{
assert(q);
if(NULL == q->_pHead)
{
q->_pHead = q->_pTail = BuyNode(data);
}
else
{
q->_pTail->_pNext = BuyNode(data);
q->_pTail = q->_pTail->_pNext;
}
}
PNode BuyNode(DataType data)
{
PNode pNewNode = (PNode)malloc(sizeof(Node));
assert(pNewNode);
pNewNode->_data = data;
pNewNode->_pNext = NULL;
return pNewNode;
}
void QueuePop(Queue* q)
{
assert(q);
if (NULL == q->_pHead)
{
return;
}
else if (q->_pHead == q->_pTail)
{
free(q->_pHead);
q->_pHead = q->_pTail = NULL;
}
else
{
//PNode pPreTail = q->_pHead;
//while (pPreTail->_pNext != q->_pTail)
//{
// pPreTail = pPreTail->_pNext;
//}
//free(q->_pTail);
//q->_pTail = pPreTail;
PNode pDel = q->_pHead;
q->_pHead = pDel->_pNext;;
free(pDel);
}
}
int QueueEmpty(Queue* q)
{
assert(q);
if (NULL == q->_pHead)
return 1;
return 0;
}
int QueueSize(Queue* q)
{
assert(q);
int count = 0;
PNode pCur;
pCur = q->_pHead;
while (pCur)
{
count++;
pCur = pCur->_pNext;
}
return count;
}
PNode QueueFront(Queue* q)
{
assert(q && q->_pHead);
return q->_pHead;
}
PNode QueueBack(Queue* q)
{
assert(q && q->_pHead);
return q->_pTail;
}
void QueueDestroy(Queue* q)
{
PNode pCur = q->_pHead;
while (pCur)
{
q->_pHead = pCur->_pNext;
free(pCur);
pCur = q->_pHead;
}
q->_pTail == NULL;
}
void TestQueue()
{
Queue q;
QueueInit(&q);
QueuePush(&q, 1);
printf("size = %d\n", QueueSize(&q));
printf("front = %d\n", QueueFront(&q));
printf("back = %d\n", QueueBack(&q));
QueuePush(&q, 2);
QueuePush(&q, 3);
QueuePush(&q, 4);
printf("size = %d\n", QueueSize(&q));
printf("front = %d\n", QueueFront(&q));
printf("back = %d\n", QueueBack(&q));
QueuePop(&q);
QueuePop(&q);
QueuePop(&q);
printf("size = %d\n", QueueSize(&q));
printf("front = %d\n", QueueFront(&q));
printf("back = %d\n", QueueBack(&q));
QueueDestroy(&q);
}
int main()
{
TestQueue();
return 0;
}
带头节点的双向链表:
https://blog.csdn.net/Romantic_C/article/details/79991268
带头节点的单链表:
https://blog.csdn.net/Romantic_C/article/details/79919836
链表面试题:
https://blog.csdn.net/Romantic_C/article/details/81395660
栈的基本操作:
https://blog.csdn.net/Romantic_C/article/details/81395874