数据结构 实验三 栈实验 实验报告(合肥工业大学 2023级)

合肥工业大学 2023级 数据结构 实验三 完整报告

1.实验目标

  1. 熟练掌握栈的顺序存储结构和链式存储结构。
  2. 熟练掌握栈的有关算法设计,并在顺序栈和链栈上实现。
  3. 根据具体给定的需求,合理设计并实现相关结构和算法。

2.实验要求

顺序栈的实验要求

  1. 顺序栈结构和运算定义,算法的实现以库文件方式实现,比如seqStack.h,不得在测试主程序中直接实现;
  2. 实验程序有较好可读性,各运算和变量的命名直观易懂,符合软件工程要求;
  3. 程序有适当的注释。

链栈实验要求

  1. 本次实验中的链栈结构指带头结点的单链表;
  2. 链栈结构和运算定义,算法的实现以库文件方式实现,比如linkedStack.h,不得在测试主程序中直接实现;
  3. 实验程序有较好可读性,各运算和变量的命名直观易懂,符合软件工程要求;
  4. 程序有适当的注释。

3.实验内容

顺序栈实验任务

设计并实现一个顺序栈,编写算法实现下列问题的求解。

1)利用顺序栈实现将10进制数转换为x进制数,2<=x<=36,除了阿拉伯数字字符,不够字符使用大写英文字符。要求键盘输入10进制数和转换的目标进制数。比如:37转换为20进制数为1H。

第一组数据:4

第二组数据:311

第三组数据:7254

第四组数据:98357

2)对一个合法的数学表达式来说,其中的各大小括号“{”,“}”,“[”,“]”,“(”和“)”应是相互匹配的。设计算法对以字符串形式读入的表达式S,判断其中的各括号是否是匹配的。比如:“{{}}”是匹配的,“{[(})]”就是不匹配的。

3)假设栈的输入序列为1、2、3、...、n,设计算法求出所有可能的出栈序列。比如输入1、2、3、4、5,可能出栈的序列为12345、13452等42个。

链栈实验任务

以带头结点的单链表表示链栈,编写算法实现下列问题的求解。

1)利用链栈实现将10进制数转换为x进制数,2<=x<=36,除了阿拉伯数字字符,不够字符使用大写英文字符。要求键盘输入10进制数和转换的目标进制数。比如:37转换为20进制数为1H。

第一组数据:4

第二组数据:311

第三组数据:7254

第四组数据:98357

2)对一个合法的数学表达式来说,其中的各大小括号“{”,“}”,“[”,“]”,“(”和“)”应是相互匹配的。设计算法对以字符串形式读入的表达式S,判断其中的各括号是否是匹配的。比如:“{[](){}}”是匹配的,“{[(})]”就是不匹配的。

3)假设栈的输入序列为1、2、3、...、n,设计算法求出所有可能的出栈序列。比如输入1、2、3、4、5,可能出栈的序列为12345、13452等42个。

栈的扩展实验

非必做内容,有兴趣的同学选做。自行选择栈的存储结构。

1)假设栈的输入序列为1、2、3、...、n,设计算法实现对给定的一个序列,判定其是否是此栈合法的输出序列。比如输入1、2、3、4、5序列,13452为合法出栈序列;15234是不合法输出序列。

2)利用栈求解算术表达式的值。

4.数据结构设计

顺序栈
#define MaxLen 100 // 最大容量  
char arr[36] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};  
  
class seqStack  
{  
    public:  
        seqStack();      // 初始化栈  
        ~seqStack();     // 析构函数  
        bool empty();    // 判断栈是否为空  
        bool full();     // 判断栈是否已满  
        bool getTop(char &x); // 获取栈顶元素  
        bool push(char x);    // 将元素入栈  
        bool pop(char &x);     // 将元素出栈  
        bool pop();     // 将元素出栈  
  
    private:  
        char data[MaxLen]; // 存放栈元素  
        int top;    // 栈顶指针(数组下标)  
};  
  
seqStack::seqStack()  
{  
    top = -1; // 初始化栈顶指针为-1,表示栈为空  
}  
  
seqStack::~seqStack()  
{  
}  
  
bool seqStack::empty()  
{  
    return top == -1; // 如果栈顶指针为-1,表示栈为空  
}  
  
bool seqStack::full()  
{  
    return top == MaxLen - 1; // 如果栈顶指针等于MaxLen-1,表示栈已满  
}  
  
bool seqStack::getTop(char &x)  
{  
    if (top == -1)  
        return false; // 如果栈为空,返回false  
    else  
    {  
        x = data[top]; // 否则将栈顶元素赋值给x  
        return true;  
    }  
}  
  
bool seqStack::push(char x)  
{  
    if (full())  
        return false; // 如果栈已满,返回false  
    else  
    {  
        data[++top] = x; // 否则将新元素放入栈顶,栈顶指针加1  
        return true;  
    }  
}  
  
bool seqStack::pop(char &x)  
{  
    if (empty())  
        return false; // 如果栈为空,返回false  
    else  
    {  
        x = data[top--]; // 否则将栈顶元素赋值给x,栈顶指针减1  
        return true;  
    }  
}  
  
bool seqStack::pop()  
{  
    if (empty())  
        return false; // 如果栈为空,返回false  
    else  
    {  
        top--; // 否则栈顶指针减1  
        return true;  
    }  
}  
链栈
char arr[36] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};  
  
// 定义链栈结点  
typedef struct lsNode  
{  
    char data; // 链栈结点数据域  
    struct lsNode *next; // 链栈结点指针域  
} node;  
  
// 定义链栈类  
class linkedStack  
{  
    public:  
        linkedStack(); // 初始化空栈  
        ~linkedStack(); // 销毁链栈  
        bool empty(); // 判定栈空  
        bool getTop(char &x); // 取栈顶元素  
        void push(char x); // 入栈  
        bool pop(char &x); // 出栈  
        bool pop(); // 出栈  
    private:  
        node* top; // 栈顶指针  
};  
  
