1.0写在前面(关于队列)
本来还想写一个队列的但是,队列其实和栈差不多,队列就是先入先出,栈就是先入后出,感觉没什么好写,就水一下算惹~。唯一需要注意的是,栈如何判断满员等问题。一般可以用循环队列解决。本文以栈为主。
队列和栈一样支持pop和push两个操作,但是与栈不同,pop完成的不是取出最顶端的元素,而是取出最底端的元素。也就是说最初放入的元素能够最先被取出(这点刚好和栈相反)
// 队列的顺序存储结构(循环队列)
#define MAX_QSIZE 5 // 最大队列长度+1
typedef struct {
int *base; // 初始化的动态分配存储空间
int front; // 头指针,若队列不空,指向队列头元素
int rear; // 尾指针,若队列不空,指向队列尾元素的下一个位置
} SqQueue;
// 构造一个空队列Q
SqQueue* Q_Init() {
SqQueue *Q = (SqQueue*)malloc(sizeof(SqQueue));
// 存储分配失败
if (!Q){
exit(OVERFLOW);
}
Q->base = (int *)malloc(MAX_QSIZE * sizeof(int));
// 存储分配失败
if (!Q->base){
exit(OVERFLOW);
}
Q->front = Q->rear = 0;
return Q;
}
// 销毁队列Q,Q不再存在
void Q_Destroy(SqQueue *Q) {
if (Q->base)
free(Q->base);
Q->base = NULL;
Q->front = Q->rear = 0;
free(Q);
}
// 将Q清为空队列
void Q_Clear(SqQueue *Q) {
Q->front = Q->rear = 0;
}
// 若队列Q为空队列,则返回1;否则返回-1
int Q_Empty(SqQueue Q) {
if (Q.front == Q.rear) // 队列空的标志
return 1;
else
return -1;
}
// 返回Q的元素个数,即队列的长度
int Q_Length(SqQueue Q) {
return (Q.rear - Q.front + MAX_QSIZE) % MAX_QSIZE;
}
// 若队列不空,则用e返回Q的队头元素,并返回OK;否则返回ERROR
int Q_GetHead(SqQueue Q, int &e) {
if (Q.front == Q.rear) // 队列空
return -1;
e = Q.base[Q.front];
return 1;
}
// 打印队列中的内容
void Q_Print(SqQueue Q) {
int p = Q.front;
while (Q.rear != p) {
cout << Q.base[p] << endl;
p = (p + 1) % MAX_QSIZE;
}
}
// 插入元素e为Q的新的队尾元素
int Q_Put(SqQueue *Q, int e) {
if ((Q->rear + 1) % MAX_QSIZE == Q->front) // 队列满
return -1;
Q->base[Q->rear] = e;
Q->rear = (Q->rear + 1) % MAX_QSIZE;
return 1;
}
// 若队列不空,则删除Q的队头元素,用e返回其值,并返回1;否则返回-1
int Q_Poll(SqQueue *Q, int &e) {
if (Q->front == Q->rear) // 队列空
return -1;
e = Q->base[Q->front];
Q->front = (Q->front + 1) % MAX_QSIZE;
return 1;
}
队列的应用
队列的应用其实有很多,最常见的就是排队的问题,排队实际上就是一个队列,先进先出。比如说银行排队等等,由于更加贴近我们平时的生活,理解起来应该也不难。
1.1栈的定义
栈(stack) 是限定仅在表尾进行插入或删除操作的线性表。因此,对栈来说,表断有其特殊的含义,称为栈顶,相应的表底称为栈底,不含元素的称为空栈。
栈又称为后进先出 的线性表(LIFO结构);结构如下:
1.2栈的基本操作
Status InitStack(SqStack &S);//构造一个空栈
Status DestroyStack(SqStack &S);//摧毁一个栈
Status ClearStack(SqStack &S);//把栈置空
Status StackEmpty(SqStack S);//判断是否为空栈
Status StackLength(SqStack S);//返回栈的长度
Status GetTop(SqStack S, SElemType &e);//返回栈顶的元素
Status Push(SqStack &S, SElemType e);//插入新元素到栈顶
Status Pop(SqStack &S, SElemType &e);//从栈顶弹出一个元素
Status StackTraverse(SqStack S, Status(*visit));//从栈底依次对每个元素调用visit,一旦visit失败,则操作失败
1.3栈的常用基本操作的实现
1.3.1数据类型的定义
这里为了方便操作将元素类型定义为int类型,具体使用过程中,可以是其他数据类型。
#define OVERFLOW 0
#define OK 1
#define TRUE 1
#define FALSE 0
#define ERROR 0
typedef int ElemType;
typedef int Status;
typedef struct {
ElemType *base; //栈底
ElemType *top; //栈顶指针
int stacksize; //当前已分配的存储空间
} SqStrack;
1.3.2构造一个空栈(InitStack)
初始化让栈的顶部等于底部,即
top == base
就可以判定为此栈为空,也就是初始化空栈,当其他需要判定是否为空栈的时候也可以使用这种方法来判断。
Status InitStack(SqStack *S) {
S->base = (ElemType *)malloc(sizeof(ElemType));
if (!S->base) {
exit(OVERFLOW);
} //申请失败
S->top = S->base;
S->stacksize = 1;
return OK;
}
1.3.3插入一个元素为栈顶元素(Push)
当插入一个新元素的时候需要注意如果内存空间不够需要重新申请空间,否则会插入失败,同时也要注意栈顶的指针向后移动一个位置, 即
*S.top = e; S.top++;
或者写作*S->top++ = e;
Status Push(SqStack *S, ElemType e) {
//将新的元素e插入到栈顶
if (S->top - S->base >= S->stacksize) {
S->base =
(ElemType *)realloc(S->base, (S->stacksize + 1) * sizeof(ElemType));
if (!S->base) {
exit(OVERFLOW);
}
S->top = S->base + S->stacksize;
S->stacksize = S->stacksize + 1;
} //如果空间不够就重新申请空间
*S->top++ = e;
return OK;
}
1.3.4弹出栈顶元素并返回(Pop)
这里需要注意判断栈是否为空,如果为空就不能成功返回值。判定方法和上面1.3.2提到的一样。
Status Pop(SqStack *S, ElemType *e) {
//若栈不为空,则弹出栈顶的元素,否则返回空栈
if (S->top == S->base