4.顺序栈和循环队列的基本运算

顺序栈和循环队列的基本运算

内容

构建顺序栈类型

  • 实现顺序栈的初始化
  • 顺序栈的判满
  • 顺序栈的判空
  • 顺序栈的入栈
  • 顺序栈的出栈
  • 顺序栈的读取栈顶元素
  • 基于顺序栈实现表达式中括号是否匹配的检验

构建循环队列类型

  • 实现循环队列的初始化
  • 循环队列的判满
  • 循环队列的判空
  • 循环队列的入队
  • 循环队列的出队
  • 循环队列的读取队头元素
  • 循环队列的读取队尾元素
  • 基于循环队列实现杨辉三角形N行数据的输出

要求

  • 栈中数据元素的类型统一抽象表示为SElemType类型,在程序中将SElemType类型具体化为char类型
  • 队列中数据元素的类型统一抽象表示为QElemType类型,在程序中将QElemType类型具体化为int类型
  • 将栈的基本运算封装在stack.hqueue.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;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值