// 初始化链栈  
linkedStack::linkedStack()  
{  
    top = NULL;  
}  
  
// 判定栈空  
bool linkedStack::empty()  
{  
    return top == NULL;  
}  
  
// 取栈顶元素  
bool linkedStack::getTop(char &x)  
{  
    if (empty())  
        return false; // 栈空,返回false  
    else  
    {  
        x = top->data; // 取栈顶元素,用参数x返回  
        return true; // 取栈顶成功,返回true  
    }  
}  
  
// 入栈  
void linkedStack::push(char x)  
{  
    node* s = new node;  
    s->data = x;  
    s->next = top;  
    top = s;  
}  
  
// 出栈,返回出栈元素  
bool linkedStack::pop(char &x)  
{  
    if (empty())  
        return false; // 栈空,返回false  
    else  
    {  
        x = top->data; // 取栈顶元素,由变量x返回  
        node* u = top; // 栈顶指针保存到u  
        top = top->next; // 栈顶指针后移一个元素结点  
        delete u; // 释放原栈顶结点  
        return true; // 出栈成功,返回true  
    }  
}  
  
// 出栈,不返回出栈元素  
bool linkedStack::pop()  
{  
    if (empty())  
        return false; // 栈空,返回false  
    else  
    {  
        node* u = top; // 栈顶指针保存到u  
        top = top->next; // 栈顶指针后移一个元素结点  
        delete u; // 释放原栈顶结点  
        return true; // 出栈成功,返回true  
    }  
}  
  
// 销毁链栈  
linkedStack::~linkedStack()  
{  
    node *p, *u;  
    p = top;  
    while (p)  
    {  
        u = p;  
        p = p->next;  
        delete u;  
    }  
    top = NULL;  
}  

5.算法设计

顺序栈
1.
【算法设计思想】
  1. 首先,函数接受三个参数:被转换的整数 q,目标进制 b,以及一个用于存储转换结果的字符数组 result[]。

  2. 然后,代码会进行一些基本的参数检查:

    如果进制 b 不在 2 到 36 之间,或者被转换数 q 小于 0,则函数会返回 false。

    如果被转换数 q 为 0,则结果数组中的第一个元素会被设置为 '0',然后返回 true。

  3. 接着,代码创建了一个顺序栈 S ,用于存储转换结果。

  4. 在一个 while 循环中,代码会不断地将 q 对 b 取余的结果压入栈 S 中,并更新 q 为 q 除以 b 的商,直到 q 为 0。

  5. 然后,代码通过一个 while 循环从栈 S 中依次弹出元素到变量 x,然后将这些元素存入结果数组 result[] 中,直到栈 S 为空。

  6. 最后,代码在结果数组的末尾添加字符串结束符 '\0',并返回 true。

【算法描述】
bool conversion(int q, int b, char result[])  
{  
    if (b < 2 || b > 36 || q < 0)  
    {  
        return false; // 如果进制b不在2到36之间,或者被转换数q小于0,则返回false  
    }  
    if (q == 0)  
    {  
        result[0] = '0'; // 如果被转换数q为0,则结果为'0'  
        result[1] = '\0';  
        return true;  
    }  
  
    seqStack S; // 创建一个顺序栈S用于存储转换结果  
  
    while (q)  
    {  
        S.push(arr[q % b]); // 将q对b取余的结果压入栈S  
        q = q / b; // 更新q为q除以b的商  
    }  
  
    int i = 0;  
    char x;  
  
    while (!S.empty())  
    {  
        S.pop(x); // 从栈S中弹出元素到x  
        result[i] = x; // 将弹出的元素存入结果数组中  
        i++;  
    }  
  
    result[i] = '\0'; // 在结果数组末尾添加字符串结束符  
    return true;  
}  
2.
【算法设计思想】
  1. 首先,定义了一个变量i用于遍历输入的字符数组ch,同时定义了一个字符变量x用于存储栈顶元素,以及一个顺序栈S用于匹配括号。

  2. 进入循环,遍历输入的字符数组ch,直到遇到字符串结束符\0为止。

  3. 在循环中,首先判断当前字符是否为左括号(,[,{,如果是,则将其压入栈S中,并且i自增。

  4. 如果当前字符不是左括号,而是右括号), ], },则需要进行匹配操作:

    获取栈顶元素到变量x中。

    检查当前字符与栈顶元素是否匹配,即右括号与对应的左括号匹配。

    如果匹配成功,弹出栈顶元素,同时i自增。

    如果匹配失败,直接返回false,表示括号匹配失败。

  5. 循环结束后,如果栈S为空,说明所有括号都匹配成功,返回true;否则,返回false,表示括号匹配失败。

【算法描述】
bool bracketMatch(char ch[])  
{  
    int i = 0;  
    char x;  
    seqStack S; // 创建一个栈S用于匹配括号  
  
    while (ch[i] != '\0')  
    {  
        if (ch[i] == '(' || ch[i] == '[' || ch[i] == '{')  
        {  
            S.push(ch[i]); // 如果是左括号,压入栈S  
            i++;  
        }  
        else if (ch[i] == ')' || ch[i] == ']' || ch[i] == '}')  
        {  
            S.getTop(x); // 获取栈顶元素到x  
            if ((ch[i] == ')' && x == '(') || (ch[i] == ']' && x == '[') || (ch[i] == '}' && x == '{'))  
            {  
                S.pop(); // 如果匹配成功,弹出栈顶元素  
                i++;  
            }  
            else  
            {  
                return false; // 匹配失败,返回false  
            }  
        }  
    }  
  
    if (S.empty())  
        return true; // 如果栈为空,说明匹配成功,返回true  
    else  
        return false; // 否则返回false  
}  
3.
【算法设计思想】

