文章目录
第2章 栈,队列,数组
栈
定义
只允许在一端进行插入或删除操作的线性表。
基本操作
InitStack(&S)
:初始化栈。构造一个空栈S,分配内存空间。
DestroyStack(& S)
:销毁栈,并释放栈S所占用的空间。
Push(&S,x)
:进栈,若栈S未满,则将x加入使之成为新栈顶。
Pop(&S,&x)
:出栈,若栈S非空,则弹出栈顶元素,并用x返回。
GetTop(S,&x)
:读取栈顶元素。若栈S非空,则用x返回栈顶元素。
其他常用操作:
StackEmpty(S)
:判断一个栈S是否为空。若S为空,则返回true,否则返回false。
顺序栈
定义
#define MaxSize 10
typedef struct {
ElemType data[MaxSize]; //静态数组存放栈中元素
int top; //当前栈顶指针位置
}SqStack;
Tips:注意栈顶指针top的含义。
基本操作——初始化
//初始化
void InitStack(SqStack &S) {
S.top = -1;
}
基本操作——进栈
bool Push(SqStack &S,ElemType x) {
if(S.top == MaxSize -1) //栈满
return false;
S.top ++;
S.data[S.top] = x; //进栈
//S.data[++S.top];
return true;
}
基本操作——出栈
bool Pop(SqStack &S,ElemType &x) {
if(S.top == -1) //栈空
return false;
x = S.data[S.top]; //出栈
S.top --;
//x = S.data[S.top--];
return true;
}
基本操作——读取栈顶元素
bool GetTop(SqStack &S,ElemType &x) {
if(S.top == -1) //栈空
return false;
x = S.data[S.top]; //x记录栈顶元素
return true;
}
链栈
栈的应用
括号匹配
/* 算法思想:依次输入表达式字符,若是左括号,将其入栈,若是右括号,则出栈一左括号与其匹配,循环执行,直到表达式输入结束。若表达式中所有括号都能被匹配,则表达式括号匹配正确,否则不正确。 */
bool BracketCheck(char str[],int length) {
SqStack S;
InitStack(S); //初始化一个栈
for(int i = 0;i < length;i++){
if(str[i] == '(' || str[i] == '[' || str[i] == '{') {
Push(S,str[i]); //扫描到左括号,入栈
}
else{
if(StackEmpty(S)) //扫描到右括号,且当前栈空,则匹配失败
return false;
char topelem;
Pop(S,topElem); //栈顶元素出栈
if(str[i] == ')' && topElem != '(')
return false;
if(str[i] == ']' && topElem != '[')
return false;
if(str[i] == '}' && topElem != '{')
return false;
}
}
return StackEmpty(S); //检查完全部括号后栈空,则说明配对成功
}
表达式求值
队列
定义
只允许在一端进项插入,在另一端删除的线性表。
基本操作
InitQueue(&Q)
:初始化队列,构造一个空队列Q。
DestroyQueue(&Q)
:销毁队列。销毁并释放队列Q所占用的空间。
EnQueue(&Q,x)
:入队,若队列未满,将x加入,使之成为新的队尾。
DeQueue(&Q,&x)
:出队,若队列Q非空,删除队头元素,并用x返回。
其他常用操作:
GetHead(Q,&x)
:读取队头元素,若队列Q非空,则将队头元素赋给x。
QueueEmpty(Q)
:判断队列是否为空,若队列为空返回true,否则返回false;
顺序队列
定义
#define MaxSize 10
typedef struct {
ElemType data[MaxSize]; //用静态数组存放队列元素
int front,rear; //队尾指针指向队尾元素后一个位置
}SqQueue;
基本操作——初始化
void InitQueue(SqQueue &Q) {
Q.rear = Q.front = 0; //队空条件
}
基本操作——入队
bppl EnQueue(SqQueue &Q) {
if(Q.rear == Q.front) //判断队满
return false;
Q.data[Q.rear] = x;
Q.rear = (Q.rear + 1) % MaxSize; //模运算使存储空间在逻辑上变成了“环”
return true;
}
其他判断队空/队满条件
(1)在不牺牲存储单元的情况下可以在结构体设置int size
记录队列长度,根据长度进行判断队空和队满。
(2)
基本操作——出队
bool DeQueue(SqQueue &Q,ElemType &x) {
if(Q.rear == Q.front)
return false; //判断队空
x = Q.data[Q.front];
Q.front = (Q.front + 1) % MaxSize;
return true;
}
基本操作——读取队头元素
bool GetHead(SqQueue Q,ElemType &x) {
if(Q.rear == Q.front)
return false; //判断队空
x = Q.data[Q.front];
return true;
}
Tips:队列元素个数 = (rear + MaxSize - front) % MaxSize
链队列
定义
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;
}
/* 不带头结点 */
void InitQueue(LinkQueue &Q) {
Q.front = NULL;
Q.rear = NULL;
}
基本操作——入队
/* 带头结点 */
void EnQueue(LinkQueue &Q,ElemType x) {
LinkNode *s = (LinkNode*) malloc(sizeof(LinkNode));
s->data = x;
s->next = NULL;
Q.rear->next = s;
Q.rear = s;
}
/* 不带头结点 */
void EnQueue(LinkQueue &Q,ElemType x) {
LinkNode *s = (LinkNode*) malloc(sizeof(LinkNode));
s->data = x;
s->next = NULL;
if(Q.front == NULL) { //空队列插入第一个元素
Q.front = s;
Q.rear = s;
}
else{
Q.rear->next = s;
Q.rear = s;
}
}
基本操作——出队
/* 带头结点 */
bool DeQueue(LinkQueue &Q,ElemType &x) {
if(Q.front == Q.rear) //空队
return false;
LinkNode *p = Q.front->next;
x = p->data;
Q.front->next = p->next;
if(Q.rear == p) //此次是最后一个结点出队
Q.rear = Q.front;
free(p);
return true;
}
/* 不带头结点 */
bool DeQueue(LinkQueue &Q,ElemType &x) {
if(Q.front == NULL) //空队
return false;
LinkNode *p = Q.front;
x = p->data;
Q.front = p->next;
if(Q.rear == p) { //此次是最后一个结点出队
Q.front = NULL;
Q.rear = NULL;
}
free(p);
return true;
}
Tips:一般不会出现队满情况。
双端队列
允许在两端插入、两端删除的线性表。(输入受限/输出受限)
Tips:在栈中合法的输出序列,在双端序列必定合法。
队列的应用
- 树的层次遍历
- 图的广度优先遍历
矩阵的压缩存储
对称矩阵
Q:数组大小应为多少?
A:(n + 1)* n / 2
上三角矩阵
三对角矩阵
稀疏矩阵
广义表
- 广义表是具有n个元素的有限序列,记为LS = (a1,a2,……an)。
- 一个广义表通常可以用一对圆括号括起来,n是它的长度。
- ai可以是单个元素,也可以是广义表,分别叫原子和子表(子表也要用圆括号括起来)。
- 用大写字母表示广义表的结构名,用小写字母表示原子。
- 广义表非空时,第一个元素a1为LS的表头(head),其余元素组成的表(a2,a3,……an)是LS的表尾(tail)。
- A = () —— A是一个空表,长度为零。
- B = (e) —— 列表B只有一个原子e,B的长度为1。
- C = (a,(b,c,d)) —— 列表C的长度为2,两个元素分别为原子a和子表(b,c,d)。
- D = (A,B,C) —— 列表D的长度为3,三个元素都是列表。
- E = (a,E) —— 这是一个递归的表,长度为2。