一、队列
1、队列原理
队列 是限制在两端 进行插入操作 和删除操作 的线性表
允许进行存入操作 的一端称为“队尾 ”
允许进行删除操作 的一端称为“队头 ”
当线性表中没有元素 时,称为“空队 ”
特点 :先进先出(FIFO )
2、队列演示
二、顺序队列
>1、顺序队列原理
规定:
front指向队头元素的位置; rear指向队尾元素的下一个位置。
在队列操作过程中,为了提高效率,以调整指针代替队列元素的移动,并将数组 作为循环队列 的操作空间。 为区别空队 和满队 ,满队元素个数比数组元素个数少一个。
因此顺序队列 的结构体 定义为:
#define DEBUG 1
typedef int data_t ;
#define N 64
typedef struct {
data_t data[N] ;
int front, rear ;
} s_queue,*squeue ;
>2、顺序队列的创建
squeue squeue_create()
{
squeue queue = (squeue)malloc(sizeof(s_queue));
if(queue == NULL)
{
#if DEBUG
printf("squeue create error!\n");
#endif
return 0;
}
memset(queue->data,0,sizeof(queue->data));
queue->front = queue->rear =0;
return queue;
}
>3、顺序队列的入队
int squeue_enter(squeue queue, data_t value)
{
if(queue == NULL)
{
#if DEBUG
printf("squeue create error!\n");
#endif
return 0;
}
if((queue->rear+1)%N == queue->front)
{
#if DEBUG
printf("squeue already full!\n");
#endif
return 0;
}
queue->data[queue->rear] = value;
queue->rear = (queue->rear+1)%N;
return 1;
}
>4、顺序队列的出队
int squeue_out(squeue queue)
{
data_t value;
if(queue == NULL)
{
#if DEBUG
printf("squeue create error!\n");
#endif
return 0;
}
if(queue->front == queue->rear)
{
#if DEBUG
printf("squeue is empty!\n");
#endif
return 0;
}
value = queue->data[queue->front];
queue->data[queue->front] = 0;
queue->front = (queue->front+1)%N;
return value;
}
>5、顺序队列的释放
int squeue_free(squeue queue)
{
if(queue == NULL)
{
#if DEBUG
printf("squeue create error!\n");
#endif
return 0;
}
free(queue);
return 1;
}
>6、顺序队列的清空
int squeue_clear(squeue queue)
{
if(queue == NULL)
{
#if DEBUG
printf("squeue create error!\n");
#endif
return 0;
}
memset(queue->data,0,sizeof(queue->data));
queue->front = queue->rear = 0;
return 1;
}
>7、队列是否为空的判断
int squeue_empty(squeue queue)
{
if(queue == NULL)
{
#if DEBUG
printf("squeue create error!\n");
#endif
return -1;
}
return queue->front == queue->rear? 1:0;
}
>8、队列是否为满的判断
int squeue_full(squeue queue)
{
if(queue == NULL)
{
#if DEBUG
printf("squeue create error!\n");
#endif
return -1;
}
if((queue->rear+1)%N == queue->front)
return 1;
else
return 0;
}
三、链表队列
>1、链表队列的原理
插入操作 在队尾 进行,删除操作 在队头 进行,由队头指针和队尾指针控制队列的操作。
因此链表队列 的结构体 定义为:
#define DEBUG 1
typedef int data_t;
typedef struct node
{
data_t data;
struct node *next;
}linklist_t,*linklist;
typedef struct
{
linklist front,rear;
}listqueue,*linkqueue;
>2、链表队列的操作演示
>3、链表队列的创建
linkqueue linkqueue_create()
{
linkqueue lq = (linkqueue)malloc(sizeof(listqueue));
if(lq == NULL)
{
#if DEBUG
printf("linkqueue create error!\n");
#endif
return 0;
}
lq->front = lq->rear = (linklist)malloc(sizeof(linklist_t));
if(lq->front == NULL || lq->rear == NULL)
{
#if DEBUG
printf("linkqueue create error!\n");
#endif
return 0;
}
lq->front->data = 0;
lq->front->next = NULL;
return lq;
}
>4、链表队列的入队
int linkqueue_enter(linkqueue lq, data_t value)
{
linklist node = (linklist)malloc(sizeof(linklist_t));
if(lq == NULL)
{
#if DEBUG
printf("lq is NULL!\n");
#endif
return 0;
}
if(node == NULL)
{
#if DEBUG
printf("node create error!\n");
#endif
return 0;
}
lq->rear->next = node;
lq->rear = node;
node->data = value;
node->next = NULL;
return 1;
}
>5、链表队列的出队
data_t linkqueue_out(linkqueue lq)
{
linklist node;
if(lq == NULL)
{
#if DEBUG
printf("lq is NULL!\n");
#endif
return 0;
}
if(lq->front == lq->rear)
{
#if DEBUG
printf("lq is empty!\n");
#endif
return 0;
}
node = lq->front;
lq->front = node->next;
free(node);
return lq->front->data;
}
>6、链表队列的释放
int linkqueue_free(linkqueue lq)
{
linklist node;
if(lq == NULL)
{
#if DEBUG
printf("lq is NULL!\n");
#endif
return 0;
}
while(lq->front)
{
node = lq->front;
lq->front = node->next;
free(node);
}
free(lq);
return 1;
}
>7、链表队列的清空
int linkqueue_clear(linkqueue lq)
{
linklist node;
if(lq == NULL)
{
#if DEBUG
printf("lq is NULL!\n");
#endif
return 0;
}
while(lq->front != lq->rear)
{
node = lq->front;
lq->front = node->next;
free(node);
}
return 1;
}
>8、判断链表队列是否为空
int linkqueue_empty(linkqueue lq)
{
if(lq == NULL)
{
#if DEBUG
printf("lq is NULL!\n");
#endif
return -1;
}
return lq->front == lq->rear? 1:0;
}
四、链表的应用–球钟问题
1、球钟简介
球 钟是一个利用球的移动 来记录时间 的简单装置
它有三个 可以容纳若干个球的指示器:分钟指示器 ,五分钟指示器 ,小时指示器
若分钟指示器中有2个球,五分钟指示器中有6个球,小时指示器中有5个球,则时间为5:32
2、球钟工作原理
- 每过
一分钟 ,球钟就会从球队列 的队首 取出一个球 放入分钟指示器 ,分钟指示器最多可容纳4个球 。 - 当放入
第五个球 时,在分钟指示器的4个球 就会按照他们被放入时 的相反顺序 加入球队列的队尾 。而第五个球 就会进入五分钟指示器 。 - 按此类推,
五分钟指示器 最多可放11个球 ,小时指示器 最多可放11个球 。
3、问题阐述
- 当
小时指示器 放入第12个球 时,原来的11个球 按照他们被放入时 的相反顺序 加入球队列的队尾 ,然后第12个球 也回到队尾 。 - 这时,
三个指示器 均为空,回到初始状态,从而形成一个循环 。因此,该球钟表示时间的范围是从0:00到11:59 。
问题: 现设初始时球队列的球数为27 ,球钟的三个指示器初态均为空。要经过多久,球队列才能恢复 到原来的顺序 ?
4、程序实现
这个问题我们选择顺序栈 来作为指示器 ,链表队列 作为球队列 。实现代码如下:
#include "linkqueue.h"
#include "sqstack.h"
int queue_check(linkqueue lq);
int main(int argc, const char *argv[])
{
linkqueue lq;
int i, min = 0;
data_t value;
sqstack *s_hour,*s_five,*s_min;
lq = linkqueue_create();
if(lq == NULL)
return 0;
s_hour = stack_create(11);
if(s_hour == NULL)
return 0;
s_five = stack_create(11);
if(s_five == NULL)
return 0;
s_min = stack_create(4);
if(s_min == NULL)
return 0;
for(i = 1; i < 28; i++)
{
linkqueue_enter(lq, i);
}
while(1)
{
min++;
value = linkqueue_out(lq);
if(!stack_full(s_min))
stack_push(s_min, value);
else
{
while(!stack_empty(s_min))
linkqueue_enter(lq, stack_pop(s_min));
if(!stack_full(s_five))
stack_push(s_five, value);
else
{
while(!stack_empty(s_five))
linkqueue_enter(lq, stack_pop(s_five));
if(!stack_full(s_hour))
stack_push(s_hour, value);
else
{
while(!stack_empty(s_hour))
linkqueue_enter(lq, stack_pop(s_hour));
linkqueue_enter(lq, value);
if(queue_check(lq))
break;
}
}
}
}
printf("min=%d\n",min);
while(!linkqueue_empty(lq))
{
printf("%d ",linkqueue_out(lq));
}
puts("");
linkqueue_free(lq);
stack_free(s_min);
stack_free(s_five);
stack_free(s_hour);
return 0;
}
int queue_check(linkqueue lq)
{
linklist p;
if(lq == NULL)
{
printf("lq is NULL\n");
return 0;
}
p = lq->front->next;
if(p == NULL || p->next == NULL)
return 0;
while(p->next)
{
if(p->data > p->next->data)
return 0;
p = p->next;
}
return 1;
}
到这里就结束啦! 这里给出免费完整代码的下载链接: 队列C程序实现
|