数据结构——队列(顺序队列,链队列)

队列

队列的定义

队列简称,它是一种运算受限的线性表,其仅允许在表的一端进行插入,而在表的另一端进行删除。把进行插入的一端称做队尾(rear),进行删除的一端称做队头(front)。

特点:先进先出

队列的顺序存储结构

普通顺序队列

先定义一下顺序队列的数据类型:

const int maxn = 10;
typedef struct{
	int data[maxn];
	int front,rear;//队首和队尾指针
	 
}Queue;
//顺序队的四要素(初始时front=rear=-1):
//队空条件:front=rear
//队满条件:rear=MaxSize-1 
//元素e进队:rear++;data[rear]=e; 
//元素e出队:front++;e=data[front]; 
//rear指向队尾元素;front指向队头元素的前一个位置。

顺序队的基本操作:

  1. 初始化队列InitQueue(q)

    //初始化一个队列
    void InitQueue(Queue *&q){
    	q =(Queue *) malloc(sizeof(Queue));
    	q->front=q->rear = -1;
    } 
    
    
  2. 销毁队列DestroyQueue(q)

    //销毁队列 
    void DestroyQueue(Queue *&q){
    	free(q);
    }
    
    
  3. 判断队列是否为空IsEmpty(q)

    bool IsEmpty(Queue *q){
    	return q->front==q->rear;
    } 
    
    
  4. 进队列enQueue(q,e)

    //入队 
    bool enQueue(Queue *&q,int e){
    	if (q->rear==maxn-1)
    	return false;
    	q->rear++;
    	q->data[q->rear]=e;
    	return true;
    }
    
    
  5. 出队列deQueue(q,e)

    扫描二维码关注公众号,回复: 10180364 查看本文章
    //出队
    bool deQueue(Queue *&q,int &e){
    	if(IsEmpty(q))
    	return false;
    	q->front++;
    	e=q->data[q->front];
    	return true;
    } 
    

整合一下

#include<stdio.h>
#include<iostream>
#include<stdlib.h> 
using namespace std;
const int maxn = 10;
typedef struct{
	int data[maxn];
	int front,rear;//队首和队尾指针
	 
}Queue;

//初始化一个队列
void InitQueue(Queue *&q){
	q =(Queue *) malloc(sizeof(Queue));
	q->front=q->rear = -1;
} 
//销毁队列 
void DestroyQueue(Queue *&q){
	free(q);
}
bool IsEmpty(Queue *q){
	return q->front==q->rear;
} 
//入队 
bool enQueue(Queue *&q,int e){
	if (q->rear==maxn-1)
	return false;
	q->rear++;
	q->data[q->rear]=e;
	return true;
}
//出队
bool deQueue(Queue *&q,int &e){
	if(IsEmpty(q))
	return false;
	q->front++;
	e=q->data[q->front];
	return true;
} 
int main(){
	Queue *qu;
	int e,a[]={1,2,3,4,5,6,7,8,6,5};
	InitQueue(qu);
	if(IsEmpty(qu))
	for(int i = 0;i<10;i++){
		enQueue(qu,a[i]);
	}
	for(int i = 0;i<=qu->rear;i++){
		printf("%d ",qu->data[i]);
	}
	printf("\n");
	deQueue(qu,e);
	deQueue(qu,e);
	deQueue(qu,e);
 
	printf("出队元素为 %d\n",e);
	printf("这时头指针为%d\n",qu->front); 
	for(int i = qu->front;i<=qu->rear;i++){
		printf("%d ",qu->data[i]);
	}
	printf("\n");
	int s=enQueue(qu,e);
	printf("%d",s);//这里结果是0,但我们刚才弹出了一个,应该是没有满才对,
	//所以这样有一个缺陷那就是队列假溢出 
} 

就像看到的那样,这里队列假满溢出,所以我们设计一个环形的顺序表来做队列

当然,这里顺序表是不可能真的首尾相连的,我们是逻辑上实现首尾相连

环形顺序队列

数据类型一样

const int maxn = 10;
typedef struct{
	int data[maxn];
	int front,rear;//队首和队尾指针
	 
}Queue;
//队空条件:front=rear 
//队满条件:(rear+1)%MaxSize=front 
//进队e操作:rear=(rear+1)%MaxSize; 将e放在rear处 
//出队操作:front=(front+1)%MaxSize; 取出front处元素e; 

