数据结构复习笔记4:队列,双端队列,循环队列

1.队列概念和特点

        队列是⼀种特殊的线性表,特殊之处就在于它只允许在表的前端进⾏删除操作,在表的后端进⾏ 插⼊操作。和栈⼀样,队列也是⼀种操作受到限制的线性表。进⾏插⼊操作的端称之为队尾,进⾏删除 操作的端称之为队头。队列中没有队列的时候,称之为空队列。队列的数据元素,⼜叫做队列元素。在 队列中插⼊⼀个队列元素称之为⼊队,在队列中删除⼀个队列元素,称之为出队。因为队列只允许在⼀ 端插⼊,在另⼀端删除,所以只有最早进⼊的队列元素才可以从队列中删除,故队列⼜称为先进先出线性表。

队列的表示和实现(存储结构)

链队列 :采用链式存储结构的队列

顺序队列 :采用顺序存储结构的队列

队列的操作包括初始化、销毁、入队、出队、获取队首元素、获取队尾元素以及检查队列是否为空等。

2.顺序队列

        当我⽤⼀⽚连续的存储空间来存储队列中的数据元素的时候,这样的队列就称之为顺序队列。类似于顺序栈。⽤⼀维数组来存放顺序队列中的数据元素。队头设置在最近⼀个离开队列元素所占的位置。队尾设置在最近⼀个进⾏⼊队列的元素位置。那么队头和队尾随着插⼊和删除的变化⽽变化。当队列为空时,front = rear;队列中的元素个数可以由队头 - 队尾求得。

假溢出

        但是,这个时候,会有⼀个问题。当我们的队尾指针指向size - 1 时,代表⻓度已满。但是根据队 列的规则,就实际情况来说,他还有空闲的空间。那么这个时候,我们就将其称之为假溢出。

        为了解决假溢出的问题,就是将我们的顺序队列看成是⾸位相接的循环结构。⾸尾指示器不变, 这种队列就叫做,循环顺序队列。

        也就是说,当我们的队尾元素达到数组的上限时,如果还有数据元素⼊队并且数组的第0个空间是 空闲时,队尾指示器就指向数组的0端,所以。整个队尾指示器+1的操作就可以修改为:rear = (rear + 1)%maxSize;队头指示器同样是如此。当队头的操作达到数组的上限的时候,如果还有数组元素出 队,这个时候,队头指示器就要指向数组的0端。所以,队头指示器+1的操作就是 front = (front + 1)%maxSize。

        这样的话,就⼜有⼀个问题,队满和队空的时候,都有rear = front。为了解决这个问题,⼀般的 ⽅法就是,少使⽤⼀个空间。所以,我们判断队空的条件就变成了 rear = front。判断队满的条件是 (rear + 1)%maxSize = front。与此同时,循环队列中数据元素的个数是(rear - front + maxSize)% maxSize。

所以普通队列的实现我们用链式存储结构。

3.链队列的代码实现

1.结点结构
///链式队列//
typedef struct qnode{//链式队列结点 
	int data;//队列元素
	struct qnode *next;//指向下一个结点的指针 
}qnode,*lqueue; 

typedef struct linkqueue{//链式队列---可选,不写结构体,直接定义对头队尾指针也可 
	lqueue front,rear;//队头队尾指针,队首指针是链表头结点 
}linkqueue;
2.初始化
//初始化
void initqueue(linkqueue *q)
{   
	q->front=q->rear=(lqueue)malloc(sizeof(qnode));
    if(q->front==NULL)
    {
    	printf("分配失败\n");
	}
	else{
		q->front->next=NULL;
	}
 } 
3.入队
//入队 
void enqueue(linkqueue* q,int x)
{
	lqueue s=(lqueue )malloc(sizeof(qnode));
	s->data =x;
	s->next =NULL;//新节点插入到链尾
	q->rear->next=s;
	q->rear =s; 
 } 
4.出队
//出队,队首指针是链表头结点 ,删除的是队首指针的下一个,即front->next 
void dequeue(linkqueue* q) 
{
	int x;//保存出队元素 
	//先判空,不空才能出 
	if(q->front->next==NULL)
	{
		printf("空\n");//队空,报错 
	 } 
	else{
		lqueue p=q->front->next; 
		x=p->data;
		q->front ->next=p->next ;
		printf("%d\n",x);
		//若原队列只有一个结点了,则删除边空,需要处理尾指针 
		if(q->rear==p)
		q->rear =q->front;
		free(p); 
		p=NULL;
	}
}

