栈(Stack)
栈的基本概念
- 栈:只允许在一端进行插入或删除的线性表
- 后进先出(Last in First out,LIFO)
- 栈的结构:
- 栈顶(Top):允许进行插入和删除的一端
- 栈底(Bottom):固定的,不允许进行插入和删除的一端
- 因为栈本质上也是线性表,所以有顺序储存和链式储存两种储存方式
顺序栈的定义与基本操作
顺序栈的定义
typedef int ElemType;
#define MaxSize 10
typedef struct{
ElemType data[MaxSize];
int top;
}SeqStack;
初始化顺序栈以及栈的判空
void InitStack(SeqStack *S){
S->top = -1;
}
bool StackEmpty(SeqStack *S){
if (S->top == -1) {
return true;
}
return false;
}
入栈操作
bool Push(SeqStack *S, ElemType e){
if (S->top == MaxSize-1) {
return false;
}
S->data[++S->top] = e;
return true;
}
出栈操作
bool Pop(SeqStack *S,ElemType *e){
if (S->top == -1) {
return false;
}
*e = S->data[S->top--];
return true;
}
读取栈顶元素
bool GetTop(SeqStack *S,ElemType *e){
if (S->top == -1) {
return false;
}
*e = S->data[S->top];
return true;
}
- 读取栈顶元素与出栈操作惟一的区别就在于:出栈需要将指针-1,而读取栈顶元素不需要
链栈的定义与基本操作
- 基本概念:栈的链式存储,采用单链表实现,并规定所有操作都是在单链表的表头进行
链栈的定义
typedef int ElemType;
typedef struct LinkNode{
ElemType data;
struct LinkNode *next;
}*LStack;
初始化链栈
LStack InitStack(void){
LStack L = (LNode *)malloc(sizeof(LNode *));
L->next = NULL;
return L;
}
int main(int argc, const char * argv[]) {
LStack L = NULL;
return 0;
}
入栈操作
bool Push(LStack L,ElemType e){
LNode *p = (LNode *)malloc(sizeof(LNode));
if (p == NULL) {
return false;
}
p->data = e;
p->next = L->next;
L->next = p;
return true;
}
出栈操作
bool Pop(LStack L,ElemType *e){
if (StackEmpty(L)) {
return false;
}
LNode *p = L->next;
*e = p->data;
L->next = p->next;
free(p);
return true;
}
队列(Queue)
队列的基本概念
- 队列:只允许在一端进行插入另一端进行删除线性表
- 先进先出(First in First out,FIFO)
- 队列的结构:
- 对头(Front):允许进行删除的一端
- 队尾(Rear):允许进行插入的一端
- 因为队列本质上也是线性表,所以有顺序储存和链式储存两种储存方式。
顺序循环队列的定义与基本操作(队列的顺序存储)
顺序循环队列的定义
typedef int ElemType;
#define MaxSize 10
typedef struct{
ElemType data[MaxSize];
int front,rear;
}SeqQueue;
初始化顺序循环队列以及队列的判空
SeqQueue InitQueue(void){
SeqQueue Q;
Q.front = 0;
Q.rear = 0;
return Q;
}
bool QueueEmpty(SeqQueue *Q){
if (Q->front == Q->rear ) {
return true;
}else{
return false;
}
}
入队操作
bool EnQueue(SeqQueue *Q,ElemType e){
if ((Q->rear+1)%MaxSize == Q->front) {
return false;
}
Q->data[Q->rear] = e;
Q->rear = (Q->rear+1)%MaxSize;
return true;
}
- 这里要注意的是:当队尾元素到data[MaxSize]时,可能因为对头元素出队导致空间其实并没有被填满,这时就需要对队尾进行取余%操作使其跳到第一个位置,这样的话在逻辑上看就是一个循环的结构(这也就是为什么此结构要叫做循环顺序队列)
- 因为我们是通过比较队头和队尾是否在同一个位置上来判断队列是否为空的,所以我们可以通过舍弃数组上的一个储存单元的方式辅助判断,当对位指向最后一个单元时就认为此队列已经被填满了。
出队操作
bool DeQueue(SeqQueue *Q,ElemType *e){
if (QueueEmpty(Q)) {
return false;
}
*e = Q->data[Q->front];
Q->front = (Q->front+1)%MaxSize;
return true;
}
链式队列的定义与基本操作
链式队列的定义
typedef int ElemType;
typedef struct LinkNode{
ElemType data;
struct LinkNode *next;
}LinkNode;
typedef struct LinkQueue{
LinkNode *front,*rear;
}LinkQueue;
初始化链式队列以及队列的判空
void InitLinkQueue(LinkQueue *Q){
LinkNode *p = (LinkNode *)malloc(sizeof(LinkNode));
p->next = NULL;
Q->front = p;
Q->rear = p;
}
bool QueueEmpty(LinkQueue Q){
if (Q.front == Q.rear) {
return true;
}
return false;
}
入队操作
bool EnQueue(LinkQueue *Q,ElemType e){
LinkNode *p = (LinkNode *)malloc(sizeof(LinkNode));
if (p == NULL) {
return false;
}
p->data = e;
p->next = NULL;
Q->rear->next = p;
Q->rear = p;
return true;
}
出队操作
bool DeQueue(LinkQueue *Q,ElemType *e){
if (QueueEmpty(*Q)) {
return false;
}
LinkNode *p = Q->front->next;
*e = p->data;
Q->front->next = p->next;
free(p);
if (Q->front->next == NULL) {
Q->rear = Q->front;
}
return true;
}