环形顺序队的实现基本操作:

  1. 初始化队列InitQueue(q)

    //初始化一个队列
    void InitQueue(Queue *&q){
    	q =(Queue *) malloc(sizeof(Queue));
    	q->front=q->rear = 0;
    } 
    
    
  2. 销毁队列DestroyQueue(q)

  3. 判断队列是否为空IsEmpty(q)

  4. 进队列enQueue(q,e)

    //入队 
    bool enQueue(Queue *&q,int e){
    	if ((q->rear+1)%maxn==q->front)
    	return false;
    	q->rear=(q->rear+1)%maxn;
    	q->data[q->rear]=e;
    	return true;
    }
    
  5. 出队列deQueue(q,e)

    //出队
    bool deQueue(Queue *&q,int &e){
    	if(IsEmpty(q))
    	return false;
    	q->front=(q->front+1)%maxn;
    	e=q->data[q->front];
    	return true;
    } 
    

整合一下

#include<stdio.h>
#include<iostream>
#include<stdlib.h> 
using namespace std;
const int maxn = 10;
typedef struct{
	int data[maxn];
	int front,rear;//队首和队尾指针
	 
}Queue;

//初始化一个队列
void InitQueue(Queue *&q){
	q =(Queue *) malloc(sizeof(Queue));
	q->front=q->rear =0;
} 
//销毁队列 
void DestroyQueue(Queue *&q){
	free(q);
}
bool IsEmpty(Queue *q){
	return q->front==q->rear;
} 
//入队 
bool enQueue(Queue *&q,int e){
	if ((q->rear+1)%maxn==q->front)
	return false;
	q->rear=(q->rear+1)%maxn;
	q->data[q->rear]=e;
	return true;
}
//出队
bool deQueue(Queue *&q,int &e){
	if(IsEmpty(q))
	return false;
	q->front=(q->front+1)%maxn;
	e=q->data[q->front];
	return true;
} 
int main(){
	Queue *qu;
	int e,a[]={1,2,3,4,5,6,7,8,9,10};
	InitQueue(qu);
	if(IsEmpty(qu))
	for(int i = 0;i<4;i++){
		enQueue(qu,a[i]);
	}
	for(int i = qu->front;i<=qu->rear;i++){
		printf("%d ",qu->data[i]);
	}
	printf("\n");
	deQueue(qu,e);
	deQueue(qu,e);
	deQueue(qu,e);
 
	printf("出队元素为 %d\n",e);
	printf("这时头指针为%d\n",qu->front); 
	for(int i = qu->front;i<=qu->rear;i++){
		printf("%d ",qu->data[i]);
	}
	printf("\n");
	int s=enQueue(qu,e);
	printf("是否成功入队 %d",s);
	printf("\n");

	for(int i = qu->front;i<=qu->rear;i++){
		printf("%d ",qu->data[i]);
	}
	printf("\n"); 
} 

这个环形队列只能存放maxn-1 个元素,因为要区分队满和队空的条件,下面我们用另外一种方法设计循环队列,

环形队列2

对于环形队列来说,如果知道队头指针和队列中 元素个数,则可以计算出队尾指针。

已知front、rear,求队中元素个数:
   count=(rear-front+MaxSize)%MaxSize

已知front、count,求rear:
   rear=(front+count)%MaxSize

已知rear、count,求front:
   front=(rear-count+MaxSize)%MaxSize

这是定义环形队列的数据结构

const int maxn = 10;
typedef struct{
	int data[maxn];
	int front,count;//队首和元素个数
	 
}Queue;
//队空条件:count=0 
//队满条件:count=maxn 
//进队e操作:rear=(rear+1)%MaxSize; 将e放在rear处 
//出队操作:front=(front+1)%MaxSize; 取出front处元素e; 

