队列--c语言顺序实现“循环队列”

队列(Queue):和栈类似同样是受限的线性表,区别在于队列只允许在一端插入,在另一端删除,称为先进先出表FIFO;

定义:
        · 队列(Queue)简称为“队”,也是一种受限的线性表。只允许在线性表的一端进行插入,在另一端进行删除;
        · 称插入数据的一端为队尾(rear),称删除数据的一端为队首(front);向队尾添加数据称为入队,新入队的元素称为队尾元素;在队列中删除元素称为出队,元素出队后它的后续元素称为新的队首元素
        · 双端队列:允许在两端进行插入和删除;相应的还有输入受限的双端队列和输出受限的双端对列;只要栈能做到的双端队列同样可以做到
        · 队列的抽象数据类型定义:
            ADT Queue{
                数据对象 : D={a0,a1,a2...,an, 其中ai(i=1,2..n)是同一种数据类型的元素}
                数据关系 : R={<ai,ai+1>}
                数据操作 :
                    InitQueue(&Q):        初始化队列
                    DestroyQueue(&Q):    销毁队列
                    ClearQueue(&Q):        清空队列
                    IsEmpty(Q):            队列判空
                    GetSize(Q):            返回队列长度
                    GetHead(Q):            查看队头
                    GetTail(Q):            查看队尾
                    EnQueue(&Q,e):        入队
                    DeQueue(&Q,&e):        出队
                    Traverse(Q):        遍历队列
            }

队列的顺序存储实现:
    *在队列的顺序实现中,一般将队列设置为一个逻辑上的圆环,这种队列称为“循环队列”,通常用循环数组实现来实现;

    *循环队列中,通常会设置两个指针,front头指针和rear尾指针;

    *在元素入队时,将新入队的元素保存到rear指向的单元,然后rear指针后移;在出队时,将队首指针front指向的元素返回,然后front后移

    *在这种循环队列中,队空是指,front和rear指向同一个单元;队满也是front和rear指向同一个单元,怎么区分队空和队满呢?
    一般用这3种方式:
        - 队列中定义一个size属性,如果size等于数组容量,则为队满;
        - 或者数组最后一个单元不存放元素,当(rear+1)%capacity==队首,则队满                                    - 队空则头尾指针为-1,队满则(q.rear-q.front+MaxSize)%MaxSize +1等于队列最大容量MaxSize。

代码实现:(这里区分队空队满采用的第三种方式)

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

#define ElemType int
//队列容量固定10
#define MaxSize 10

typedef struct Queue{
	ElemType *data;
	int front;
	int rear;
}Queue;

// InitQueue(&Q):		初始化队列
void InitQueue(Queue* q){
	//申请一片容量为MaxSize大小的连续空间
	q->data = (ElemType*)malloc(MaxSize * sizeof(ElemType));
	if(q->data == NULL){ exit(1); }

	q->front = -1;
	q->rear = -1;
}

// DestroyQueue(&Q):	销毁队列
void DestroyQueue(Queue* q){
	//释放申请的内存
	free(q->data);
	//置空指针
	q->data = NULL;
	q->front = -1;
	q->rear = -1;
}

// ClearQueue(&Q):		清空队列
void ClearQueue(Queue* q){
	q->front = -1;
	q->rear = -1;
}

// IsEmpty(Q):			队列判空
int IsEmpty(Queue q){
	return q.front == -1;
}

// GetSize(Q):			返回队列长度
int GetSize(Queue q){
	if(q.front == -1){
		return 0;
	}else{
		return (q.rear-q.front+MaxSize)%MaxSize +1;
	}
}

// GetHead(Q):			查看队头
ElemType GetHead(Queue q){
	if(q.front == -1){ exit(1); }//队空,获取失败,退出程序
	return q.data[q.front];//返回队头元素
}

// GetTail(Q):			查看队尾
ElemType GetTail(Queue q){
	if(q.front == -1){ exit(1); }//队空,获取失败,退出程序
	return q.data[q.rear];//返回队尾元素
}

// EnQueue(&Q,e):		入队
void EnQueue(Queue* q, ElemType e){
	if(GetSize(*q) == MaxSize){ exit(1); }//队满,入队失败

	//如果此时队空,那么头尾指针都是-1,入队前要改头尾指针
	if(q->front == -1){
		q->rear = 0;
		q->front = 0;
	}else{//否则只改尾指针即可
		q->rear = (q->rear+1)%MaxSize;
	}
	q->data[q->rear] = e;
}

// DeQueue(&Q,&e):		出队,并返回该元素
ElemType DeQueue(Queue* q){
	if(GetSize(*q) == 0){ exit(1); }//队空出队失败

	//保存队头元素
	ElemType ret = q->data[q->front];

	//如果队头队尾指针相等,说明队中元素就一个,队后应该将队头队尾设置为-1
	if(q->rear == q->front){
		q->front = -1;
		q->rear = -1;
	}else{
		//更新队头指针
		q->front = (q->front+1)%MaxSize;
	}
	return ret;
}

// Traverse(Q):			遍历队
void Traverse(Queue q){
	printf("\n");
	int i, j;
	j = q.front;
	for( i=1; i<=GetSize(q); i++ ){
		printf("%d  ", q.data[j]);
		j = (j+1)%MaxSize;
	}
	printf("\n");
}

int main(int argc, char const *argv[])
{
	Queue q;
	InitQueue(&q);
	Traverse(q);

	EnQueue(&q, 2);
	EnQueue(&q, 12);
	EnQueue(&q, 22);
	EnQueue(&q, 32);
	EnQueue(&q, 42);
	EnQueue(&q, 52);
	EnQueue(&q, 62);
	EnQueue(&q, 72);
	Traverse(q);
	printf("size==%d\n", GetSize(q));
	printf("IsEmpty:%d\n", IsEmpty(q));
	printf("head:%d\n", GetHead(q));

	DeQueue(&q);
	DeQueue(&q);
	DeQueue(&q);
	DeQueue(&q);
	printf("head:%d\n", GetHead(q));
	Traverse(q);

	DeQueue(&q);
	DeQueue(&q);
	DeQueue(&q);
	DeQueue(&q);
	printf("size==%d\n", GetSize(q));

	DestroyQueue(&q);
	Traverse(q);
	printf("IsEmpty:%d\n", IsEmpty(q));
	return 0;
}

运行结果:

代码不够完善,欢迎评论补充^0^

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值