数据结构之队列的实现

队列的基本操作

InitQueue(&Q):初始化队列,构造一个空队列Q。

QueueEmpty(Q):判队列空,若队列Q为空返回true,否则返回false。

EnQueue(&Qx):入队,若队列Q未满,则将x加入使之成为新的队尾。

DeQueue(&Q&x):出队,若队列Q非空,则删除队头元素,并用x返回。

GetHead(Q&x):读队头元素,若队列Q非空则用x返回队头元素。

ClearQueue(&Q):销毁队列,并释放队列Q占用的内存空间。

常用的FIFO缓存其实就是队列。

顺序队列参考:顺序队列的基本操作-CSDN博客

更多参考:【数据结构】队列(顺序队列、循环队列、链队列)-CSDN博客

队列(queue)是一中先进先出的(first in first out,缩写为FIFO)的线性表,它只允许在表的一端进行插入,而在另一端删除元素。这和我们日常生活中的排队是一致的,最早进入的元素最早离开。

在队列中,允许插入的一端叫做队尾(rear),允许删除的一端叫做队头(front)。

队列顺序存储的约定及说明

front指针指向队头元素

rear指针指向队尾元素的下一个位置

空队时:rear == front

队列初始化:rear = front = 0

入队:队未满时,先送值到队尾,再队尾指针加一

出队:队未空时,先取队头元素,再队头指针加一

当队列满的时候,我们就不能入队了,不过不能简单使用q->rear == MaxSize 判断队满,因为出队的过程中,数组的前面部分会有空闲,这时候入队会有上溢出,但是是假溢出。

注意:

假溢出:指队列进行多次入队与出队操作之后,队尾指针已经指向数组最后一个位置,但队列并没有被填满,如果再插入新的元素,就会超过数组的长度,这种溢出我们称为假溢出。

真溢出:指队列进行多次入队与出队操作之后,队尾指针已经指向数组最后一个位置,并且此时队列已经被填满,如果再插入新的元素,就会超过数组的长度,这种溢出我们称为真溢出。

为了改进假溢出的问题,可以将顺序队列想象为一个首尾相接的环状空间,以此逻辑来进行操作,这就是我们常说的循环队列。

顺序队列

顺序队列的定义

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

#define ERROR  0
#define OK     1
#define TRUE   1
#define FALSE  0
#define QUEUESIZE 10


typedef int Status;
typedef int QElemtype;

typedef struct QNode{
	QElemtype *base;
	int front;
	int rear;
}SqQueue; 

注意,这里的front和rear指的是数组的下标;

理解头和尾的关键是,明白队列的有效部分其实就是头和尾之间的部分。

顺序队列的初始化

void InitQueue(SqQueue *Q)
{
	Q->base=(QElemtype*)malloc(sizeof(QElemtype)*QUEUESIZE);
	assert(Q->base!=NULL);
	Q->front=Q->rear=0; 
}

入队操作

Status EnQueue(SqQueue *Q,QElemtype e)
{
	if(Q->rear==QUEUESIZE)
	{
		return ERROR;
	}
	Q->base[Q->rear]=e;
	Q->rear++;
	return OK;
}

出队操作

Status DeQueue(SqQueue *Q,QElemtype *e)
{
	if(Q->front==Q->rear)
	{
		return ERROR;
	}
	*e=Q->base[Q->front];
	Q->front++;
	return OK;
}

判断队列是否为空

Status QueueEmpty(SqQueue *Q)
{
	if(Q->front==Q->rear)
	{
		return TRUE;
	}
	return FALSE;
}

求队列长度

Status QueueLength(SqQueue Q)
{
	return Q.rear-Q.front;
}

获取队头元素

Status GetHead(SqQueue *Q,QElemtype *e)
{
	if(Q->front==Q->rear)
	{
		return ERROR;
	}
	*e=Q->base[Q->front];
	return OK;
}

销毁队列

void DestoryQueue(SqQueue *Q)
{
	if(Q->base)      //队列Q存在 
	{
		free(Q->base);
	}
	Q->base=NULL;
	Q->front=Q->rear=0;
}

清空队列

void ClearQueue(SqQueue *Q)
{
	Q->front=Q->rear=0;
}

遍历队列

void QueueTraverse(SqQueue Q,void(*visit)(QElemtype))
{
	int i=Q.front;
	while(i!=Q.rear)
	{
		visit(Q.base[i]);
		i++;
	}
	printf("\n");
} 
void Print(QElemtype e)
{
	printf("%d ",e);
}

主函数