4.顺序实现循环队列

1.结点结构
//循环队列 
typedef struct
{
	int* data;//指针模拟开数组 
	int f,r;//本质是下标 	
}squeue; 
2.初始化
//初始化
squeue initqueue()
{
	squeue q;
	q.data=(int*)malloc(sizeof(int)*maxx);
	q.f=q.r=0;
	return q;
 } 
3.入队
//入队---->前提先判满 
void enqueue(squeue* q,int k)
{
	//判满
	if(q->f==((q->r+1)%maxx)) 
	{
		printf("队满\n");
		return; 
	}
	q->data[q->r]=k;
	q->r=(q->r+1)%maxx; 
 } 
4.出队
//出队 --->前提 判空 
void dequeue(squeue* q) 
{
	//判空
	if(q->r==q->f)
	{
		printf("队空\n");
		return ; 
	 } 
	 q->f=(q->f+1)%maxx;
}

5.双端队列

1.特点

        对于双端队列来说,就是两端都是结尾的队列。队列的每⼀端都可以插⼊数据项和移除 数据项。相对于普通队列。双端队列的⼊队和出队操作在两端都可以进进⾏。

        这种数据结构的特性,使得他更加的实⽤和⽅便。当你只允许使⽤⼀端出队、⼊队操作的时候, 他等价于⼀个栈。当限制⼀端只能出队,另⼀端只能⼊队,他就等价于⼀个普通队列。

2.双端队列链式存储全操作展示
#define maxx 10
typedef struct Node{
	int data;
	struct Node* pre;
	struct Node* next;
}node; 
//中间节点存储右端第一次插入的数据
node* l;
node* r;
void initqueue()
{
	node* s=(node*)malloc(sizeof(node));
	s->pre=s->next=NULL;
	l=r=s;
}
//左边插入
void left_insert(int k)
{//l 指向真实的左端数据 
	node* s=(node*)malloc(sizeof(node));
	s->data=k;
	s->pre=NULL;
	l->pre=s;
	s->next=l;
	l=s;
} 
//右插入
void right_insert(int k)
{
	//r 指向真实的右端数据的下一个节点 
	node* s=(node*)malloc(sizeof(node));
	r->data=k;
	r->next=s;
	s->next=NULL;
	s->pre=r;
	r=s; 
} 
//左删除 
void left_del()
{
	if(l==r)
	{
		printf("空\n");
		return;
	 } 
	 node* p=l;
	 l=l->next;
	 l->pre=NULL;
	 printf("删除了%d\n",p->data);
	 free(p);
	 p=NULL;
 } 
 //右删除
void right_del()
{
	if(l==r)
	{
		printf("空\n");
		return;
	 } 
	 node* p=r;
	 r=r->pre;
	 r->next=NULL;
	 printf("删除了%d\n",r->data);
	 free(p);
	 p=NULL;
} 
3.双端队列顺序存储全操作展示
#define maxx 10
typedef struct {
	int *data;
	int l,r;
	int sum;//元素个数 
}douqueue; 
douqueue initqueue()
{
	douqueue q;
	q.data=(int *)malloc(sizeof(int)*maxx);
	q.l=q.r=0;
	q.sum=0;
	return q;
}
//左端插入
void left_insert(douqueue *q,int k)
{
	if(q->sum==maxx)
	{
		printf("满\n");
		return;
	 } 
	 q->data[q->l]=k;
	 q->l=(q->l+maxx-1)%maxx;//
	 q->sum++;
}
//左端删除
void left_delet(douqueue *q) 
{
	int x;//保存删除的元素
	if(q->sum==0)
	{
		printf("空\n");
		return;
	 } 
	x=q->data[(q->l+1)%maxx];
	printf("删除了%d\n",x);
	q->l=(q->l+1)%maxx;
	q->sum--;
}
//右端插入
void right_insert(douqueue *q,int k)
{
	if(q->sum==maxx)
	{
		printf("满\n");
		return;
	 } 
	 q->r=(q->r+1)%maxx;
	 q->data[q->r]=k;
	 q->sum++;
}
//右端删除
void right_delet(douqueue *q) 
{
	int x;//保存删除的元素
	if(q->sum==0)
	{
		printf("空\n");
		return;
	 } 
	x=q->data[q->r];
	printf("删除了%d\n",x);
	q->r=(q->r-1+maxx)%maxx;//
	q->sum--;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值