说明:
学习内容根据b站王卓老师视频学习记录
参考地址第02周08--2.4线性表的顺序表示和实现3_哔哩哔哩_bilibili
目录
定义:栈和队列是限定插入和删除只能在表的“端点”进行的线性表。
栈:(装电池的手电筒电池的排列)后进先出,只能在队尾删除和插入;
队列:(排队)先进先出,只能在队尾插入,在队头删除。
栈:
表尾(即端)称为栈顶 Top;表头(即端)称为栈底 Base。
“入”栈 = PUSH “出”栈 = POP
空栈的表示:base == top;
栈满的表示:top - base == stacksize;
顺序栈的表示和实现:
上溢(overflow):栈已经满,又要压入元素;
下溢(underflow):栈已经空,还要弹出元素。
- 设置top指针,指示栈顶元素在顺序表栈中的位置。
注:为了方便操作,通常top指示真正的栈顶元素之上的下标地址- 另设base指针,指示栈底元素在顺序栈中的位置。
- 用stacksize表示栈可用的最大容量
存储结构:
typedef char SElemType; typedef struct { SElemType *base; //栈底指针 SElemType *top; //栈顶指针 int stacksize; //栈可用的最大容量 }SqStack;
初始化:
- 创建一个空栈,并使栈的头指针 top 和尾指针 base 相等;
//顺序栈的初始化 //创造一个空栈 Status InitStack(SqStack &S){ //分配储存空间 S.base = new SElemType[MAXSIZE]; //或 S.base = (SElemType *)malloc(MAXSIZE * sizeof(SElemType)); if (!S.base) return OVERFLOW; //储存分配失败 S.top = S.base; //栈顶指针等于栈底指针 S.stacksize = MAXSIZE; return OK; }
判断顺序栈是否为空:
- 若栈为空,返回TRUE;否则返回FALSE(TRUE和FALSE在.h中已经做了定义)
//判断顺序栈是否为空 //若栈为空,返回TRUE;否则返回FALSE Status StackEmpty(SqStack S){ if (S.top == S.base){ return TRUE; } else{ return FALSE; } }
求顺序栈的长度:
- 顺序栈的头指针 top 和尾指针 base 相减得到的数值
//求顺序栈的长度 int StackLength(SqStack S){ return S.top - S.base; }
清空顺序栈:
- 使栈里的头指针 top 和尾指针 base 再次相等即可,无需删除释放栈里的元素数值;
//清空顺序栈 Status ClearStack(SqStack S){ if (S.base){ //判断栈是否存在 S.top = S.base; } return OK; }
销毁顺序栈:
- 直接销毁顺序栈,使顺序栈里的元素以及存储空间释放
//销毁顺序栈 Status DestroyStack(SqStack &S){ if (S.base){ delete S.base; S.stacksize = 0; S.base = S.top = NULL; } return OK; }
顺序栈的入栈:
- 判断是否满栈,若满栈则会出错(溢出)
- 元素e压入栈顶
- 栈顶指针加1
//顺序栈的入栈 Status Push(SqStack &S,SElemType e){ if (S.top - S.base == S.stacksize){ //判断是否栈满 return ERROR; } *S.top++ = e; //等同于*S.top = e; S.top++; return OK; }
顺序栈的出栈:
- 判断是否为空栈,若空则出错(下溢)
- 获取栈顶元素e
- 栈顶指针减1
//顺序栈的出栈 Status Pop(SqStack &S,SElemType &e){ if (S.top == S.base){ //等价于if(StackEmpty(S)) return ERROR; } e = *--S.top; //等价于--S.top; e = *S.top; }
链栈的表示和实现:
- 链栈的指针指针域的指向和普通链表不一样,在链栈中指针域指向的是前一个元素
- 例子: 指向。
- 链栈只有尾指针(指向链表的尾部)
- 链栈没有头结点
存储结构:
typedef struct StackNode{ SElemType data; //创建数据域 struct StackNode *next; //创建指针域 }StackNode,*LinkStack;
链栈的初始化:
- 构建一个空栈,栈顶指针置为空
//链栈的初始化 Status InitStack(LinkStack &S){ S = NULL; return OK; }
判断链栈是否为空:
- 使尾指针为空
//判断链栈是否为空 Status StackEmpty(LinkStack S){ if (S == NULL){ return TRUE; } else{ return FALSE; } }
链栈的入栈:
- 插入一个新元素到链表的尾部(栈顶)
//链栈的入栈 Status Push(LinkStack &S,SElemType e){ StackNode *p = new StackNode ; //生成新结点p p->data = e; //将新结点数据域置为e p->next = S; //将新结点插入栈顶 S = p; //修改栈顶指针 return OK; }
链栈的出栈:
- 从链栈的栈顶删除一个元素
//链栈的出栈 Status Pop(LinkStack &S,SElemType &e){ if (S == NULL){ //链栈存在 return ERROR; } e = S->data; StackNode *p = S; S = S->next; delete p; return OK; }
获取栈顶元素:
- 得到链栈栈顶元素的值,并返回。
SElemType GetTop(LinkStack S){ if (S != NULL){ return S->data; } }
队列(queue):
队列也和栈一样,也区分顺序队列和链式队列。
顺序队列:
循环队列解决队满时判断方法——设置一个标志;
循环队列解决队满时判断方法——用count计数;
循环队列解决队满时判断方法——少用一个元素空间:队空:front == rear;
队满:(rear + 1) %MAXQSIZE == front;存储结构:
typedef struct { QElemType *base; //初始化的动态分配储存空间 int front; //头指针 int rear; //尾指针 }SqQueue;
队列的初始化:
- 创建一个空队列
//队列的初始化 Status InitQueue(SqQueue &Q){ Q.base = new QElemType [MAXQSIZE]; //分配数组空间 //或 Q.base = (QElemType *)malloc(MAXQSIZE * sizeof(QElemType)); if (!Q.base){ //存储分配失败 return ERROR; } Q.front = Q.rear = 0; //头指针尾指针置为0,队列为空 return OK; }
求队列的长度:
//求队列的长度 int QueueLength(SqQueue Q){ //防止尾指针在头指针下面这种情况发生 return ((Q.rear - Q.front + MAXQSIZE)%MAXQSIZE); }
循环队列入队:
//循环队列入队 Status EnQueue(SqQueue &Q,QElemType e){ if ((Q.rear + 1)%MAXQSIZE == Q.front){ //判断是否队满 return ERROR; } Q.base[Q.rear] = e; //新元素加入队尾 Q.rear = (Q.rear + 1)%MAXQSIZE; //队尾指针+1 return OK; }
循环队列出队:
//循环队列出队 Status DeQueue(SqQueue &Q,QElemType &e){ if (Q.front == Q.rear){ //判断队列是否为空 return ERROR; } e = Q.base[Q.front]; //保存队头元素 Q.front = (Q.front + 1)%MAXQSIZE; //队头指针+1 return OK; }
取队头元素:
//取队头元素 QElemType GetHead(SqQueue Q){ if (Q.front != Q.rear){ //队列不为空 return Q.base[Q.front]; //返回队头指针元素的值,队头指针不变 } }
链队列:
存储结构:
typedef struct QNode{ QElemType data; struct Qnode *next; }QNode,*QueuePtr; typedef struct { QueuePtr front; //队头指针 QueuePtr rear; //队尾指针 }LinikQueue;
链队列初始化:
//链队列的初始化 Status InitQueue(LinkQueue &Q){ Q.front = Q.rear = new QNode; //或Q.front = Q.rear = (QueuePtr)malloc(sizeof (QNode)); if (!Q.front){ return OVERFLOW; } Q.front->next = NULL; return OK; }
销毁链队列:
- 从头结点开始,依次释放所有结点
//销毁链队列 Status DestroyQueue(LinkQueue &Q){ while (Q.front){ QNode *p = Q.front->next; delete(Q.front); Q.front = p; //或Q.rear = Q.front->next; // free(Q.front); // Q.front = Q.rear; } return OK; }
链队列的入队:
- 将元素e入队
//链队列的入队 Status EnQueue(LinkQueue &Q,QElemType e){ QNode *p = new QNode; if (!p){ return OVERFLOW; } p->data = e; p->next = NULL; Q.rear->next = p; Q.rear = p; return OK; }
链队列出队:
//链队列的入队 Status DeQueue(LinkQueue &Q,QElemType &e){ if (Q.front == Q.rear){ return OVERFLOW; } QNode *p; p = Q.front->next; e = p->data; Q.front->next = p->next; if (Q.rear == p){ Q.rear = Q.front; } delete p; return OK; }
求链队列的队头元素:
//求链队列的队头元素 Status GetHead(LinkQueue Q,QElemType &e){ if (Q.front == Q.rear){ return ERROR; } e = Q.front->next->data; return OK; }
第二章完结。