通过不断模拟元素的入栈和出栈操作,来生成所有可能的出栈顺序。具体执行过程为:

  1. 如果 i 大于等于 len,表示已经处理完所有输入元素:

    如果栈为空,说明全部元素已经入栈并出栈,输出当前出栈顺序。

    如果栈不为空,表示还有元素未出栈,则将栈顶元素出栈,继续递归处理。处理完后,将之前出栈的元素重新入栈,以便尝试其他出栈顺序。

  2. 如果 i 小于 len,表示还有元素未处理:

    如果栈不为空,先将栈顶元素出栈,继续递归处理。

    将当前元素入栈,继续递归处理下一个元素。

    处理完后,将当前元素出栈,以便尝试其他入栈顺序。

【算法描述】
void outSequence(seqStack &s, char *in, char *out, int len, int &num, int i = 0, int j = 0)  
{  
    if (i >= len)  
    {  
        if (s.empty()) // 结束(全部入栈过,且全部已经出栈)  
        {  
            cout << "第" << num + 1 << "种 : "; // 输出序列种类  
            num++;  
            out[j] = '\0'; // 在输出序列末尾添加字符串结束符  
            cout << out << endl; // 输出当前序列  
        }  
        else // 全部入栈过,但未全部出栈  
        {  
            s.pop(out[j]); // 出栈  
            outSequence(s, in, out, len, num, i, j + 1);  
            // 恢复  
            s.push(out[j]); // 恢复栈状态  
        }  
    }  
    else if (i < len)  
    {  
        if (!s.empty()) // 未全部入栈过,且当前栈非空  
        {  
            s.pop(out[j]); // 出栈  
            outSequence(s, in, out, len, num, i, j + 1);  
            // 恢复  
            s.push(out[j]); // 恢复栈状态  
        }  
  
        s.push(in[i]); // 入栈  
        outSequence(s, in, out, len, num, i + 1, j);  
        // 恢复  
        s.pop(); // 恢复栈状态  
    }  
}  

链栈实验任务

1.
【算法设计思想】
  1. 首先,函数会检查输入的参数是否符合要求:

    如果进制b不在2到36之间,或者被转换的数q小于0,则函数会返回false。

    如果被转换的数q为0,则结果数组中只存储字符'0',然后返回true。

  2. 接着,函数会创建一个链栈S。

  3. 然后,进入一个循环,将被转换的数q按照给定的进制b进行转换:

    每次取q除以b的余数,将余数压入栈S中。

    更新q的值为q除以b的商。

  4. 接下来,从栈S中依次弹出元素,将其存入结果数组中,直到栈为空。

  5. 最后,将结果数组末尾添加字符串结束符'\0',表示字符串的结束,并返回true。

【算法描述】
bool conversion(int q, int b, char result[])  
{  
    if (b < 2 || b > 36 || q < 0)  
    {  
        return false; // 如果进制不在2到36之间或者被转换的数小于0,则返回false  
    }  
    if (q == 0)  
    {  
        result[0] = '0';  
        result[1] = '\0';  
        return true; // 如果被转换的数为0,则结果为"0",返回true  
    }  
  
    linkedStack S; // 创建一个链栈S  
  
    while (q)  
    {  
        S.push(arr[q % b]); // 将q除以b的余数入栈  
        q = q / b; // 更新q的值  
    }  
  
    int i = 0;  
    char x;  
  
    while (!S.empty())  
    {  
        S.pop(x); // 出栈  
        result[i] = x; // 将出栈的元素存入结果数组  
        i++;  
    }  
  
    result[i] = '\0'; // 在结果数组末尾添加字符串结束符  
    return true;  
}  
2.
【算法设计思想】

函数通过遍历输入的字符数组ch,依次检查每个字符。如果是左括号,则将其入栈;如果是右括号,则与栈顶元素匹配,如果匹配则出栈,否则返回false。最后,函数返回栈是否为空。具体执行过程为:

  1. 首先,函数初始化了一个索引变量i,并声明了一个字符变量x以及一个链栈S。
  2. 然后,函数通过while循环遍历输入的字符数组ch,直到遇到空字符为止。在循环中,它检查每个字符是否是左括号或右括号,并根据情况执行相应的操作。
  3. 如果是左括号,则将其入栈,并递增索引i。
  4. 如果是右括号,则首先检查栈是否为空。如果栈不为空,则获取栈顶元素,并与当前字符进行匹配。如果匹配成功,则出栈,并递增索引i;如果匹配不成功,则返回false。如果栈为空,说明右括号多于左括号,也返回false。
  5. 最后,函数返回栈是否为空,以判断括号是否匹配完全。
【算法描述】
bool bracketMatch(char ch[])  
{  
    int i = 0;  
    char x;  
    linkedStack S; // 创建一个链栈S  
  
    while (ch[i] != '\0')  
    {  
        if (ch[i] == '(' || ch[i] == '[' || ch[i] == '{')  
        {  
            S.push(ch[i]); // 如果是左括号,入栈  
            i++;  
        }  
        else if (ch[i] == ')' || ch[i] == ']' || ch[i] == '}')  
        {  
            if (!S.empty())  
            {  
                S.getTop(x); // 获取栈顶元素  
                if ((ch[i] == ')' && x == '(') || (ch[i] == ']' && x == '[') || (ch[i] == '}' && x == '{'))  
                {  
                    S.pop(); // 出栈  
                    i++;  
                }  
                else  
                {  
                    return false; // 括号不匹配,返回false  
                }  
            }  
            else  
            {  
                return false; // 右括号多于左括号,返回false  
            }  
        }  
    }  
  
    return S.empty(); // 返回栈是否为空  
}  
3.
【算法设计思想】

