1. 队列
队列是限制在两端进行插入操作和删除操作的线性表。
允许进行存入操作的一端称为“队尾” 允许进行删除操作的一端称为“队头” 当线性表中没有元素时,称为“空队”。
特点 :先进先出(FIFO)。
2. 循环队列
规定:front指向队头元素的位置; rear指向队尾元素的下一个位置。
在队列操作过程中,为了提高效率,以调整指针代替队列元素的移动,并将数组作为循环队列的操作空间。
为区别空队和满队,满队元素个数比数组元素个数少一个。
3. 顺序队列
需要进行判满和判空。
sq->front = sq->rear = 0; // 空队列
(sq->rear + 1) % N == sq->front // 判断队满
结构体说明
typedef int data_t ; /定义队列中数据元素的数据类型/
#define N 64 /定义队列的容量/
typedef struct {
data_t data[N] ; /用数组作为队列的储存空间/
int front, rear ; /指示队头位置和队尾位置的指针/
} sequeue_t ; /顺序队列类型定义/
sequeue * queue_create(); // 创建
int enqueue(sequeue *sq,datatype value); // 入队
datatype dequeue(sequeue *sq); // 出队
int queue_empty(sequeue *sq); // 判读空队
int queue_full(sequeue *sq); // 判读队满
int queue_clear(sequeue *sq); // 清空队列
sequeue * queue_free(sequeue *sq); // 释放队列
实现框架
sequeue.h
typedef int datatype;
#define N 128
typedef struct{
datatype data[N];
int front;
int rear;
}sequeue;
sequeue * queue_create(); // 创建
int enqueue(sequeue *sq,datatype value); // 入队
datatype dequeue(sequeue *sq); // 出队
int queue_empty(sequeue *sq); // 判读空队
int queue_full(sequeue *sq); // 判读队满
int queue_clear(sequeue *sq); // 清空队列
sequeue * queue_free(sequeue *sq); // 释放队列
sequeue.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sequeue.h"
sequeue * queue_create()
{
sequeue *sq;
if((sq = (sequeue *)malloc(sizeof(sequeue))) == NULL){
printf("malloc failed\n");
return NULL;
}
memset(sq->data, 0 ,sizeof(sq->data));
// 这一步很关键
sq->front = sq->rear = 0; // 空队列
return sq;
}
int enqueue(sequeue *sq,datatype value)
{
if(sq == NULL){
printf("sq is NULL\n");
return -1;
}
if((sq->rear + 1) % N == sq->front){ //队满
printf("sequeue is full\n");
return -1;
}
sq->data[sq->rear] = value;
sq->rear = (sq->rear+1) % N;
return 0;
}
datatype dequeue(sequeue *sq)
{
if(sq == NULL){
printf("sq is NULL\n");
return -1;
}
datatype t;
t = sq->data[sq->front];
sq->front = (sq->front + 1) % N;
return t;
}
int queue_full(sequeue *sq)
{
if(sq == NULL){
printf("sq is NULL\n");
return -1;
}
if((sq->rear + 1 ) % N == sq->front){
return 1;
}else{
return 0;
}
}
int queue_clear(sequeue *sq)
{
if(sq == NULL){
printf("sq is NULL\n");
return -1;
}
sq->front = sq->rear = 0;
return 0;
}
sequeue *queue_free(sequeue *sq)
{
if(sq == NULL){
printf("sq is NULL\n");
return NULL;
}
free(sq);
//需要置空,不然成野指针
sq = NULL;
return NULL;
}
int queue_empty(sequeue *sq)
{
if(sq == NULL){
printf("sq is NULL\n");
return -1;
}
return (sq->front == sq->rear ? 1 : 0);
}
test.c
#include <stdio.h>
#include "sequeue.h"
int main(int argc, const char *argv[])
{
sequeue *sq;
sq = queue_create();
if(sq == NULL){
return -1;
}
enqueue(sq,10);
enqueue(sq,20);
enqueue(sq,30);
enqueue(sq,40);
enqueue(sq,50);
enqueue(sq,666);
while(!queue_empty(sq)){
printf("dequeue:%d\n",dequeue(sq));
}
queue_free(sq);
return 0;
}
4. 链式队列
插入操作在队尾进行,删除操作在队头进行,由队头指针和队尾指针控制队列的操作。
问题:链式队列有假溢出么?链式队列需要判空判满么?为什么?
答:
(1)没有假溢出。因为在进行队列的操作时,只能从队尾进行入队,队头进行出队。
(2)需要判空,因为链式队列可能没有元素。不需要判满,因为入队是从队尾实现,链式队列可以申请动态空间。
结构体说明:
typedef int datatype;
typedef struct node{
datatype data;
struct node * next;
}listnode,*linklist;
typedef struct{
linklist front;
linklist rear;
}linkqueue;
创建空队列 :
linkqueue_t *CreateQueue()
{
linkqueue_t *lq = (linkqueue_t *)malloc(sizeof(linkqueue_t));
lq->front = lq->rear = (linklist_t)malloc(sizeof(linknode_t));
lq->front->next = NULL ; /置空队/
return lq; /返回队列指针/
}
判断队列空 :
int EmptyQueue(linkqueue_t *lq) {
return ( lq->front = = lq->rear) ;
}
入队 :
void EnQueue (linkqueue_t *lq, data_t x)
{
加粗样式 lq->rear->next = (linklist_t)malloc(sizeof(linknode_t)) ;
lq->rear = lq->rear->next; /修改队尾指针/
lq->rear->data = x ; /新数据存入新节点/
lq->rear->next = NULL ; /新节点为队尾/
return;
}
出队
data_t DeQueue(linkqueue_t *lq)
{
data_t x;
linklist_t p; /定义一个指向队头结点的辅助指针/
p = lq->front->next ; /将它指向队头结点/
lq->front->next = p->next ; /*删除原先队头结点
x = p->data;
free§ ; /释放原队头结点/
if (lq->front->next == NULL) lq->rear = lq->front;
return x;
}
实现框架
linkqueue.h
typedef int datatype;
typedef struct node{
datatype data;
struct node * next;
}listnode,*linklist;
typedef struct{
linklist front;
linklist rear;
}linkqueue;
linkqueue * queue_create();
int enqueue(linkqueue *lq,datatype x);
datatype dequeue(linkqueue *lq);
int queue_empty(linkqueue *lq);
int queue_clear(linkqueue *lq);
linkqueue * queue_free(linkqueue *lq); //返回linkqueue * 目的是防止程序还进行其他队列操作
linkqueue.c
#include <stdio.h>
#include <stdlib.h>
#include "linkqueue.h"
linkqueue * queue_create()
{
linkqueue *lq;
if( (lq = (linkqueue *)malloc(sizeof(linkqueue))) == NULL){
printf("malloc linkqueue failed\n");
return NULL;
}
// 两次malloc不一样
lq->front = lq->rear = (linklist)malloc(sizeof(listnode));
if(lq->front == NULL){
printf("malloc node failed\n");
return NULL;
}
// 头节点
lq->front->data = 0;
lq->front->next = NULL;
return lq;
}
int enqueue(linkqueue *lq,datatype x)
{
linklist p;
if(lq == NULL){
printf("lq is NULL\n");
return -1;
}
if((p = (linklist)malloc(sizeof(listnode))) == NULL){
printf("malloc node failed\n");
return -1;
}
p->data = x;
p->next = NULL;
lq->rear->next = p;
lq->rear = p;
return 0;
}
datatype dequeue(linkqueue *lq)
{
linklist p;
if(lq == NULL){
printf("lq is NULL\n");
return -1;
}
p = lq->front;
lq->front = p->next;
free(p);
p = NULL;
return (lq->front->data);
}
int queue_empty(linkqueue *lq)
{
if(lq == NULL){
printf("lq is NULL\n");
return -1;
}
return (lq->front == lq->rear ? 1 : 0);
}
int queue_clear(linkqueue *lq)
{
linklist p;
if(lq == NULL){
printf("lq is NULL\n");
return -1;
}
while(lq->front->next){ //会剩最后一个没清空
p = lq->front;
lq->front = p->next;
printf("clear free:%d\n",p->data);
free(p);
p = NULL;
}
return 0;
}
linkqueue * queue_free(linkqueue *lq)
{
linklist p;
if(lq == NULL){
printf("lq is NULL\n");
return NULL;
}
while(lq->front){
p = lq->front;
lq->front = p->next;
printf("free:%d\n",p->data);
free(p);
}
free(lq);
lq = NULL;
return NULL;
}
test.c
#include <stdio.h>
#include "linkqueue.h"
int main(int argc, const char *argv[])
{
linkqueue *lq;
lq = queue_create();
if (lq == NULL)
return -1;
enqueue(lq, 10);
enqueue(lq, 20);
enqueue(lq, 30);
enqueue(lq, 40);
//while (!queue_free_empty(lq)) {
printf("dequeue:%d\n", dequeue(lq));
}
queue_clear(lq);
lq = queue_free(lq);
enqueue(lq, 50);
return 0;
}