《数据结构》队列的循序存储结构2019/9/11

在开始今天的笔记之前,想先谈一谈最近 

对于函数中指针和“return”的一点思考 

对于整个线性表来说,针对“插入”、“删除”等会改变  线表本身的操作,有两种的思路:

一种是通过return直接返回L,来确保函数内部对L的操作再函数外部也能实现;

另一种是通过再建立函数时,用*L做其形参,如此一来就不需要再占用return来返回L了,相反可以统一函数返回值的数据类型。

 

 

比如:对于链式存储的线性表获取其第K位置的元素这个操作来说。

第一种实现方式:

 

typedef struct LNode* PtrToLNode;
struct LNode{
	ElementType Data;
	PtrToLNode Next;
}; 
typedef PtrToLNode Position;
typedef PtrToLNode List;




//获取第K个位置的元素
 
#define ERROR -1 //一般定义为表中不可能取到的值

ElementType FindKth(List L,int K)
{
	Position p;
	int cnt=1;
	p=L;
	while (p&&cnt<k){
		p=p->Next;
		cnt++;
	}
	if((cnt==k)&&p){
		return p->Data;
	}
	else 
		return ERROR;//两个return出口并不一致,只能用define来自定义ERROR来保持一致。 
 } 

在这种实现方式中,两个return出口的类型并不一致。

 

第二种实现方式:

#define OK 1
#define ERROR 0
#define TURE 1
#define FALSE 0
typedef int Status;//Status是函数的类型,它的值是函数结果状态代码,比如OK、ERROR等。

//初始化
typedef struct Node{
	ElemType data;
	struct Node* next;
}Node;
typedef struct Node* List;
//获取第K个位置的元素
Status FindKth (List L,int K,ElementType e)
{
	List p;
	p=L;
	int cnt=1;
	while(p&&cnt<k){
		p=p->next;
		cnt++;
	}
	if((cnt==k)&&p){
		*e=p->data;
		return OK;
	}
	else
		return ERROR;
 } 

这种实现方式中两个return都是status类型的,出口一致。

 

 

 

队列 

队列和堆栈一样的是都是一种限制出口的线性表,不一样的是队列更加符合人们对于“排队”的认识,因为它是一种先进先出(First In First Out)  的线性表。他在比如:键盘键入、多程序同时运行时等场景都有应用。

队列在采用顺序存储结构的时候容易出现一种“假溢出”

  a3a4a5

                                                                           front                                                                              rear ? 

例如上图队列,此时如果在a5后面插入一个新元素,就会产生数组越界的错误,然而此时队列下边为0和1的地方还是空闲的。

这时候就有人提出利用“循环”的概念来定义循环队列

a6 a3a4a5

                                                                       rear         front

 

此时如何判别队列是空还是满就成了问题:当空的时候rear=front;然而当满的时候rear=front仍然成立,为什么会出现这种问题?因为rear-front最多只有n种情况(数组大小为n),而此时队列元素共有n+1个,所以仅仅依靠rear、front并不能完全覆盖所有情况,解决方法有两种:

第一种是另外再增加一个变量,比如可以增加一个记录当前队列元素个数的变量Size、或者是记录最后一次操作是入队还是出队的变量Flag,这两个变量都可以很容易的判别是否为满(因为此时的信息量已经足够满足n+1种情况了);

第二种方法是少用一个元素空间,当rear=front时就仅表示队列为空,而当队列中还有一个空间时,我们就人为的认为他已经满了(就像第二个表格示意的情况);

在第二个解决方法,判别是否为满仍有问题,因为虽说当rear和front在逻辑位置上相邻时,就代表了当前队列已满,但是rear指针有可能在front之后也有可能在front之前,front在前时,rear+1-front=QSIZE;当rear在前时,rear+1-front=0;所以队列满的条件就可以总结为:(rear+1)%QSIZE==front (QSIZE是当前队列的长度);

相应的计算队列长度的公式:(rear-front+QSIZE)%QSIZE

 

 

循环队列的顺序存储结构的实现 

定义:

typedef int Position;
typedef struct QNode* PtrToQNode;
struct QNode{
    ElementType *Data;
    Position Front,Rear;
    int MaxSize;
};
typedef PtrToQNode Queue;

创建:

Queue CreatQueue(int MaxSize)
{
    Queue Q=(Queue)malloc(sizeof(struct QNode));
    Q->Data=(ElementType*)malloc(MaxSize*sizeof(ElementType));//申请动态数组
    Q->Front=Q->Rear=0;
    Q-MaxSize=MaxSize;
    return Q;
}

初始化为空:

Status InitQueue(Queue Q)
{
    Q->Front=0;
    Q->Rear=0;
    return OK;
}

求队列长度:

int QueueLength(Queue Q)
{
    return (Q->Rear-Q->Front+MaxSize)%MaxSize;
}

入队:



Status EnQueue(Queue *Q,ElementType e)
{
    if((Q->Rear+1)%MaxSize==Q->Front)
        return ERROR;
    Q->Data[Q->Rear]=e;
    Q->Rear=(Q->Rear+1)%MaxSize;//rear指针向后移动一位置,若到最后则转到数组头部


    return OK;
}

出队:

Status DeQueue(Queue *Q,ElementType *e)
{
    if(Q->Front==Q->Rear)
        return ERROR;
    *e=Q->Data[Q->Front];
    Q->Front=(Q->Front+1)%MaxSize;//front指针向后移动一位置,若到最后则转到数组头部
    return OK;
}

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值