数据结构——队列的循环顺序存储(优缺点及代码实现:C语言)

队列

队列是运算受限的线性表,和线性表一样也是线性结构,只不过插入只能在队尾插入称为入队,删除只能在队头删除称为出队,和日常生活中的排队顺序一样,是先进先出(FIFO)的线性表。队列存储结构分为顺序存储和链式存储,本文主要介绍最常用的 循环顺序存储队列.

溢出现象

当队空的时候出队 就会产生下溢;
上溢分为真上溢和假上溢,真上溢:当队满的时候入队会产生真上溢。
假上溢主要发生在当入队和出队操作,头指针指增加不减少,致使被删除元素的空间永远无法被利用,当队列中实际元素个数远远小于向量空间的规模时,也有可能超越向量空间的上界而不能做入队操作,那么这种现象就称之为“假上溢”现象.
为了解决假上溢现象,引入循环队列(放弃一个结点空间,当rear+1达到 MAXSIZE时,将rear重新指向 “队头” 已出队那一端)
优点:
节省存储空间:循环顺序存储结构可以利用数组来存储队列元素,不需要额外的指针空间,节省了存储空间。
操作简单高效:循环顺序存储结构可以通过数组的下标来直接访问队列元素,操作简单高效,插入和删除操作的时间复杂度为O(1)。
缺点:
需要预先确定队列的最大长度:循环顺序存储结构需要预先确定队列的最大长度,如果队列长度超出预设长度,需要进行扩容操作,可能会导致元素搬移,影响性能。
需要处理循环队列的溢出问题:循环顺序存储结构需要处理循环队列的溢出问题,即队列头尾指针相遇时的处理,可能会增加代码的复杂度。

代码实现(C语言)

定义

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

#define MAXSIZE 100
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2

typedef int Status;
typedef  int DataType;

typedef struct{
	DataType *data;  
	int front;   //队头
	int rear;   //队尾
}SeqQueue;

初始化

Status InitQueue(SeqQueue *Q)
{
	Q->data = (DataType *)malloc(sizeof(DataType) * MAXSIZE);//申请内存结点
	if(!Q->data)  //如果申请失败
		exit(OVERFLOW);
	Q->front = Q->rear = 0;   
	return OK;
}

判队空

Status IsEmpty(SeqQueue *Q)
{
	return Q->front == Q->rear;  //头指针和尾指针相等时 队空
}

判队满

Status IsFull(SeqQueue *Q)
{
	return (Q->rear+1) % MAXSIZE == Q-> front; //队满条件 (有一个结点空间没有使用,另外一种方法是设置一个计数器,入队计数器+1,判队满就是看计数器和MAXSIZE相不相等)
}

求队列长度

int GetLength(SeqQueue *Q)
{
	return (Q->rear - Q->front + MAXSIZE) % MAXSIZE;
}

入队

时间复杂度O(1)

Status EnQueue(SeqQueue *Q,DataType x)
{
	if(IsFull(Q)) //队满返回 TRUE 1
	{
		printf("队满,不能入队!")
		return ERROR;
	}
	Q->data[Q->rear] = x;    //入队元素赋值
	Q->rear = (Q->rear +1) % MAXSIZE;  //队尾指针 + 1 
	return OK; 
}

出队

时间复杂度O(1)

Status DeQueue(SeqQueue *Q, DataType *x)
{
	if(IsEmpty(Q))
	{
		printf("队空不能出队!");
		return ERROR;
	}
	*x = Q->data[Q->front];  //队头指针的元素值取出来
	Q->front = (Q->front +1) % MAXSIZE;
	return OK;
}

取队头元素

DataType GetHead(SeqQueue *Q)
{
	if(IsEmpty(Q))
	{
		printf("队空不能取队头!");
		return ERROR;
	}
	return Q->data[Q->front];
}

显示队中所有元素

void ShowQueue(SeqQueue *Q)
{
	int p =Q->front;
	if(p == Q->rear)
		printf("队空,无元素!");
	else
	{
		printf("从队头起,队列中各元素为:");
		while(p != Q->rear)
		{
			printf("%5d",Q->data[p]);
			p++;
		}
	}
}

完整示例(C语言实现)

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

#define MAXSIZE 100
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2

typedef int Status;
typedef  int DataType;

typedef struct{
	DataType *data;
	int front;   //队头
	int rear;   //队尾
}SeqQueue;


//初始化队列
Status InitQueue(SeqQueue *Q)
{
	Q->data = (DataType *)malloc(sizeof(DataType) * MAXSIZE);
	if(!Q->data)
		exit(OVERFLOW);
	Q->front = Q->rear =0;
	return OK;
}