通过不断模拟元素的入栈和出栈操作,来生成所有可能的出栈顺序。具体执行过程为:

  1. 如果 i 大于等于 len,表示已经处理完所有输入元素:

    如果栈为空,说明全部元素已经入栈并出栈,输出当前出栈顺序。

    如果栈不为空,表示还有元素未出栈:将栈顶元素出栈,继续递归处理。处理完后,将之前出栈的元素重新入栈,以便尝试其他出栈顺序。

  2. 如果 i 小于 len,表示还有元素未处理:

    如果栈不为空,先将栈顶元素出栈,继续递归处理。

    将当前元素入栈,继续递归处理下一个元素。

    处理完后,将当前元素出栈,以便尝试其他入栈顺序。

【算法描述】
void outSequence(linkedStack &s, char *in, char *out, int len, int &num, int i = 0, int j = 0)  
{  
    if (i >= len)  
    {  
        if (s.empty()) // 结束(全部入栈过,且全部已经出栈)  
        {  
            cout << "第" << num + 1 << "种 : ";  
            num++;  
            out[j] = '\0'; // 在输出数组末尾添加字符串结束符  
            cout << out << endl; // 输出结果  
        }  
        else // 全部入栈过,但未全部出栈  
        {  
            s.pop(out[j]); // 出栈  
            outSequence(s, in, out, len, num, i, j + 1);  
            // 恢复  
            s.push(out[j]); // 入栈  
        }  
    }  
    else if (i < len)  
    {  
        if (!s.empty()) // 未全部入栈过,且当前栈非空  
        {  
            s.pop(out[j]); // 出栈  
            outSequence(s, in, out, len, num, i, j + 1);  
            // 恢复  
            s.push(out[j]); // 入栈  
        }  
  
        s.push(in[i]); // 入栈  
        outSequence(s, in, out, len, num, i + 1, j);  
        // 恢复  
        s.pop(); // 出栈  
    }  
}  

栈的扩展实验

顺序栈
【算法设计思想】
  1. 创建一个顺序栈S,用于检查序列的合法性。

  2. 初始化变量j为0,用于追踪chuArr数组的索引。

  3. 在for循环中,遍历ruArr数组的元素:

    将ruArr[i]元素依次压入栈S中。

    获取栈顶元素到变量x。

    进入while循环,只要栈不为空且栈顶元素与chuArr[j]相同:弹出栈顶元素。索引j增加。获取新的栈顶元素到变量x。

    循环结束后,继续遍历下一个元素。

  4. 最终,通过return S.empty()判断栈是否为空,如果栈为空则返回true,表示序列合法;如果栈不为空则返回false,表示序列不合法。

【算法描述】
bool sequenceLegitimacy(char ruArr[], char chuArr[], int len)  
{  
    seqStack S; // 创建一个顺序栈S用于检查序列合法性  
    int j = 0;  
    char x;  
    for (int i = 0; i < len; i++)  
    {  
        S.push(ruArr[i]); // 将入栈序列ruArr的元素依次压入栈S  
        S.getTop(x); // 获取栈顶元素到x  
  
        while (!S.empty() && x == chuArr[j])  
        {  
            S.pop(); // 如果栈非空且栈顶元素与chuArr相同,则弹出栈顶元素  
            j++;  
            S.getTop(x); // 获取新的栈顶元素  
        }  
    }  
    return S.empty(); // 返回栈是否为空,判断序列合法性  
}  
链栈
【算法设计思想】
  1. 创建一个链栈S。

  2. 通过循环遍历ruArr中的元素,依次将其入栈。

  3. 每次入栈后,通过S.getTop(x)获取栈顶元素x。

  4. 进入一个内部循环,只要栈不为空且栈顶元素x等于chuArr中的元素chuArr[j],则执行以下操作:

    出栈操作S.pop()。

    增加j的值,用于遍历chuArr。

    再次通过S.getTop(x)获取栈顶元素x。

  5. 最终返回栈S是否为空的结果,即判断是否所有元素都匹配完毕。

【算法描述】
bool sequenceLegitimacy(char ruArr[], char chuArr[], int len)  
{  
    linkedStack S; // 创建一个链栈S  
    int j = 0;  
    char x;  
    for (int i = 0; i < len; i++)  
    {  
        S.push(ruArr[i]); // 将ruArr中的元素依次入栈  
        S.getTop(x); // 获取栈顶元素  
  
        while (!S.empty() && x == chuArr[j])  
        {  
            S.pop(); // 出栈  
            j++;  
            S.getTop(x); // 获取栈顶元素  
        }  
    }  
    return S.empty(); // 返回栈是否为空  
} 

6.运行和测试

顺序栈
1.

第一组数据:4

第二组数据:311

第三组数据:7254

第四组数据:98357

2.

第一组数据:“{{}}”

第二组数据:“{[(})]”

3.

n=5时,共42种:

链栈
1.

第一组数据:4

第二组数据:311

第三组数据:7254

第四组数据:98357

2.

第一组数据:“{{}}”

第二组数据:“{[(})]”

3.

n=5时,共42种:

栈的拓展实验

顺序栈

当入栈序列为“12345”时,出栈序列“15234”非法,“23415”合法

链栈

当入栈序列为“12345”时,出栈序列“15234”非法,“23415”合法