环形顺序队的实现基本操作:

  1. 初始化队列InitQueue(q)

    //初始化一个队列
    void InitQueue(Queue *&q){
    	q =(Queue *) malloc(sizeof(Queue));
    	q->front=q->count = 0;
    } 
    
    
  2. 销毁队列DestroyQueue(q)

  3. 判断队列是否为空IsEmpty(q)

    bool IsEmpty(Queue *q){
    	return q->count==0;
    } 
    
  4. 进队列enQueue(q,e)

    //入队 
    bool enQueue(Queue *&q,int e){
    	int rear;// 临时队尾
        if(q->count==maxn)
            return false;//溢出
        else{
            rear = (count+front)%maxn;
            rear = (rear+1)%maxn;//队尾加一
            q->data[rear]=e;
            q->count++;//元素个数加一
            return true;
        }
    }
    
  5. 出队列deQueue(q,e)

    //出队
    bool deQueue(Queue *&q,int &e){
    	if(IsEmpty(q))
    	return false;
        else{
            q->front=(q->front+1)%maxn;
    		e=q->data[q->front];
            q->count--;
    		return true;
        }
    	
    } 
    

具体整合这里就不操作了,和上面类似

链队列

有头节点的链队

链队列,我们不但要有存放数据节点的单链表,还要有指向头节点和尾节点的单链表指针,

先来定义一下数据类型

typedef struct qnode{
	int data;
	struct qnode *next;
}Qnode;//这个其实就是个单链表 
typedef struct{
	Qnode *front;//指向单链表队头节点 
	Qnode *rear;//指向单链表队尾节点 
}LQueue;//链队头节点 
//队空条件:front=rear=NULL 
//队满条件:不考虑 
//进队e操作:将包含e的节点插入到单链表表尾 
//出队操作:删除单链表首数据节点 

链队列实现简单操作

  1. 初始化链队

    void InitQueue(LQueue *&q){
    	q = (LQueue*)malloc(sizeof(LQueue));
    	q->front=q->rear=NULL;
    }
    
  2. 销毁一个链队

void DestroyQueue(LQueue *&q){
	//我们需要销毁每个数据节点和链队头节点
	Qnode *p = q->front,*r;
	if(p!=NULL){
		r = p->next;
		while (r!=NULL){
			free(p);
			p=r;
			r=p->next;
		}//销毁数据节点
	} 
	free(p);free(q);//销毁链队头节点
}
  1. 判断链队是否为空

    bool IsEmpty(LQueue *q){
    	return q->rear ==NULL;
    }
    
    
  2. 进队

    void enQueue(LQueue *&q,int e){
    	Qnode *p;
    	p=(Qnode*)malloc(sizeof(Qnode));
    	p->data=e;
    	p->next =NULL;//先创建一个数据节点;
    	//考虑原来队列空和非空两种情况
    	if(IsEmpty(q)){
    		q->front = q->rear=p;
    	} 
    	else{
    		q->rear->next=p;
    		q->rear=p;
    		
    	}
    }
    
    
  3. 出队

    bool deQueue(LQueue*&q,int &e){
    	Qnode *t;
    	//先判断一下队列是否是空的
    	if(IsEmpty(q))
    	return false;
    	t=q->front;
    	if(q->front==q->rear)//原来队列只有一个节点
    	{
    		q->front=q->rear=NULL; 
    	} 
    	else{
    		q->front=q->front->next;
    	}
    	e=t->data;
    	free(t);
    	return true;
    }
    

完整代码

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

typedef struct qnode{
	int data;
	struct qnode *next;
}Qnode;//这个其实就是个单链表 
typedef struct{
	Qnode *front;//指向单链表队头节点 
	Qnode *rear;//指向单链表队尾节点 
}LQueue;//链队头节点 

void InitQueue(LQueue *&q){
	q = (LQueue*)malloc(sizeof(LQueue));
	q->front=q->rear=NULL;
} 
void DestroyQueue(LQueue *&q){
	//我们需要销毁每个数据节点和链队头节点
	Qnode *p = q->front,*r;
	if(p!=NULL){
		r = p->next;
		while (r!=NULL){
			free(p);
			p=r;
			r=p->next;
		}
	} 
	free(p);free(q);
} 
bool IsEmpty(LQueue *q){
	return q->rear ==NULL;
}
void enQueue(LQueue *&q,int e){
	Qnode *p;
	p=(Qnode*)malloc(sizeof(Qnode));
	p->data=e;
	p->next =NULL;//先创建一个数据节点;
	//考虑原来队列空和非空两种情况
	if(IsEmpty(q)){
		q->front = q->rear=p;
	} 
	else{
		q->rear->next=p;
		q->rear=p;
		
	}
}
bool deQueue(LQueue*&q,int &e){
	Qnode *t;
	//先判断一下队列是否是空的
	if(IsEmpty(q))
	return false;
	t=q->front;
	if(q->front==q->rear)//原来队列只有一个节点
	{
		q->front=q->rear=NULL; 
	} 
	else{
		q->front=q->front->next;
	}
	e=t->data;
	free(t);
	return true;
}
int main(){
	LQueue *q;
	InitQueue(q);
	int a[]={4,3,5,6,7},e;
	for(int i=0;i<5;i++){
		enQueue(q,a[i]);
	} 
	for(int i=0;i<3;i++){
		deQueue(q,e);
		printf("%d ",e);
	}
	printf("%d ",q->front->data);
} 