int main()
{
	QElemtype i,e,d;
	SqQueue Q;
	InitQueue(&Q);
	printf("请输入队列的%d个元素:\n",QUEUESIZE);
	for(i=0;i<QUEUESIZE;i++)
	{
		scanf("%d",&d);
		EnQueue(&Q,d);
	}
	printf("队列的元素为:");
	QueueTraverse(Q,Print);
	printf("队列长度为:%d\n",QueueLength(Q));
	int k=QueueLength(Q);
	printf("连续%d次由对头删除元素,队尾插入元素:\n",k/2);
	for(i=0;i<k/2;i++)
	{
		DeQueue(&Q,&e);
		printf("删除的队列的元素是:%d,请输入插入的元素:",e);
		scanf("%d",&d);
		EnQueue(&Q,d);
	}
	printf("新的队列元素为:\n");
	QueueTraverse(Q,Print);
	
	int n=GetHead(&Q,&e);
	if(n)printf("对头元素为:%d\n",e);
	else {
		printf("队空!\n");	return -1;
	}
	ClearQueue(&Q);
	printf("清空队列后队列是否为空:%d\t(1:为空 ,0:不为空)\n",QueueEmpty(&Q));
	DestoryQueue(&Q);
	printf("销毁队列后:\nQ.base=%u\tQ.front=%d\tQ.rear=%d\t\n",Q.base,Q.front,Q.rear);
	return 0; 
}

更多待补充。

ringbuffer

优秀的内存规划方法——环形缓冲区(ring buffer)-CSDN博客

环形缓冲区(ringbuffer)-CSDN博客

【高阶】linux内核环形缓冲区ring buffer实现原理分析_linux ringbuffer-CSDN博客

ringbuffer其实就是一种循环队列。

基本操作如下:

typedef int ElemType
#define MAXSIZE 1024
 
/*循环队列的顺序存储结构*/
typedef struct
{
    ElemType data[MAXSIZE];
    int front;    //头指针
    int rear;    //尾指针
}SqQueue;
 
/*初始化一个空队列*/
int Init_SeQueue(SeQueue *Q)
{
    Q=(SeQueue *)malloc(sizeof(SeQueue));
    if(Q!=NULL)
    {
        Q->front=0;
        Q->rear=0;
    }
    return 1;
}
 
/*求队列长度*/
int QueueLength(SeQueue *Q)
{
    return (Q->rear-Q->front+MAXSIZE)%MAXSIZE;
}
 
/*判空*/
int SeQueue_Empty(SeQueue *Q)
{
    return Q->rear==Q->front;
}
 
/*判满*/
int SeQueue_Full(SeQueue *Q)
{
    return (Q->rear+1)%MAXSIZE==Q->front;
}
 
/*入队操作*/
int Enter_SeQueue(SeQueue *Q,ElemType e)
{
    if(SeQueue_Full(Q))
    {
        return 0;
    }
 
    Q->data[Q->rear]=e;
    Q->rear=(Q->rear+1)%MAXSIZE;
    return 1;
}
 
/*出队操作*/
int Delete_SeQueue(SeQueue *Q,ElemType e)
{
    if(SeQueue_Empty(Q))
    {
        return 0;
    }
 
    e=Q->data[Q->front];
    Q->front=(Q->front+1)%MAXSIZE;
    return 1;
}

更多待补充。

链队列

用链式存储实现的队列

typedef int ElemType
 
/*结点结构*/
typedef struct QNode
{
    ElemType data;
    struct QNode *next;
}QNode,*QNodePtr;
 
/*链队列结构*/
typedef struct 
{
    QNodePtr front,rear;//队头、队尾指针
}LinkQueue,*LinkQueuePtr;
 
/*初始化一个空队列*/
int Init_LinkQueue(LinkQueuePtr Q)
{
    Q=(LinkQueuePtr)malloc(sizeof(LinkQueue));
    QNodePtr head=(QueuePtr)malloc(sizeof(QNode));
    
    if(head!=NULL && Q!=NULL)
    {
        head->next=NULL;
        Q->front=head;
        Q->rear=head;
    }
    return 1;
}
 
/*判空*/
int LinkQueue_Empty(LinkQueuePtr Q)
{
    return Q->front==Q->rear;
}
 
/*入队操作*/
int Enter_LinkQueue(LinkQueuePtr Q,ElemType e)
{
    QNodePtr s=(QNodePtr)malloc(sizeof(QNode));
    if(s==NULL){
        return 0
    }    
    //初始化新结点
    s->data=e;
    s->next=NULL;
    //建立新联系
    Q->rear->next=s;
    Q->rear=s;
 
    return 1;
}
 
/*出队操作*/
int Delte_LinkQueue(LinkQueuePtr Q,ElemType *e)
{
    QNodePtr p;
    if(LinkQueue_Empty(Q)){
        return 0
    } 
       
    //保留删除结点的信息
    p=Q->front->next;
    *e=p->data;
 
    //建立新联系
    Q->front->next=p->next;
   
    if(Q->rear==p)
    {
        Q->rear=Q->front)
    }
    
    free(p);
 
    return 1;
}

更多待补充。

  • 13
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值