7.总结、心得和建议

  1. 利用栈后进先出(LIFO)的特性,可以用来实现进制转换、括号匹配以及表达式计算。
  2. 在链栈中,应该编写对应的析构函数或者销毁函数来手动释放链栈元素。
  3. 在进制转换一题中,使用字符数组下标与对应字符匹配,这种方式很巧妙。
  4. 在合法出栈序列一题中,考虑所有的情况,通过递归实现函数功能,这道题比较难,捋清思路废了不少功夫,好在收获巨大,熟悉了写递归函数情况列举以及恢复现场的重要性。
  5. 为了保证函数的健壮性,在编写每个函数前应该先思考栈为空或为满的状态,假如函数无返回值,尽量设置一个“bool”类型的返回值,通过返回的“True”或“False”来确定函数是否成功执行。
  6. 在参数传入函数时,可以选用引用传参,这样就可以避免再拷贝一份,影响执行效率。但是,如果只需要读取其中元素值,而不需要改变内容时,最好在传入时添加“const”修饰,防止被修改。

附录(源代码)

seqStack.cpp

#include <iostream>
#include <queue>
using namespace std;

#define MaxLen 100 // 最大容量
char arr[36] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};

class seqStack
{
    public:
        seqStack();      // 初始化栈
        ~seqStack();     // 析构函数
        bool empty();    // 判断栈是否为空
        bool full();     // 判断栈是否已满
        bool getTop(char &x); // 获取栈顶元素
        bool push(char x);    // 将元素入栈
        bool pop(char &x);     // 将元素出栈
        bool pop();     // 将元素出栈

    private:
        char data[MaxLen]; // 存放栈元素
        int top;    // 栈顶指针(数组下标)
};

seqStack::seqStack()
{
    top = -1; // 初始化栈顶指针为-1,表示栈为空
}

seqStack::~seqStack()
{
}

bool seqStack::empty()
{
    return top == -1; // 如果栈顶指针为-1,表示栈为空
}

bool seqStack::full()
{
    return top == MaxLen - 1; // 如果栈顶指针等于MaxLen-1,表示栈已满
}

bool seqStack::getTop(char &x)
{
    if (top == -1)
        return false; // 如果栈为空,返回false
    else
    {
        x = data[top]; // 否则将栈顶元素赋值给x
        return true;
    }
}

bool seqStack::push(char x)
{
    if (full())
        return false; // 如果栈已满,返回false
    else
    {
        data[++top] = x; // 否则将新元素放入栈顶,栈顶指针加1
        return true;
    }
}

bool seqStack::pop(char &x)
{
    if (empty())
        return false; // 如果栈为空,返回false
    else
    {
        x = data[top--]; // 否则将栈顶元素赋值给x,栈顶指针减1
        return true;
    }
}

bool seqStack::pop()
{
    if (empty())
        return false; // 如果栈为空,返回false
    else
    {
        top--; // 否则栈顶指针减1
        return true;
    }
}

bool conversion(int q, int b, char result[])
{
    if (b < 2 || b > 36 || q < 0)
    {
        return false; // 如果进制b不在2到36之间,或者被转换数q小于0,则返回false
    }
    if (q == 0)
    {
        result[0] = '0'; // 如果被转换数q为0,则结果为'0'
        result[1] = '\0';
        return true;
    }

    seqStack S; // 创建一个栈S用于存储转换结果

    while (q)
    {
        S.push(arr[q % b]); // 将q对b取余的结果压入栈S
        q = q / b; // 更新q为q除以b的商
    }

    int i = 0;
    char x;

    while (!S.empty())
    {
        S.pop(x); // 从栈S中弹出元素到x
        result[i] = x; // 将弹出的元素存入结果数组中
        i++;
    }

    result[i] = '\0'; // 在结果数组末尾添加字符串结束符
    return true;
}

bool bracketMatch(char ch[])
{
    int i = 0;
    char x;
    seqStack S; // 创建一个栈S用于匹配括号

    while (ch[i] != '\0')
    {
        if (ch[i] == '(' || ch[i] == '[' || ch[i] == '{')
        {
            S.push(ch[i]); // 如果是左括号,压入栈S
            i++;
        }
        else if (ch[i] == ')' || ch[i] == ']' || ch[i] == '}')
        {
            S.getTop(x); // 获取栈顶元素到x
            if ((ch[i] == ')' && x == '(') || (ch[i] == ']' && x == '[') || (ch[i] == '}' && x == '{'))
            {
                S.pop(); // 如果匹配成功,弹出栈顶元素
                i++;
            }
            else
            {
                return false; // 匹配失败,返回false
            }
        }
    }

    if (S.empty())
        return true; // 如果栈为空,说明匹配成功,返回true
    else
        return false; // 否则返回false
}

// 检查序列的合法性
bool sequenceLegitimacy(char ruArr[], char chuArr[], int len)
{
    seqStack S; // 创建一个栈S用于检查序列合法性
    int j = 0;
    char x;
    for (int i = 0; i < len; i++)
    {
        S.push(ruArr[i]); // 将入栈序列ruArr的元素依次压入栈S
        S.getTop(x); // 获取栈顶元素到x

        while (!S.empty() && x == chuArr[j])
        {
            S.pop(); // 如果栈非空且栈顶元素与chuArr相同,则弹出栈顶元素
            j++;
            S.getTop(x); // 获取新的栈顶元素
        }
    }
    return S.empty(); // 返回栈是否为空,判断序列合法性
}

void outSequence(seqStack &s, char *in, char *out, int len, int &num, int i = 0, int j = 0)
{
    if (i >= len)
    {
        if (s.empty()) // 结束(全部入栈过,且全部已经出栈)
        {
            cout << "第" << num + 1 << "种 : "; // 输出序列种类
            num++;
            out[j] = '\0'; // 在输出序列末尾添加字符串结束符
            cout << out << endl; // 输出当前序列
        }
        else // 全部入栈过,但未全部出栈
        {
            s.pop(out[j]); // 出栈
            outSequence(s, in, out, len, num, i, j + 1);
            // 恢复
            s.push(out[j]); // 恢复栈状态
        }
    }
    else if (i < len)
    {
        if (!s.empty()) // 未全部入栈过,且当前栈非空
        {
            s.pop(out[j]); // 出栈
            outSequence(s, in, out, len, num, i, j + 1);
            // 恢复
            s.push(out[j]); // 恢复栈状态
        }

        s.push(in[i]); // 入栈
        outSequence(s, in, out, len, num, i + 1, j);
        // 恢复
        s.pop(); // 恢复栈状态
    }
}


