队列 queue
1)队列
是一种 "先进先出 FIFO" "后进后出"的线性表
它只允许 在表的一端进行插入操作
在表的另外一端进行删除操作
队尾 rear : 允许插入元素 入队
队首 front : 允许删除元素 出队
2)队列的基本操作
InitQueue() 初始化一个队列
EnQueue() 入队
DeQueue() 出队
QueueLength() 队列的长度(元素的个数)
GetHead() 获取队首元素,但是不出队
IsEmpty() 判断队列是否为空
ClearQueue() 清空队列
DestroyQueue() 销毁队列
3)队列的实现
(3.1)顺序队列
用一组地址连续的空间 依次存储队列的每一个元素 "数组"
"循环队列"
#define MAX_LEN 10 //队列的最大的容量
typedef int ElemType; //数据的类型typedef struct CircleQueue //循环队列
{
ElemType data[MAX_LEN];
int front; //保存队首元素的下标
int rear; //保存队尾元素的下标
int num; //保存队列中元素的个数
} CircleQueue ;
练习:
1)初始化一个循环队列
CircleQueue.c / CircleQueue.h
//初始化一个循环队列
CircleQueue * InitQueue()
{
//创建一个循环队列,并初始化
CircleQueue * q = (CircleQueue *)malloc( sizeof(CircleQueue) );
q->front = -1;
q->rear = -1;
q->num = 0;
return q;
}
2)判断队列是否为空
返回值:
1 为空
0 不为空
int IsEmpty( CircleQueue * q )
{
//队列不存在 || 队列的元素个数为0
if( q == NULL || q->num == 0 )
{
return 1;
}
return 0;
}
3)获取队列的长度(元素个数)
int QueueLength( CircleQueue * q )
{
if( q == NULL )
{
return 0;
}
return q->num;
}
4)清空队列
void ClearQueue( CircleQueue * q )
{
if( q )
{
q->front = -1;
q->rear = -1;
q->num = 0;
}
}
5)销毁队列
void DestroyQueue( CircleQueue * q )
{
if( q )
{
q->front = -1;
q->rear = -1;
q->num = 0;
free( q );
}
}
6)入队
返回值:
1 入队成功
0 入队失败
int EnQueue( CircleQueue *q, ElemType d )
{
//不能入队的情况: 队列不存在 || 队列满了
if( q == NULL || q->num == MAX_LEN )
{
return 0;
}
//入队,只允许在队尾进行入队操作
if( q->num == 0 )
{
q->front = ( q->front + 1 ) % MAX_LEN;
q->rear = ( q->rear + 1 ) % MAX_LEN;
q->data[ q->rear ] = d;
}
else
{
q->rear = ( q->rear + 1 ) % MAX_LEN;
q->data[ q->rear ] = d;
}
q->num ++;
return 1;
}
7)出队
返回值:
1 出队成功
0 出队失败
int DeQueue( CircleQueue *q, ElemType *d )
{
//不能出队的情况: 队列不存在 || 队列为空
if( q == NULL || q->num == 0 )
{
return 0;
}
//出队,只允许在队首进行出队操作
*d = q->data[ q->front ];
q->num --;
if( q->num == 0 )
{
q->front = ( q->front + 1 ) % MAX_LEN;
q->rear = ( q->rear + 1 ) % MAX_LEN;
//q->front = -1;
//q->rear = -1;
}
else
{
q->front = ( q->front + 1 ) % MAX_LEN;
}
return 1;
}
8)获取队首元素,但是不出队 (队首下标不变)
返回值:
1 获取成功
0 获取失败
int GetHead( CircleQueue *q, ElemType *d )
{
//不能获取的情况: 队列不存在 || 队列为空
if( q == NULL || q->num == 0 )
{
return 0;
}
//获取队首元素的值,下标保持不变
*d = q->data[ q->front ];
return 1;
}
(3.2)链式队列
"带头结点的单向链表"
typedef int ElemType; //数据元素中 数据的类型
typedef struct node //数据元素的类型
{
ElemType data; //数据域 --> 存储数据
struct node * next; //指针域 --> 保存逻辑上的关系(下一个)
} Node;//队列的头结点的类型
typedef struct LinkQueue //链式队列
{
Node * front; //指向队首元素 first
Node * rear; //指向队尾元素 last
int num; //保存队列的数据元素的个数
//...
} LinkQueue ;
基本操作: 同上
练习:
LinkQueue.c / LinkQueue.h
1)初始化一个链式队列
LinkQueue * InitQueue()
{
//创建队列的头结点,并初始化
LinkQueue *q = (LinkQueue *)malloc( sizeof(LinkQueue) );
q->front = NULL;
q->rear = NULL;
q->num = 0;
return q;
}
2)判断队列是否为空
int IsEmpty( LinkQueue * q )
{
//队列不存在 || 队列的元素个数为0
if( q == NULL || q->num == 0 )
{
return 1;
}
return 0;
}
3)获取队列的长度
int QueueLength( LinkQueue * q )
{
if( q == NULL )
{
return 0;
}
return q->num;
}
4)清空队列
void ClearQueue( LinkQueue * q )
{
//队列不存在 || 队列的元素个数为0
if( q == NULL || q->num == 0 )
{
return ;
}
//遍历,删除每一个数据节点 (只允许在队首进行出队操作-->删除队首节点)
Node * p = q->front; //遍历指针
while( p )
{
q->front = q->front->next;
p->next = NULL;
free( p );
p = q->front;
}
q->rear = NULL;
q->num = 0;
}
5)销毁队列
void DestroyQueue( LinkQueue * q )
{
//队列不存在
if( q == NULL )
{
return ;
}
//遍历,删除每一个数据节点 (只允许在队首进行出队操作-->删除队首节点)
ClearQueue( q );
//释放队列的头结点
free( q );
}
6)入队
返回值:
1 入队成功
0 入队失败
int EnQueue( LinkQueue *q, ElemType d )
{
//不能入队的情况: 队列不存在
if( q == NULL )
{
return 0;
}
//创建一个新的数据节点空间, 并初始化
Node * pnew = (Node *)malloc( sizeof(Node) );
pnew->data = d;
pnew->next = NULL;
//入队,只允许在队尾进行入队操作 --> 尾插法
if( q->num == 0 ) //从无到有
{
q->front = pnew;
q->rear = pnew;
}
else //从少到多
{
//尾插法
q->rear->next = pnew;
q->rear = pnew;
}
q->num ++;
return 1;
}
7)出队
返回值:
1 出队成功
0 出队失败
int DeQueue( LinkQueue *q, ElemType *d )
{
//不能出队的情况: 队列不存在 || 队列为空
if( q == NULL || q->num == 0 )
{
return 0;
}
//出队,只允许在队首进行出队操作
//先获取队首元素的值
*d = q->front->data;
//再出队(删除队首节点)
Node * p = q->front; //指向要删除的这个队首节点
q->front = q->front->next;
p->next = NULL;
free( p );
q->num --;
if( q->num == 0 ) //仅剩的一个节点也被删除了,那么队尾rear也要被置NULL
{
q->rear = NULL;
}
return 1;
}
8)获取队首元素,但是不出队 (队首下标不变)
返回值:
1 获取成功
0 获取失败
int GetHead( LinkQueue *q, ElemType *d )
{
//不能获取的情况: 队列不存在 || 队列为空
if( q == NULL || q->num == 0 )
{
return 0;
}
//获取队首元素的值,但是不出队
*d = q->front->data;
return 1;
}