没有头节点的链队

没有头节点,只有指向队尾的指针作为唯一标识

先来定义一下数据类型

typedef struct qnode{
	int data;
	struct qnode *next;
}Qnode;//这个其实就是个单链表 
typedef struct{
	Qnode *front;//指向单链表队头节点 
	Qnode *rear;//指向单链表队尾节点 
}LQueue;//链队头节点 
//队空条件:rear=NULL 
//队满条件:不考虑 
//进队e操作:将包含e的节点插入到单链表表尾 
//出队操作:删除单链表首数据节点 

链队列实现简单操作

  1. 初始化链队

    void InitLinkList(LinkList *&rear){
    	rear=NULL;
    } 
    
    
  2. 销毁一个链队 这个没有什么特别的,和上面类似

  3. 判断链队是否为空

    bool IsEmpty(LinkList *rear){
    	return rear==NULL;
    }
    
  4. 进队

    void enQueue(LinkList *&rear,int e){
    	LinkList *q;
    	q=(LinkList*)malloc(sizeof(LinkList));
    	//判断是否为空
    	q->data=e;
    	if(IsEmpty(rear)){
    		q->next=q;//自己指自己 
    		rear=q;
    	}
    	else{
    		q->next=rear->next;//这里,rear的next永远指着首节点 
    		rear->next=q;
    		rear=q; 
    		 
    	}
    }
    
  5. 出队

    bool deQueue(LinkList *&rear,int &e){
    	LinkList *q;
    	if(IsEmpty(rear))
    	return false;//队空 
    	if(rear->next==rear){//只有一个节点 
    		e=rear->data;
    		free(rear);rear=NULL;
    	}
    	else {
    		q=rear->next;
    		e=q->data;
    		rear->next=q->next;
    		free(q); 
    	} 
    	return true ;	
    }
    

完整代码

#include<stdlib.h>
#include<stdio.h>
typedef struct qnode{
	int data;
	qnode *next; 
}LinkList;
void InitLinkList(LinkList *&rear){
	rear=NULL;
} 
bool IsEmpty(LinkList *rear){
	return rear==NULL;
}
void enQueue(LinkList *&rear,int e){
	LinkList *q;
	q=(LinkList*)malloc(sizeof(LinkList));
	//判断是否为空
	q->data=e;
	if(IsEmpty(rear)){
		q->next=q;//自己指自己 
		rear=q;
	}
	else{
		q->next=rear->next;//这里,rear的next永远指着首节点 
		rear->next=q;
		rear=q; 
		 
	}
}
bool deQueue(LinkList *&rear,int &e){
	LinkList *q;
	if(IsEmpty(rear))
	return false;//队空 
	if(rear->next==rear){//只有一个节点 
		e=rear->data;
		free(rear);rear=NULL;
	}
	else {
		q=rear->next;
		e=q->data;
		rear->next=q->next;
		free(q); 
	} 
	return true ;	
}
int main(){
	LinkList *rear;
	int a[]{3,5,8,6,4},e;
	InitLinkList(rear);
	for(int i=0;i<5;i++){
		enQueue(rear,a[i]);
	}
	for(int i=0;i<3;i++){
		deQueue(rear,e);
		printf("%d ",e);
	}
}

我来要赞啦啊,如果觉得可以学到些什么的话就点个赞再走吧
欢迎各位路过的大佬评论指正

发布了50 篇原创文章 · 获赞 50 · 访问量 2713

猜你喜欢

转载自blog.csdn.net/weixin_45691686/article/details/104935113
今日推荐