int main()
{

    char ch[100];
    cout << "第一组数据:4" << endl;
    conversion(4, 2, ch);
    cout << "转换为二进制为" << ch << endl;
    conversion(4, 8, ch);
    cout << "转换为八进制为" << ch << endl;
    conversion(4, 16, ch);
    cout << "转换为十六进制为" << ch << endl;
    cout << endl;
    cout << "第二组数据:311" << endl;
    conversion(311, 2, ch);
    cout << "转换为二进制为" << ch << endl;
    conversion(311, 8, ch);
    cout << "转换为八进制为" << ch << endl;
    conversion(311, 16, ch);
    cout << "转换为十六进制为" << ch << endl;
    cout << endl;
    cout << "第三组数据:7254" << endl;
    conversion(7254, 2, ch);
    cout << "转换为二进制为" << ch << endl;
    conversion(7254, 8, ch);
    cout << "转换为八进制为" << ch << endl;
    conversion(7254, 16, ch);
    cout << "转换为十六进制为" << ch << endl;
    cout << endl;
    cout << "第四组数据:98357" << endl;
    conversion(98357, 2, ch);
    cout << "转换为二进制为" << ch << endl;
    conversion(98357, 8, ch);
    cout << "转换为八进制为" << ch << endl;
    conversion(98357, 16, ch);
    cout << "转换为十六进制为" << ch << endl;
    cout << endl;

    cout << "第一组数据:“{[](){}}”" << endl;
    char ch2[] = "{[](){}}";
    if (bracketMatch(ch2))
    {
        cout << "匹配" << endl;
    }
    else
    {
        cout << "不匹配" << endl;
    }
    cout << "第二组数据:“{[(})]”" << endl;
    char ch3[] = "{[(})]";
    if (bracketMatch(ch3))
    {
        cout << "匹配" << endl;
    }
    else
    {
        cout << "不匹配" << endl;
    }
    cout << endl;

    seqStack s;
    char res[5];

    char *in = new char[5];

    for (int i = 0; i < 5; i++)
    {
        *(in + i) = arr[i + 1];
    }

    int num = 0;
    cout << "当n=5时,所有可能出栈的序列有:" << endl;
    outSequence(s, in, res, 5, num);
    cout << "共" << num << "种" << endl;

    cout << endl;
    cout << "当入栈序列为“12345”时:" << endl;
    char ruArr[] = "12345";
    char chuArr1[] = "15234";
    char chuArr2[] = "23415";
    cout << "序列“15234”是 ";
    if (sequenceLegitimacy(ruArr, chuArr1, 5))
    {
        cout << "合法";
    }
    else
    {
        cout << "非法";
    }
    cout << " 的" << endl;
    cout << "序列“23415”是 ";
    if (sequenceLegitimacy(ruArr, chuArr2, 5))
    {
        cout << "合法";
    }
    else
    {
        cout << "非法";
    }
    cout << " 的" << endl;

}

main.cpp

#include <iostream>
using namespace std;

#define MaxLen 100 // 最大容量
char arr[36] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};

class seqStack
{
    public:
        seqStack();      // 初始化
        ~seqStack();     // 析构函数
        bool empty();    // 判断栈空
        bool full();     // 判断栈满
        bool getTop(char &x); // 取栈顶元素
        bool push(char x);    // 入栈
        bool pop(char &x);     // 出栈
        bool pop();     // 出栈

    private:
        char data[MaxLen]; // 存放栈元素
        int top;    // 栈顶指针(数组下标)
};

seqStack::seqStack()
{
    top = -1;
}

seqStack::~seqStack()
{
}

bool seqStack::empty()
{
    return top == -1;
}

bool seqStack::full()
{
    return top == MaxLen - 1;
}

bool seqStack::getTop(char &x)
{
    if (top == -1)
        return false;
    else
    {
        x = data[top];
        return true;
    }
}

bool seqStack::push(char x)
{
    if (full())
        return false;
    else
    {
        data[++top] = x; // 先移动栈顶指针,再将新元素放入栈顶
        return true;
    }
}

bool seqStack::pop(char &x)
{
    if (empty())
        return false;
    else
    {
        x = data[top--]; // 先取出栈顶元素,再移动栈顶指针
        return true;
    }
}

bool seqStack::pop()
{
    if (empty())
        return false;
    else
    {
        top--;
        return true;
    }
}

bool seqConversion(int q, int b, char result[])
{
    if (b < 2 || b > 36 || q < 0)
    {
        return false;
    }
    if (q == 0)
    {
        result[0] = '0';
        result[1] = '\0';
        return true;
    }

    seqStack S;

    while (q)
    {
        S.push(arr[q % b]);
        q = q / b;
    }

    int i = 0;
    char x;

    while (!S.empty())
    {
        S.pop(x);
        result[i] = x;
        i++;
    }

    result[i] = '\0';
    return true;
}

bool seqBracketMatch(char ch[])
{
    int i = 0;
    char x;
    seqStack S;

    while (ch[i] != '\0')
    {
        if (ch[i] == '(' || ch[i] == '[' || ch[i] == '{')
        {
            S.push(ch[i]);
            i++;
        }
        else if (ch[i] == ')' || ch[i] == ']' || ch[i] == '}')
        {
            S.getTop(x);
            if ((ch[i] == ')' && x == '(') || (ch[i] == ']' && x == '[') || (ch[i] == '}' && x == '{'))
            {
                S.pop();
                i++;
            }
            else
            {
                return false;
            }
        }
    }

    if (S.empty())
        return true;
    else
        return false;

}