//判队空
Status IsEmpty(SeqQueue *Q)
{
	return Q->front == Q->rear;
}


//判队满
Status IsFull(SeqQueue *Q)
{
	return (Q->rear + 1) % MAXSIZE == Q->front; 
}


//求队列长度
int GetLength(SeqQueue *Q)
{
	return (Q->rear - Q->front + MAXSIZE) % MAXSIZE; 
}


//入队
Status EnQueue(SeqQueue *Q, DataType x)
{
	if(IsFull(Q))
	{
		printf("队满,不能入队元素!");
        return ERROR;
	}
	Q->data[Q->rear] = x;
	Q->rear = (Q->rear + 1) % MAXSIZE;
	return OK;
}

//出队
Status DeQueue(SeqQueue *Q, DataType *x)
{
	if(IsEmpty(Q))
	{
		printf("队空,不能出队元素!");
		return ERROR;
	}
	*x = Q->data[Q->front];
	Q->front = (Q->front+ 1) %MAXSIZE;
	return OK;
}

//取队头元素
DataType GetHead(SeqQueue *Q)
{
	if(IsEmpty(Q))
	{
		printf("队空,不能取队头元素!");
		return ERROR;
	}
	return Q->data[Q->front];
}

//显示队中所有元素

void ShowQueue(SeqQueue  *Q)
{
	int p =Q->front;
	if(p == Q->rear)
		printf("队列为空,无元素!\n");
	else
	{
		printf("从队头起,队列中各元素为:");
		while(p != Q->rear)
		{
			printf("%5d",Q->data[p]);
			p++;
		}
	}
}

// 显示菜单子函数
void  Menu()                                    
{  
	printf("\n                  顺序队列的各种操作");
    printf("\n =================================================");  
    printf("\n|               1——初始化队列                  |");
    printf("\n|               2——判队空                      |");
    printf("\n|               3——判队满                      |");
    printf("\n|               4——求队列长度                  |");
    printf("\n|               5——入队操作                    |");
    printf("\n|               6——出队操作                    |");
    printf("\n|               7——求队头元素                  |");
    printf("\n|               8——显示队中所有元素            |");
    printf("\n|               0——返回                        |");
    printf("\n ================================================="); 
    printf("\n请输入菜单号(0-8):"); 	
}

int main() {
    int i, n, flag;
    SeqQueue Q;
    DataType x;
    char ch1, ch2, a;
    ch1 = 'y';

    while (ch1 == 'y' || ch1 == 'Y') {
        Menu();
        scanf("%c", &ch2);
        getchar();

        switch (ch2) {
            case '0':
                ch1 = 'n';
                break;
            case '1':
                InitQueue(&Q);
                printf("队列的初始化完成!\n");
                break;
            case '2':
                if (IsEmpty(&Q))
                    printf("队列为空!\n");
                else
                    printf("队列不为空!\n");
                break;
            case '3':
                if (IsFull(&Q))
                    printf("队列已满!\n");
                else
                    printf("队列未满!\n");
                break;
            case '4':
                printf("队列的长度为:%d\n", GetLength(&Q));
                break;
            case '5':
                printf("请输入要入队的元素个数:");
                scanf("%d", &n);
                printf("请输入%d个入队的整数:", n);
                for (i = 0; i < n; i++) {
                    scanf("%d", &x);
                    flag = EnQueue(&Q, x);
                }
                if (flag == 1)
                    printf("入队操作成功!\n");
                else
                    printf("入队操作失败!\n");
                break;
            case '6':
                printf("请输入要出队的元素个数:");
                scanf("%d", &n);
                printf("出队的元素顺序依次为:");
                for (i = 0; i < n; i++) {
                    flag = DeQueue(&Q, &x);
                    printf("%5d", x);
                }
                if (flag == 1)
                    printf("\n出队操作成功!\n");
                else
                    printf("\n出队操作失败!\n");
                break;
            case '7':
                x = GetHead(&Q);
                printf("当前的队头元素值为:%d\n", x);
                break;
            case '8':
                ShowQueue(&Q);
                break;
            default:
                printf("输入有误,请输入0-8进行选择!\n");
        }

        if (ch2 != '0') {
            printf("\n按回车键继续,按任意键返回主菜单!\n");
            a = getchar();
            if (a != '\n') {
                getchar();
                ch1 = 'n';
            }
        }
    }

    return 0;
}

结语

循环顺序队列:
空队列 Q->front ==Q->rear
满队列 (Q->rear+1)%MAXSIZE
队长 (Q->rear -Q->front +MAXSIZE) %MAXSIZE

敬请各位大佬批评指正 日后也会持续更新数据结构相关内容,互相学习😊😊
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值