在开始今天的笔记之前,想先谈一谈最近
对于函数中指针和“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) 的线性表。他在比如:键盘键入、多程序同时运行时等场景都有应用。
队列在采用顺序存储结构的时候容易出现一种“假溢出”
a3 | a4 | a5 |
front rear ?
例如上图队列,此时如果在a5后面插入一个新元素,就会产生数组越界的错误,然而此时队列下边为0和1的地方还是空闲的。
这时候就有人提出利用“循环”的概念来定义循环队列 :
a6 | a3 | a4 | a5 |
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;
}