void seqDostack(char in[], seqStack s, char out[], int &res, int b)
{
    char x;
    if (in[0] == '\0')
    {
        if (s.empty())
        {
            res++;
            out[5] = '\0';
            cout << out << endl;
        }
        else
        {
            s.getTop(out[b]);
            b++;
            s.pop();
            seqDostack(in, s, out, res, b);
        }
    }
    else
    {
        if (!s.empty())
        {
            seqStack ts;
            char *tin, *tout;
            int c = b;
            tin = in;
            ts = s;
            tout = out;
            ts.getTop(tout[c]);
            c++;
            ts.pop();
            seqDostack(tin, ts, tout, res, c);
        }
        s.push(in[0]);
        char *temp = ++in;
        seqDostack(temp, s, out, res, b);
    }
}

// 检查序列的合法性
bool seqSequenceLegitimacy(char ruArr[], char chuArr[], int len)
{
    seqStack S;
    int j = 0;
    char x;
    for (int i = 0; i < len; i++)
    {
        S.push(ruArr[i]);
        S.getTop(x);

        while (!S.empty() && x == chuArr[j])
        {
            S.pop();
            j++;
            S.getTop(x);
        }
    }
    return S.empty();
}

typedef struct lsNode
{
    char data; //链栈结点数据域
    struct lsNode *next; //链栈结点指针域
} node;

class linkedStack
{
    public:
        linkedStack(); //初始化空栈
        ~linkedStack(); //销毁链栈
        bool empty(); //判定栈空
        bool getTop(char &x); //取栈顶元素
        void push(char x); //入栈
        bool pop(char &x); //出栈
        bool pop(); //出栈
    private:
        node* top; //栈顶指针
};

linkedStack::linkedStack()
{
    top = NULL;
}

bool linkedStack::empty()
{
    return top == NULL;
}

bool linkedStack::getTop(char &x)
{
    if (empty())
        return false; //栈空,返回false
    else
    {
        x = top->data; //取栈顶元素,用参数x返回
        return true; //取栈顶成功,返回true
    }
}

void linkedStack::push(char x)
{
    node* s = new node;
    s->data = x;
    s->next = top;
    top = s;
}

bool linkedStack::pop(char &x)
{
    if (empty())
        return false; //栈空,返回false
    else
    {
        x = top->data; //取栈顶元素,由变量x返回
        node* u = top; //栈顶指针保存到u
        top = top->next; //栈顶指针后移一个元素结点
        delete u; //释放原栈顶结点
        return true; //出栈成功,返回true
    }
}

bool linkedStack::pop()
{
    if (empty())
        return false; //栈空,返回false
    else
    {
        node* u = top; //栈顶指针保存到u
        top = top->next; //栈顶指针后移一个元素结点
        delete u; //释放原栈顶结点
        return true; //出栈成功,返回true
    }
}

linkedStack::~linkedStack()
{
    node *p, *u;
    p = top;
    while (p)
    {
        u = p;
        p = p->next;
        delete u;
    }
    top = NULL;
}

bool linkConversion(int q, int b, char result[])
{
    if (b < 2 || b > 36 || q < 0)
    {
        return false;
    }
    if (q == 0)
    {
        result[0] = '0';
        result[1] = '\0';
        return true;
    }

    linkedStack S;

    while (q)
    {
        S.push(arr[q % b]);
        q = q / b;
    }

    int i = 0;
    char x;

    while (!S.empty())
    {
        S.pop(x);
        result[i] = x;
        i++;
    }

    result[i] = '\0';
    return true;
}

