一. 栈的定义
1. 栈的定义及术语
栈(stack)是只允许在一端进行插入或删除操作的线性表。
①栈顶:允许增删的一端
②栈底:不允许插入删除的一端
③空栈:空的线性表
Last In First Out 后进先出(LIFO)
n个不同元素进栈,出栈元素不同排列的个数为(卡特兰数)
满了再放=上溢,空了再取=下溢
二. 顺序栈的实现
1. 顺序栈的初始化
/*顺序栈的初始化*/
#define MaxSize 10
typedef struct {
ElemType data[MaxSize];
int top;//栈顶指针,指向栈顶元素的数组下标
}SqStack;
void InitStack(SqStack& S) {
S.top = -1;
}
2 .判空
/*判空*/
bool StackEmpty(SqStack S) {
return(S.top == -1);
}
3. 新元素入栈
/*新元素入栈*/
bool Push(SqStack& S, ElemType e) {
if (S.top == MaxSize - 1)return false;//栈满
//下面两行可以简化为S.data[++S.top] = e;
S.top += 1;
S.data[S.top] = e;
return true;
}
4. 出栈操作
没有用malloc申请内存空间,所以不必手动释放。系统自动回收内存
/*出栈操作*/
bool Pop(SqStack& S, ElemType& e) {
if (S.top == -1)return false;
//下面两行可以简化为e=S.data[S.top--];
e = S.data[S.top];
S.top -= 1;
return true;//没有用malloc申请内存空间,所以不必手动释放。系统自动回收内存
}
5. 读栈顶元素
/*读栈顶元素*/
bool GetTop(SqStack S, ElemType& e) {
if (S.top == -1)return false;
e = S.data[S.top];
return true;
}
6. 共享栈
/*共享栈*/
#define MaxSize 10
typedef struct {
ElemType data[MaxSize];
int top0;//0号栈顶指针
int top1;//1号栈顶指针
}Shstack;
void InitStack(Shstack& S) {
S.top0 = -1;
S.top1 = MaxSize;
}
栈满时:top0+1==top1
三. 链栈的实现
1. 链栈的初始化
/*链栈的初始化*/
typedef struct LinkNode {
ElemType data;
struct LinkNode* next;
}LiStack;
bool InitStack(LiStack& S) {
S = (LinkNode*)malloc(sizeof(LinkNode));
if (S == NULL)return false;
S->next = NULL;
return true;
}
2. 判空
/*判空*/
bool StackEmpty(LiStack S) {
return (S->next == NULL);
}
3. 进栈
/*进栈*/
void Push(LiStack& S, ElemType e) {
LinkNode* p;
p = (LinkNode*)malloc(sizeof(LinkNode));
p->data = e;
p->next = S->next;
S->next = p;
}
4. 出栈
/*出栈*/
bool Pop(LiStack& S, ElemType& e) {
LinkNode* p;
if (S->next == NULL)return false;
p = S->next;
e = p->data;
S->next = p->next;
free(p);
return true;
}
5. 读栈顶元素
/*读栈顶元素*/
bool GetTop(LiStack S, ElemType& e) {
if (S->next == NULL)return false;
e = S->next->data;
return true;
}
四. 队列的定义
1. 队列的定义及术语
队列(Queue)是只允许在一端进行插入,在另一端进行删除的线性表。
①空队列:空线性表
②队尾:允许插入的一端
③队头:允许删除的一端
First In First Out 先入先出(FIFO)
五. 队列的顺序实现
1. 顺序队列初始化
/*顺序队列初始化*/
#define MaxSize 10
typedef struct {
ElemType data[MaxSize];
int front, rear;
}SqQueue;
void InitQueue(SqQueue& Q) {
Q.rear = Q.front = 0;
}
2. 判空
/*判空*/
bool QueueEmpty(SqQueue Q) {
return (Q.rear == Q.front);
}
3. 入队
/*入队*/
bool EnQueue(SqQueue& 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;
}
4. 出队
/*出队*/
bool DeQueue(SqQueue& Q, ElemType& e) {
if (Q.rear == Q.front)return false;
e = Q.data[Q.front];
Q.front = (Q.rear + 1) % MaxSize;//循环队列
return true;
}
5. 获得队头元素
/*获得队头元素*/
bool GetHead(SqQueue Q, ElemType& e) {
if (Q.rear == Q.front)return false;
e = Q.data[Q.front];
return true;
}
6. 关键代码
/*关键代码*/
//判空
Q.rear == Q.front;
//判满
(Q.rear + 1) % MaxSize == Q.front;
//队列元素个数
(Q.rear + MaxSize - Q.front) % MaxSize;
7. 应对考试
①在typedef时,为了让存储空间不浪费,可加上size这一属性
②同上述要求,加上tag这一属性
六. 链式存储实现队列
1. 初始化(带头结点)
/*链队的初始化(带头结点)*/
typedef struct LinkNode {
ElemType data;
struct LinkNode* next;
}LinkNode;
typedef struct {
LinkNode* front, * rear;
}LinkQueue;
void InitQueue(LinkQueue& Q) {
Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));
Q.front->next = NULL;
}
2. 判空
/*判空*/
bool IsEmpty(LinkQueue Q) {
return (Q.front == Q.rear);
}
3. 入队(带头结点)
/*入队(带头结点)*/
void EnQueue(LinkQueue& Q, ElemType e) {
LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
s->data = e;
s->next = NULL;
Q.rear->next = s;
Q.rear = s;
}
4. 出队(带头结点)
/*出队(带头结点)*/
bool DeQueue(LinkQueue& Q, ElemType& e) {
if (Q.front == Q.rear)return false;//空队
LinkNode* p = Q.front->next;
e = p->data;
Q.front->next = p->next;
if (Q.rear == p)Q.rear = Q.front;//出去完了,修改rear指针
free(p);
return true;
}
七. 双端队列
1. 双端队列的定义
双端队列是只允许从两端插入、两端删除的线性表
①输入受限的
②输出受限的
③正常的双端队列
2. 考点(输出序列合法性的判断)
若数据元素输入序列为1,2,3,4,则那些输出序列是合法的,哪些是非法的?
1,2,3,4 | 2,1,4,3 | 3,1,2,4 | 4,1,2,3 |
1,2,4,3 | 2,1,3,4 | 3,1,4,2 | 4,1,3,2 |
1,3,2,4 | 2,3,1,4 | 3,2,1,4 | 4,2,1,3 |
1,3,4,2 | 2,3,4,1 | 3,2,4,1 | 4,2,3,1 |
1,4,2,3 | 2,4,1,3 | 3,4,1,2 | 4,3,1,2 |
1,4,3,2 | 2,4,3,1 | 3,4,2,1 | 4,3,2,1 |
其中总是包含符合栈的出入顺序的序列,