顺序栈和循环队列的基本运算
内容
构建顺序栈类型
- 实现顺序栈的初始化
- 顺序栈的判满
- 顺序栈的判空
- 顺序栈的入栈
- 顺序栈的出栈
- 顺序栈的读取栈顶元素
- 基于顺序栈实现表达式中括号是否匹配的检验
构建循环队列类型
- 实现循环队列的初始化
- 循环队列的判满
- 循环队列的判空
- 循环队列的入队
- 循环队列的出队
- 循环队列的读取队头元素
- 循环队列的读取队尾元素
- 基于循环队列实现杨辉三角形N行数据的输出
要求
- 栈中数据元素的类型统一抽象表示为
SElemType
类型,在程序中将SElemType
类型具体化为char
类型 - 队列中数据元素的类型统一抽象表示为
QElemType
类型,在程序中将QElemType类型具体化为int
类型 - 将栈的基本运算封装在
stack.h
和queue.h
文件中,源程序直接#include “stack.h”
和#include “queue.h”
- 提交
1个
源程序文件,而并非提交2个
源程序文件
解析
1. 顺序栈
什么是顺序栈?官方的定义:栈(stack)是限定仅在表尾进行插入和删除操作的线性表。允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom),不含任何数据元素的栈称为空栈。栈又称为先进后出(Last In First Out)的线性表。
何为栈?何为先进后出,举个例子,手枪的弹匣其实就是一个栈(也是顺序栈),先装入的子弹在弹匣的底部,最后装入的子弹在顶部,每次开枪发射的时候总是打出弹匣顶部的子弹。
1.1. 顺序栈的结构定义
typedef char SElemType;
#define MaxSize 500
typedef struct {
SElemType data[MaxSize];
int top; //栈顶指针
} SqStack;
#### 顺序栈的初始化
```cpp
void InitStack(SqStack *S) {
for (int i = 0; i < MaxSize; ++i) {
S->data[i] = '\000';
}
S->top = -1;
}
1.2. 顺序栈的判满
bool IsFull(SqStack S) {
if (S.top == MaxSize - 1)
return true;
else
return false;
}
1.3. 顺序栈的判空
bool IsEmpty(SqStack S) {
if (S.top == -1)
return true;
else return false;
}
1.4. 顺序栈的入栈
bool Push(SqStack *S, SElemType e) {
if (S->top == MaxSize - 1) //栈满
return false;
S->top++;
S->data[S->top] = e; //元素入栈
return true;
}
1.5. 顺序栈的出栈
bool Pop(SqStack *S, SElemType *e) {
if (S->top == -1)
return false; //栈空
*e = S->data[S->top];
S->top--;
return true;
}
1.6. 顺序栈的读取栈顶元素
SElemType GetTop(SqStack S) {
return S.data[S.top];
}
1.7. stack.h
文件
//
// Created by Louie on 2022/10/1.
//
typedef char SElemType;
#define MaxSize 500
typedef struct {
SElemType data[MaxSize];
int top;
} SqStack;
void InitStack(SqStack *S) {
for (int i = 0; i < MaxSize; ++i) {
S->data[i] = '\000';
}
S->top = -1;
}
bool IsEmpty(SqStack S) {
if (S.top == -1)
return true;
else return false;
}
bool IsFull(SqStack S) {
if (S.top == MaxSize - 1)
return true;
else
return false;
}
bool DestroyStack(SqStack *S) {
if (S->top == -1)
return false;
for (int i = 0; i < S->top; ++i) {
S->data[i] = 0;
}
S->top = -1;
return true;
}
SElemType GetTop(SqStack S) {
return S.data[S.top];
}
bool Push(SqStack *S, SElemType e) {
if (S->top == MaxSize - 1) //栈满
return false;
S->top++;
S->data[S->top] = e; //元素入栈
return true;
}
//bool Pop(SqStack *S) {
// if (S->top == -1)
// return false; //栈空
// S->data[S->top] = '\000';
// S->top--;
// return true;
//}
bool Pop(SqStack *S, SElemType *e) {
if (S->top == -1)
return false; //栈空
*e = S->data[S->top];
S->top--;
return true;
}
int StackLength(SqStack S) {
return (S.top + 1);
}
#ifndef DATASTRUCT_STACK_H
#define DATASTRUCT_STACK_H
#endif //DATASTRUCT_STACK_H
1.8. 基于顺序栈实现表达式中括号是否匹配的检验
arr[]
数组用来存放括号,使用while循环遍历数组,如果是左括号那么就入栈,如果当前的 arr[i]
是右括号,那么就与栈顶元素进行对比,如果正好匹配上如{}
、[]
、()
那么就将栈顶元素弹出栈顶(类似于消消乐),考虑到,如果是一组合法的括号序列,那么经过遍历之后顺序栈应该是一个空栈,且栈顶的top == -1
,如果栈不为空,那么这组括号序列一定是不合法的。具体代码如下
void Match(const char arr[]) { //括号匹配,arr[]存放所有的括号
SqStack sqStack;
InitStack(&sqStack); //初始化栈
int i = 0; //数组arr[]下标
SElemType e; //存放栈顶元素
while (arr[i] != '\000') { //遍历arr[]数组
if (arr[i] == '(' || arr[i] == '{' || arr[i] == '[') {
Push(&sqStack, arr[i]); //如果是左括号就进栈
} else if (arr[i] == ')' || arr[i] == '}' || arr[i] == ']') { //如果匹配到右括号就与栈顶元素进行比较
switch (arr[i]) {
case ')':
e = GetTop(sqStack);
if (e == '(')
Pop(&sqStack, &e); //如果当前的括号与栈顶符号匹配,那么就将栈顶元素压出栈
break;
case ']':
e = GetTop(sqStack);
if (e == '[')
Pop(&sqStack, &e);
break;
case '}':
e = GetTop(sqStack);
if (e == '{')
Pop(&sqStack, &e);
break;
}
}
i++;
}
if (IsEmpty(sqStack)) //如果栈为空,说明匹配成功
printf("Bracket matching succeeded!!!\n");
else
printf("Bracket matching failed!!!\n");
}
1.8.1. File_Input()
函数
该函数可以从文件里面读取内容,然后对内容进行提取括号,检测文中的括号是否合法。
fopen()里面的第一个参数是目标文件的绝对路径,第二个参数r
表示该文件是只读模式。防止对文件的内容进行修改。
/*
* 该函数的作用是读取文件,然后筛选出括号并存入arr[]数组中
*/
void File_Input(char arr[]) {
int ch = 0;
int count = 0;
FILE *fp;
fp = fopen("F:\\DataStruct\\homework\\NO3.cpp ", "r");//test文件的绝对路径
if (fp == nullptr)
printf("file is error\n");
while (ch != EOF) { //EOF是文件的结束标志
ch = fgetc(fp);
if (ch == '(' || ch == ')' || ch == '{' || ch == '}' || ch == '[' || ch == ']')
arr[count++] = ch;
}
fclose(fp);
}
考虑到有些同学对文件操作并不熟悉,为此我提供了终端输入括号序列的方式
1.8.2. Terminal_iInput()函数
void Terminal_iInput(char arr[]) {
printf("Please enter bracket sequence:\n");
scanf("%s", arr);
}
1.8.3. 括号匹配的测试函数
void BracketMatching_Test() {
int i = 0;
char arr[1000] = ""; //初始化数组'\000'
char arr_1[1000] = "";
Terminal_iInput(arr);
Match(arr);
File_Input(arr_1);
printf("%s\n", arr_1);
Match(arr_1);
}
2. 循环队列
2.1 循环队列的结构定义
typedef int QElemType;
#define MaxSize 500
typedef struct {
QElemType data[MaxSize];
int front;
int rear;
} SeqQueue;
2.2 实现循环队列的初始化
void InitQueue(SeqQueue *Q) {
Q->front = Q->rear = 0;
for (int i = 0; i < MaxSize; ++i) {
Q->data[i] = 0;
}
}
2.3 循环队列的判满
bool Is_Full_Q(SeqQueue Q) {
if ((Q.rear) % MaxSize == Q.front)
return true;
else
return false;
}
2.4 循环队列的判空
bool Is_Empty_Q(SeqQueue Q) {
if (Q.front == Q.rear)
return true;
else
return false;
}
2.5 循环队列的入队
bool Push_Q(SeqQueue *Q, QElemType e) {
if ((Q->rear + 1) % MaxSize == Q->front) //队列满了
return false;
Q->data[Q->rear] = e;
Q->rear = (Q->rear + 1) % MaxSize;
return true;
}
2.6 循环队列的出队
bool Pop_Q(SeqQueue *Q, QElemType *e) {
if (Q->front == Q->rear)
return false;
*e = Q->data[Q->front];
Q->front = (Q->front + 1) % MaxSize;
return true;
}
2.7 循环队列的读取队头元素
bool GetHead(SeqQueue Q, QElemType *e) {
if (Q.front == Q.rear)
return false;
*e = Q.data[Q.front];
return true;
}
2.8 循环队列的读取队尾元素
bool GetRear(SeqQueue Q, QElemType *e) {
if (Q.front == Q.rear)
return false;
*e = Q.data[Q.rear];
return true;
}
2.9 queue.h
文件
//
// Created by Louie on 2022/10/7.
//
typedef int QElemType;
#define MaxSize 500
typedef struct {
QElemType data[MaxSize];
int front;
int rear;
} SeqQueue;
void InitQueue(SeqQueue *Q) {
Q->front = Q->rear = 0;
for (int i = 0; i < MaxSize; ++i) {
Q->data[i] = 0;
}
}
bool Is_Empty_Q(SeqQueue Q) {
if (Q.front == Q.rear)
return true;
else
return false;
}
bool Is_Full_Q(SeqQueue Q) {
if ((Q.rear) % MaxSize == Q.front)
return true;
else
return false;
}
bool Push_Q(SeqQueue *Q, QElemType e) {
if ((Q->rear + 1) % MaxSize == Q->front) //队列满了
return false;
Q->data[Q->rear] = e;
Q->rear = (Q->rear + 1) % MaxSize;
return true;
}
bool Pop_Q(SeqQueue *Q, QElemType *e) {
if (Q->front == Q->rear)
return false;
*e = Q->data[Q->front];
Q->front = (Q->front + 1) % MaxSize;
return true;
}
bool GetHead(SeqQueue Q, QElemType *e) {
if (Q.front == Q.rear)
return false;
*e = Q.data[Q.front];
return true;
}
bool GetRear(SeqQueue Q, QElemType *e) {
if (Q.front == Q.rear)
return false;
*e = Q.data[Q.rear];
return true;
}
#ifndef DATASTRUCT_QUEUE_H
#define DATASTRUCT_QUEUE_H
#endif //DATASTRUCT_QUEUE_H
2.10 基于循环队列实现杨辉三角形N行数据的输出
太简单了,我就不说了,亲们自己看,看不懂的评论留言,或者联系扣扣 1633497269
void YangHuiTriangle() {
SeqQueue Q;
QElemType x;
InitQueue(&Q);
Push_Q(&Q, 1);
QElemType t;
printf("请输入行数:");
int num;
scanf("%d", &num);
for (int i = 2; i <= num + 1; i++) {
for (int j = 0; j <= num - i; ++j) {
printf(" ");
}
Push_Q(&Q, 1);
for (int j = 1; j <= i - 2; j++) {
Pop_Q(&Q, &t);
printf("%d ", t);
GetHead(Q, &x);
t = t + x;
Push_Q(&Q, t);
}
Pop_Q(&Q, &x);
printf("%d\n", x);
Push_Q(&Q, 1);
}
}
3. 完整代码
#include <cstdio>
#include "stack.h"
#include "queue.h"
void Match(const char arr[]) { //括号匹配,arr[]存放所有的括号
SqStack sqStack;
InitStack(&sqStack); //初始化栈
int i = 0; //数组arr[]下标
SElemType e; //存放栈顶元素
while (arr[i] != '\000') { //遍历arr[]数组
if (arr[i] == '(' || arr[i] == '{' || arr[i] == '[') {
Push(&sqStack, arr[i]); //如果是左括号就进栈
} else if (arr[i] == ')' || arr[i] == '}' || arr[i] == ']') { //如果匹配到右括号就与栈顶元素进行比较
switch (arr[i]) {
case ')':
e = GetTop(sqStack);
if (e == '(')
Pop(&sqStack, &e); //如果当前的括号与栈顶符号匹配,那么就将栈顶元素压出栈
break;
case ']':
e = GetTop(sqStack);
if (e == '[')
Pop(&sqStack, &e);
break;
case '}':
e = GetTop(sqStack);
if (e == '{')
Pop(&sqStack, &e);
break;
}
}
i++;
}
if (IsEmpty(sqStack)) //如果栈为空,说明匹配成功
printf("Bracket matching succeeded!!!\n");
else
printf("Bracket matching failed!!!\n");
}
/*
* 该函数的作用是读取文件,然后筛选出括号并存入arr[]数组中
*/
void File_Input(char arr[]) {
int ch = 0;
int count = 0;
FILE *fp;
fp = fopen("F:\\DataStruct\\homework\\NO3.cpp ", "r");//test文件的绝对路径
if (fp == nullptr)
printf("file is error\n");
while (ch != EOF) {
ch = fgetc(fp);
if (ch == '(' || ch == ')' || ch == '{' || ch == '}' || ch == '[' || ch == ']')
arr[count++] = ch;
}
fclose(fp);
}
void Terminal_iInput(char arr[]) {
printf("Please enter bracket sequence:\n");
scanf("%s", arr);
}
void BracketMatching_Test() {
int i = 0;
char arr[1000] = ""; //初始化数组'\000'
char arr_1[1000] = "";
Terminal_iInput(arr);
Match(arr);
File_Input(arr_1);
printf("%s\n", arr_1);
Match(arr_1);
}
void YangHuiTriangle() {
SeqQueue Q;
QElemType x;
InitQueue(&Q);
Push_Q(&Q, 1);
QElemType t;
printf("请输入行数:");
int num;
scanf("%d", &num);
for (int i = 2; i <= num + 1; i++) {
for (int j = 0; j <= num - i; ++j) {
printf(" ");
}
Push_Q(&Q, 1);
for (int j = 1; j <= i - 2; j++) {
Pop_Q(&Q, &t);
printf("%d ", t);
GetHead(Q, &x);
t = t + x;
Push_Q(&Q, t);
}
Pop_Q(&Q, &x);
printf("%d\n", x);
Push_Q(&Q, 1);
}
}
int main() {
BracketMatching_Test();
YangHuiTriangle();
return 0;
}