bool linkBracketMatch(char ch[])
{
    int i = 0;
    char x;
    linkedStack S;

    while (ch[i] != '\0')
    {
        if (ch[i] == '(' || ch[i] == '[' || ch[i] == '{')
        {
            S.push(ch[i]);
            i++;
        }
        else if (ch[i] == ')' || ch[i] == ']' || ch[i] == '}')
        {
            if (!S.empty())
            {
                S.getTop(x);
                if ((ch[i] == ')' && x == '(') || (ch[i] == ']' && x == '[') || (ch[i] == '}' && x == '{'))
                {
                    S.pop();
                    i++;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
    }

    return S.empty();
}

// 检查序列的合法性
bool linkSequenceLegitimacy(char ruArr[], char chuArr[], int len)
{
    linkedStack S;
    int j = 0;
    char x;
    for (int i = 0; i < len; i++)
    {
        S.push(ruArr[i]);
        S.getTop(x);

        while (!S.empty() && x == chuArr[j])
        {
            S.pop();
            j++;
            S.getTop(x);
        }
    }
    return S.empty();
}

void work(char *a, char *b, int m, int &res, const int &n)
{
    if (m == n - 1)
    {
        if (linkSequenceLegitimacy(b, a, n))
        {
            a[n] = '\0';
            cout << a << endl;
            res++;
        }
        return;
    }
    for (int i = m; i < n; i++)
    {
        swap(a[i], a[m]);
        work(a, b, m + 1, res, n);
        swap(a[i], a[m]);
    }
}

int main()
{
    char linkch[200];
    linkConversion(37, 20, linkch);

    cout << linkch << endl;

    char linkch2[] = "{[(})]";
    cout << linkBracketMatch(linkch2);
    cout << endl;


    linkedStack links;
    char linkb[] = "12345";
    char linka[] = "12345";

    int res = 0;

    work(linkb, linkb, 0, res, 5);

    cout << endl;

    cout << "res=" << res << endl;

    return 0;
}

linkedStack.cpp

#include <iostream>
using namespace std;

char arr[36] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};

// 定义链栈结点
typedef struct lsNode
{
    char data; // 链栈结点数据域
    struct lsNode *next; // 链栈结点指针域
} node;

// 定义链栈类
class linkedStack
{
    public:
        linkedStack(); // 初始化空栈
        ~linkedStack(); // 销毁链栈
        bool empty(); // 判定栈空
        bool getTop(char &x); // 取栈顶元素
        void push(char x); // 入栈
        bool pop(char &x); // 出栈
        bool pop(); // 出栈
    private:
        node* top; // 栈顶指针
};

// 初始化链栈
linkedStack::linkedStack()
{
    top = NULL;
}

// 判定栈空
bool linkedStack::empty()
{
    return top == NULL;
}

// 取栈顶元素
bool linkedStack::getTop(char &x)
{
    if (empty())
        return false; // 栈空,返回false
    else
    {
        x = top->data; // 取栈顶元素,用参数x返回
        return true; // 取栈顶成功,返回true
    }
}

// 入栈
void linkedStack::push(char x)
{
    node* s = new node;
    s->data = x;
    s->next = top;
    top = s;
}

// 出栈,返回出栈元素
bool linkedStack::pop(char &x)
{
    if (empty())
        return false; // 栈空,返回false
    else
    {
        x = top->data; // 取栈顶元素,由变量x返回
        node* u = top; // 栈顶指针保存到u
        top = top->next; // 栈顶指针后移一个元素结点
        delete u; // 释放原栈顶结点
        return true; // 出栈成功,返回true
    }
}

// 出栈,不返回出栈元素
bool linkedStack::pop()
{
    if (empty())
        return false; // 栈空,返回false
    else
    {
        node* u = top; // 栈顶指针保存到u
        top = top->next; // 栈顶指针后移一个元素结点
        delete u; // 释放原栈顶结点
        return true; // 出栈成功,返回true
    }
}

// 销毁链栈
linkedStack::~linkedStack()
{
    node *p, *u;
    p = top;
    while (p)
    {
        u = p;
        p = p->next;
        delete u;
    }
    top = NULL;
}

bool conversion(int q, int b, char result[])
{
    if (b < 2 || b > 36 || q < 0)
    {
        return false; // 如果进制不在2到36之间或者被转换的数小于0,则返回false
    }
    if (q == 0)
    {
        result[0] = '0';
        result[1] = '\0';
        return true; // 如果被转换的数为0,则结果为"0",返回true
    }

    linkedStack S; // 创建一个链式栈对象S

    while (q)
    {
        S.push(arr[q % b]); // 将q除以b的余数入栈
        q = q / b; // 更新q的值
    }

    int i = 0;
    char x;

    while (!S.empty())
    {
        S.pop(x); // 出栈
        result[i] = x; // 将出栈的元素存入结果数组
        i++;
    }

    result[i] = '\0'; // 在结果数组末尾添加字符串结束符
    return true;
}

bool bracketMatch(char ch[])
{
    int i = 0;
    char x;
    linkedStack S; // 创建一个链式栈对象S

    while (ch[i] != '\0')
    {
        if (ch[i] == '(' || ch[i] == '[' || ch[i] == '{')
        {
            S.push(ch[i]); // 如果是左括号,入栈
            i++;
        }
        else if (ch[i] == ')' || ch[i] == ']' || ch[i] == '}')
        {
            if (!S.empty())
            {
                S.getTop(x); // 获取栈顶元素
                if ((ch[i] == ')' && x == '(') || (ch[i] == ']' && x == '[') || (ch[i] == '}' && x == '{'))
                {
                    S.pop(); // 出栈
                    i++;
                }
                else
                {
                    return false; // 括号不匹配,返回false
                }
            }
            else
            {
                return false; // 右括号多于左括号,返回false
            }
        }
    }

    return S.empty(); // 返回栈是否为空
}

// 检查序列的合法性
bool sequenceLegitimacy(char ruArr[], char chuArr[], int len)
{
    linkedStack S; // 创建一个链式栈对象S
    int j = 0;
    char x;
    for (int i = 0; i < len; i++)
    {
        S.push(ruArr[i]); // 将ruArr中的元素依次入栈
        S.getTop(x); // 获取栈顶元素

        while (!S.empty() && x == chuArr[j])
        {
            S.pop(); // 出栈
            j++;
            S.getTop(x); // 获取栈顶元素
        }
    }
    return S.empty(); // 返回栈是否为空
}

void outSequence(linkedStack &s, char *in, char *out, int len, int &num, int i = 0, int j = 0)
{
    if (i >= len)
    {
        if (s.empty()) // 结束(全部入栈过,且全部已经出栈)
        {
            cout << "第" << num + 1 << "种 : ";
            num++;
            out[j] = '\0'; // 在输出数组末尾添加字符串结束符
            cout << out << endl; // 输出结果
        }
        else // 全部入栈过,但未全部出栈
        {
            s.pop(out[j]); // 出栈
            outSequence(s, in, out, len, num, i, j + 1);
            // 恢复
            s.push(out[j]); // 入栈
        }
    }
    else if (i < len)
    {
        if (!s.empty()) // 未全部入栈过,且当前栈非空
        {
            s.pop(out[j]); // 出栈
            outSequence(s, in, out, len, num, i, j + 1);
            // 恢复
            s.push(out[j]); // 入栈
        }

        s.push(in[i]); // 入栈
        outSequence(s, in, out, len, num, i + 1, j);
        // 恢复
        s.pop(); // 出栈
    }
}

int main()
{
    linkedStack s;
    char res[5];

    char *in = new char[5];

    for (int i = 0; i < 5; i++)
    {
        *(in + i) = arr[i + 1];
    }

    int num = 0;
    outSequence(s, in, res, 5, num);
    cout << endl << num << endl;

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值