l4-d9 队列实现及其应用(下)

一、链式队列

插入操作在队尾进行,删除操作在队头进行,由队头指针和队尾指针控制队列的操作。

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;
}

运行结果

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值