一、链式队列
插入操作在队尾进行,删除操作在队头进行,由队头指针和队尾指针控制队列的操作。
typedef int data_t;
typedef struct node_t{
data_t data;
struct node_t *next;
}linknode_t, *linklist_t;
typedef struct{
linklist_t front, rear;
}linkqueue_t;
1.原理图
2.常见命令
入队
尾部插入
1)封装节点;2)连接节点;3)更新队尾
//入队
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
p->data = x;
p->next = NULL;
//队列连接节点p
lq->rear->next = p;
lq->rear = p;
return 0;
}
出队
头部删除
只有一个元素时,rear需要回指头节点
或者,删除头节点,第一个节点视为头节点,元素“5”出队。
1)指针p指向要删除的目标;2)更改指针指向;3)释放内存
//出队
datatype dequeue(linkqueue *lq) {
linklist p;
if (lq == NULL) {
printf("lq is NULL\n");
return -1;
}
p = lq->front;//指针p指向要删除的目标
lq->front = p->next;//更改p
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);
}
释放空间
先释放内层,再释放外层。
//释放内存
linkqueue * queue_free(linkqueue *lq) {
linklist p;
if (lq == NULL) {
printf("lq is NULL\n");
return NULL;
}
//p指针循环后移
while (lq->front) {//当队列的front一直存在
p = lq->front;
lq->front = p->next;
printf("free:%d\n", p->data);//先打印后释放
free(p);
}
free(lq);
lq = NULL;//置空
return NULL;
}
清空
与释放不同的是,清空是队列元素清空,保留头节点。
//队列清空
int queue_clear(linkqueue *lq) {
linklist p;
if (lq == NULL) {
printf("lq is NULL\n");
return -1;
}
//删除p指向的节点
while (lq->front->next) {//结束条件:front->next为空
p = lq->front;
lq->front = p->next;//连接p之后的节点
printf("clear free:%d\n", p->data);
free(p);
p = NULL;
}
return 0;
}
3. 源代码
头文件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.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;
}
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
p->data = x;
p->next = NULL;
//队列连接节点p
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;//指针p指向要删除的目标
lq->front = p->next;//更改p
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;
}
//删除p指向的节点
while (lq->front->next) {//结束条件:front->next为空
p = lq->front;
lq->front = p->next;//连接p之后的节点
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;
}
//p指针循环后移
while (lq->front) {//当队列的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_empty(lq)) { //出队
//printf("dequeue:%d\n", dequeue(lq));
//}
queue_clear(lq);
lq = queue_free(lq);
enqueue(lq, 50);
return 0;
}
二、栈和队列的应用-球钟问题
1.球钟问题
球钟是一个利用球的移动来记录时间的简单装置。
它有三个可以容纳若干个球的指示器:分钟指示器,五分钟指示器,小时指示器。
若分钟指示器中有2个球,五分钟指示器中有6个球,小时指示器中有5个球,则时间为5:32。
每过一分钟,球钟就会从球队列的队首取出一个球放入分钟指示器,分钟指示器最多可容纳4个球。
当放入第五个球时,在分钟指示器的4个球就会按照他们被放入时的相反顺序加入球队列的队尾。而第五个球就会进入五分钟指示器。
按此类推,五分钟指示器最多可放11个球,小时指示器最多可放11个球。
当小时指示器放入第12个球时,原来的11个球按照他们被放入时的相反顺序加入球队列的队尾,然后第12个球也回到队尾。这时,三个指示器均为空,回到初始状态,从而形成一个循环。因此,该球钟表示时间的范围是从0:00到11:59。
现设初始时球队列的球数为27,球钟的三个指示器初态均为空。问,要经过多久,球队列才能回复到原来的顺序?
2.常见命令
检查队列是否升序
int check(linkqueue * lq) {
linklist p;
if (lq == NULL) {
printf("lq is NULL\n");
return -1;
}
p = lq->front->next;
while (p && p->next) {
if (p->data < p->next->data) {
p = p->next;
} else {
return 0;
}
}
return 1;
}
3.源代码
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.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;
}
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;
}
sqstack.h
typedef int data_t;
typedef struct {
data_t *data;
int maxlen;//栈的最大容量
int top;//栈顶
}sqstack;
sqstack * stack_create(int len);
int stack_push(sqstack * s, data_t value);
int stack_empty(sqstack *s);
int stack_full(sqstack *s);
data_t stack_pop(sqstack *s);
data_t stack_top(sqstack *s);
int stack_clear(sqstack *s);
int stack_free(sqstack *s);
sqstack.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sqstack.h"
sqstack * stack_create(int len) {
sqstack * s;
if ((s =(sqstack *)malloc(sizeof(sqstack))) == NULL) {
printf("malloc sqstack failed\n");
return NULL;
}
if ((s->data = (data_t *)malloc(len * sizeof(data_t)))==NULL) {
printf("malloc data failed\n");
free(s);
return NULL;
}
memset(s->data, 0, len*sizeof(data_t));
s->maxlen = len;
s->top = -1;
return s;
}
int stack_push(sqstack * s, data_t value) {
if (s == NULL) {
printf("s is NULL\n");
return -1;
}
if (s->top == s->maxlen-1) {
printf("stack is full\n");
return -1;
}
s->top++;
s->data[s->top] = value;
return 0;
}
/*
*@ret 1-empty
* */
int stack_empty(sqstack *s) {
if (s == NULL) {
printf("s is NULL\n");
return -1;
}
return (s->top == -1 ? 1 : 0);
}
/*
* @ret 1-full
* */
int stack_full(sqstack *s) {
if (s == NULL) {
printf("s is NULL\n");
return -1;
}
return (s->top == s->maxlen-1 ? 1 : 0);
}
data_t stack_pop(sqstack *s) {
s->top--;
return (s->data[s->top+1]);
}
data_t stack_top(sqstack *s) {
return (s->data[s->top]);
}
int stack_clear(sqstack *s) {
if (s == NULL) {
printf("s is NULL\n");
return -1;
}
s->top = -1;
return 0;
}
int stack_free(sqstack *s) {
if (s == NULL) {
printf("s is NULL\n");
return -1;
}
if (s->data != NULL)
free(s->data);
free(s);
return 0;
}
test.c
#include <stdio.h>
#include "linkqueue.h"
#include "sqstack.h"//栈的头文件
int check(linkqueue * lq);
int main(int argc, const char *argv[])
{
linkqueue *lq;
sqstack *s_hour, *s_five, *s_min;//一小时、五分钟、一分钟三个栈
int value;
int i, min = 0;
if ((lq = queue_create()) == NULL) {
return -1;
}
for (i = 1; i <= 27; i++) {
enqueue(lq, i);
}
if ((s_hour = stack_create(11)) == NULL) {//1小时栈最大容量11,即11个球
return -1;
}
if ((s_five = stack_create(11)) == NULL) {//5分钟栈最大容量11
return -1;
}
if ((s_min = stack_create(4)) == NULL) {//1分钟栈最大容量4
return -1;
}
while (1) {
min++;
if (!queue_empty(lq)) {//如果队列不空
value = dequeue(lq);//出队
if (!stack_full(s_min)) {//如果栈不满,则入栈
stack_push(s_min, value);//入分钟栈
} else {//分钟栈满
while (!stack_empty(s_min)) {//清空栈
enqueue(lq, stack_pop(s_min));//栈里的元素放进队列中
}
if (!stack_full(s_five)) {//如果栈不满,则入栈
stack_push(s_five, value);//入五分钟栈
} else {
while (!stack_empty(s_five)) {//清空栈
enqueue(lq, stack_pop(s_five));//栈里的元素放进队列中
}
if (!stack_full(s_hour)) {//如果栈不满,则入栈
stack_push(s_hour, value);//入小时栈
} else {
while (!stack_empty(s_hour)) {//清空栈
enqueue(lq, stack_pop(s_hour));//栈里的元素放进队列中
}
enqueue(lq, value);//最后一个球放进队列中
//0:0
if (check(lq) == 1) {//检查队列是否升序
break;
}
}
}
}
}
}
printf("total:%d\n", min);
printf("dequeue:");
while (!queue_empty(lq))
printf("%d ", dequeue(lq));
puts("");
return 0;
}
int check(linkqueue * lq) {
linklist p;
if (lq == NULL) {
printf("lq is NULL\n");
return -1;
}
p = lq->front->next;
while (p && p->next) {
if (p->data < p->next->data) {
p = p->next;
} else {
return 0;
}
}
return 1;
}
三、作业
1、链式队列有假溢出么?链式队列需要判空判满么?为什么?
(1)没有假溢出。因为在进行队列的操作时,只能从队尾进行入队,队头进行出队。
(2)需要判空。因为链式队列可能没有元素。不需要判满,因为入队是从队尾实现,链式队列可以申请动态空间。
2、代码实现链式队列,输入数字入队,输入字符出队。
头文件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_clear(linkqueue *lq);
linkqueue * queue_free(linkqueue *lq);
程序文件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 is failed\n");
return NULL;
}
lq -> front = lq -> rear = (linklist)malloc(sizeof(listnode));
if(lq -> front == NULL){
printf("malloc is 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_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("dequeue:%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<ctype.h>
#include"linkqueue.h"
int main(){
linkqueue * lq;
lq = queue_create();
if (lq == NULL)
return -1;
printf("input:\n");
while(1){
char ch;
scanf("%c",&ch);
if(isalpha(ch))//判断是否为字符
printf("dequeue:%c\n",ch);
else if(isdigit(ch)){//判断是否为数字
ch = (int)(ch - '0');
enqueue(lq ,ch);
printf("enqueue:%d\n",ch);
}
else if(ch == 27)//按下esc结束
break;
}
queue_clear(lq);
lq = queue_free(lq);
return 0;
}
运行结果