合肥工业大学 2023级 数据结构 实验三 完整报告
1.实验目标
- 熟练掌握栈的顺序存储结构和链式存储结构。
- 熟练掌握栈的有关算法设计,并在顺序栈和链栈上实现。
- 根据具体给定的需求,合理设计并实现相关结构和算法。
2.实验要求
顺序栈的实验要求
- 顺序栈结构和运算定义,算法的实现以库文件方式实现,比如seqStack.h,不得在测试主程序中直接实现;
- 实验程序有较好可读性,各运算和变量的命名直观易懂,符合软件工程要求;
- 程序有适当的注释。
链栈实验要求
- 本次实验中的链栈结构指带头结点的单链表;
- 链栈结构和运算定义,算法的实现以库文件方式实现,比如linkedStack.h,不得在测试主程序中直接实现;
- 实验程序有较好可读性,各运算和变量的命名直观易懂,符合软件工程要求;
- 程序有适当的注释。
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.
【算法设计思想】
-
首先,函数接受三个参数:被转换的整数 q,目标进制 b,以及一个用于存储转换结果的字符数组 result[]。
-
然后,代码会进行一些基本的参数检查:
如果进制 b 不在 2 到 36 之间,或者被转换数 q 小于 0,则函数会返回 false。
如果被转换数 q 为 0,则结果数组中的第一个元素会被设置为 '0',然后返回 true。
-
接着,代码创建了一个顺序栈 S ,用于存储转换结果。
-
在一个 while 循环中,代码会不断地将 q 对 b 取余的结果压入栈 S 中,并更新 q 为 q 除以 b 的商,直到 q 为 0。
-
然后,代码通过一个 while 循环从栈 S 中依次弹出元素到变量 x,然后将这些元素存入结果数组 result[] 中,直到栈 S 为空。
-
最后,代码在结果数组的末尾添加字符串结束符 '\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.
【算法设计思想】
-
首先,定义了一个变量i用于遍历输入的字符数组ch,同时定义了一个字符变量x用于存储栈顶元素,以及一个顺序栈S用于匹配括号。
-
进入循环,遍历输入的字符数组ch,直到遇到字符串结束符\0为止。
-
在循环中,首先判断当前字符是否为左括号
(
,[
,{
,如果是,则将其压入栈S中,并且i自增。 -
如果当前字符不是左括号,而是右括号
)
,]
,}
,则需要进行匹配操作:获取栈顶元素到变量x中。
检查当前字符与栈顶元素是否匹配,即右括号与对应的左括号匹配。
如果匹配成功,弹出栈顶元素,同时i自增。
如果匹配失败,直接返回false,表示括号匹配失败。
-
循环结束后,如果栈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.
【算法设计思想】
通过不断模拟元素的入栈和出栈操作,来生成所有可能的出栈顺序。具体执行过程为:
-
如果 i 大于等于 len,表示已经处理完所有输入元素:
如果栈为空,说明全部元素已经入栈并出栈,输出当前出栈顺序。
如果栈不为空,表示还有元素未出栈,则将栈顶元素出栈,继续递归处理。处理完后,将之前出栈的元素重新入栈,以便尝试其他出栈顺序。
-
如果 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.
【算法设计思想】
-
首先,函数会检查输入的参数是否符合要求:
如果进制b不在2到36之间,或者被转换的数q小于0,则函数会返回false。
如果被转换的数q为0,则结果数组中只存储字符'0',然后返回true。
-
接着,函数会创建一个链栈S。
-
然后,进入一个循环,将被转换的数q按照给定的进制b进行转换:
每次取q除以b的余数,将余数压入栈S中。
更新q的值为q除以b的商。
-
接下来,从栈S中依次弹出元素,将其存入结果数组中,直到栈为空。
-
最后,将结果数组末尾添加字符串结束符'\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。最后,函数返回栈是否为空。具体执行过程为:
- 首先,函数初始化了一个索引变量i,并声明了一个字符变量x以及一个链栈S。
- 然后,函数通过while循环遍历输入的字符数组ch,直到遇到空字符为止。在循环中,它检查每个字符是否是左括号或右括号,并根据情况执行相应的操作。
- 如果是左括号,则将其入栈,并递增索引i。
- 如果是右括号,则首先检查栈是否为空。如果栈不为空,则获取栈顶元素,并与当前字符进行匹配。如果匹配成功,则出栈,并递增索引i;如果匹配不成功,则返回false。如果栈为空,说明右括号多于左括号,也返回false。
- 最后,函数返回栈是否为空,以判断括号是否匹配完全。
【算法描述】
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.
【算法设计思想】
通过不断模拟元素的入栈和出栈操作,来生成所有可能的出栈顺序。具体执行过程为:
-
如果 i 大于等于 len,表示已经处理完所有输入元素:
如果栈为空,说明全部元素已经入栈并出栈,输出当前出栈顺序。
如果栈不为空,表示还有元素未出栈:将栈顶元素出栈,继续递归处理。处理完后,将之前出栈的元素重新入栈,以便尝试其他出栈顺序。
-
如果 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(); // 出栈
}
}
栈的扩展实验
顺序栈
【算法设计思想】
-
创建一个顺序栈S,用于检查序列的合法性。
-
初始化变量j为0,用于追踪chuArr数组的索引。
-
在for循环中,遍历ruArr数组的元素:
将ruArr[i]元素依次压入栈S中。
获取栈顶元素到变量x。
进入while循环,只要栈不为空且栈顶元素与chuArr[j]相同:弹出栈顶元素。索引j增加。获取新的栈顶元素到变量x。
循环结束后,继续遍历下一个元素。
-
最终,通过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(); // 返回栈是否为空,判断序列合法性
}
链栈
【算法设计思想】
-
创建一个链栈S。
-
通过循环遍历ruArr中的元素,依次将其入栈。
-
每次入栈后,通过S.getTop(x)获取栈顶元素x。
-
进入一个内部循环,只要栈不为空且栈顶元素x等于chuArr中的元素chuArr[j],则执行以下操作:
出栈操作S.pop()。
增加j的值,用于遍历chuArr。
再次通过S.getTop(x)获取栈顶元素x。
-
最终返回栈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.总结、心得和建议
- 利用栈后进先出(LIFO)的特性,可以用来实现进制转换、括号匹配以及表达式计算。
- 在链栈中,应该编写对应的析构函数或者销毁函数来手动释放链栈元素。
- 在进制转换一题中,使用字符数组下标与对应字符匹配,这种方式很巧妙。
- 在合法出栈序列一题中,考虑所有的情况,通过递归实现函数功能,这道题比较难,捋清思路废了不少功夫,好在收获巨大,熟悉了写递归函数情况列举以及恢复现场的重要性。
- 为了保证函数的健壮性,在编写每个函数前应该先思考栈为空或为满的状态,假如函数无返回值,尽量设置一个“bool”类型的返回值,通过返回的“True”或“False”来确定函数是否成功执行。
- 在参数传入函数时,可以选用引用传参,这样就可以避免再拷贝一份,影响执行效率。但是,如果只需要读取其中元素值,而不需要改变内容时,最好在传入时添加“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;
}