提问人:bluediager 提问时间:10/24/2023 最后编辑:Okabluediager 更新时间:10/24/2023 访问量:91
括号、大括号、副括号匹配的 2 项测试失败
Failing 2 tests in bracket,braces, paranthesis matching
问:
试图让所有测试用例都通过,但根据测试用例的不同,我总是得到很少或很多测试用例错误。我有一种感觉,好像我错过了一些重要的东西,但无数个小时后,我仍然不知道我错过了什么。
测试用例: 12 是字符串数,后跟字符串数 空行是要测试的第一个字符串。
12
([])
(([()])))
([()[]()])()
(([()])
([])
(([()])))
([()[]()])()
(
(]
)(
][
预期输出:
Yes
Yes
No
Yes
No
Yes
No
Yes
No
No
No
No
我的输出:
Yes
Yes
No
Yes
Yes // should be no
Yes
No
Yes
Yes // should be no
No
No
No
失败案例:
([])
(
main.c
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
void ClearKeyboardBuffer(void) {
char c;
int noc;
noc = scanf("%c", &c);
while (noc == 1 && c != '\n') {
scanf("%c", &c);
}
}
Boolean isMatch(void) {
STACK hStack;
int noc;
char c;
Boolean m = TRUE;
hStack = StackInitDefault();
if (hStack == NULL) {
printf("Failed to allocate space for stack object.\n");
exit(2);
}
noc = scanf("%c", &c);
while (noc == 1 && c != '\n') {
if (StackIsEmpty(hStack)) {
if (c == '(' || c == '[' || c == '{') {
StackPush(hStack, c);
} else if (c == ')' || c == ']' || c == '}') {
m = FALSE;
}
} else if (!StackIsEmpty(hStack)) {
if (c == '(' || c == '[' || c == '{') {
StackPush(hStack, c);
} else if (c == ')' || c == ']' || c == '}') {
if (c == ')' && StackTop(hStack, NULL) == '(') {
StackPop(hStack);
} else if (c == ']' && StackTop(hStack, NULL) == '[') {
StackPop(hStack);
} else if (c == '}' && StackTop(hStack, NULL) == '{') {
StackPop(hStack);
} else {
m = FALSE;
}
}
}
noc = scanf("%c", &c);
}
return m;
}
int main(int argc, const char * argv[]) {
STACK hStack;
int n;
hStack = StackInitDefault(); // initialize the object
if (hStack == NULL) {
printf("Failed to allocate space for stack object.\n");
exit(1);
}
scanf("%d", &n); // get number of strings that the user will be inputting
ClearKeyboardBuffer();
while (n--) {
if (isMatch()) {
printf("Yes\n");
} else {
printf("No\n");
}
while (!StackIsEmpty(hStack)) {
StackPop(hStack);
}
}
StackDestroy(&hStack);
return 0;
}
堆栈.c
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
#include "status.h"
struct node;
typedef struct node Node;
struct node {
char value;
Node* next;
};
struct stack {
Node* head;
};
typedef struct stack Stack;
STACK StackInitDefault(void) {
Stack* pStack = (Stack*)malloc(sizeof(Stack));
if (pStack != NULL) {
pStack->head = NULL;
}
return pStack;
}
Boolean StackIsEmpty(STACK hStack) {
Stack* pStack = (Stack*)hStack;
return (pStack->head == NULL)?TRUE:FALSE;
}
char StackTop(STACK hStack, Status* pStatus) {
Stack* pStack = (Stack*)hStack;
if (StackIsEmpty(hStack)) {
if (pStatus != NULL) {
*pStatus = FAILURE;
}
return 'e';
}
if (pStatus != NULL) {
*pStatus = SUCCESS;
}
return pStack->head->value;
}
Status StackPush(STACK hStack, char c) {
Stack* pStack = (Stack*)hStack;
Node* temp = (Node*)malloc(sizeof(Node));
if (temp == NULL) {
return FAILURE;
}
temp->value = c;
temp->next = pStack->head;
pStack->head = temp;
return SUCCESS;
}
Status StackPop(STACK hStack) {
Stack* pStack = (Stack*)hStack;
Node* temp;
if (StackIsEmpty(hStack)) {
return FAILURE;
}
temp = pStack->head;
pStack->head = pStack->head->next;
free(temp);
return SUCCESS;
}
void StackDestroy(STACK* phStack) {
Stack* pStack = (Stack*)*phStack;
Node* temp = pStack->head;
while (pStack->head != NULL) {
temp = pStack->head;
pStack->head = pStack->head->next;
free(temp);
}
free(pStack);
*phStack = NULL;
}
堆栈.h
#ifndef stack_h
#define stack_h
#include "status.h"
typedef void* STACK;
STACK StackInitDefault(void);
Status StackPush(STACK hStack, char c);
Status StackPop(STACK hStack);
char StackTop(STACK hStack, Status* pStatus);
void StackDestroy(STACK* phStack);
Boolean StackIsEmpty(STACK hStack);
#endif /* stack_h */
状态.h
#ifndef STATUS_H
#define STATUS_H
enum status { FAILURE, SUCCESS };
typedef enum status Status;
enum boolean { FALSE, TRUE };
typedef enum boolean Boolean;
#endif
答:
这些评论基本上涵盖了这里的所有问题,但我将尝试进行总结。
主要问题是,为了平衡表达式,应在表达式完成解析后检查堆栈是否为空。这不会在您的代码中完成。
第二个问题是,您对某些测试用例的期望似乎是错误的(例如,期望 )。Yes
(([()])))
其他问题包括:
in 和 in 不是同一个对象。里面的对象永远不会传递给 ,而里面的对象是没有意义的。STACK hStack;
main
STACK hStack;
isMatch
isMatch
StackDestroy
main
最普遍的问题之一是此代码中有相当多的重复。结构,例如
if (StackIsEmpty(hStack)) {
/* ... */
} else if (!StackIsEmpty(hStack)) {
/* ... */
过于冗长。分支条件可以仅由语句暗示。else
整个 push & pop 部分花费大量时间检查不必要或冗余的条件。实际上,对于表达式中的每个角色,只需执行几件事isMatch
- 给定一个开始字符 (, , ),将其推送到堆栈中。
(
[
{
- 给定结束字符 (, , ),如果堆栈为空,或者堆栈顶部不是关联的开始字符,则返回无效结果。
)
]
}
您实际上是在输入行方面工作,但通过一次从标准输入中读取一个字符来做到这一点。至少,有人可能会建议不要使用 ,但更不用说用 读取整行,然后将其处理为字符串的可能性,这将是失职的。只要你的线条不是很长,这很简单。getchar
scanf("%c", ...)
fgets
考虑到以下评论,一些明显的班级/课程/讲师/教授特定的批评:
老实说,我不确定。我确实同意很多事情看起来有点毫无意义,但教授真的很老派,他希望我们练习将堆栈对象视为不透明对象。这不是我个人制作这个项目的方式,但这是他希望我们这样做的方式。
这两者基本上都是噪音:
enum status { FAILURE, SUCCESS };
typedef enum status Status;
enum boolean { FALSE, TRUE };
typedef enum boolean Boolean;
这两个枚举都可以很容易地用 type: 表示,并且自 C99 以来一直通过 <stdbool.h>
提供(C23 将使它们成为关键字)。bool
true
false
这typedef
typedef void* STACK;
不是很好。 不需要便于使用不透明类型。不透明类型本质上只是指向不完整类型(一种没有定义的可识别类型,即有关其大小的信息)的指针。对于不透明类型,标头可以仅包含void *
typedef struct stack Stack;
Stack *StackInitDefault(void);
替换为源文件中的定义。struct stack
此外,-ing 指针有些争议,但最常见的建议是避免这样做。最重要的是,不需要将 a 显式转换为另一种指针类型,因为 a 可以隐式转换为任何其他指针类型。typedef
void *
void *
(如果你的编译器在抱怨,你可能使用的是 C++ 编译器,而不是 C 编译器。)
同样,做任何你需要做的事情来通过课程,但其中一些要求不是好的做法。
下面是一个遵循上述大部分建议的实现。它避免了 -ing 一起。 不存在,因为它不需要。它只是检查所有输入行(而不是从第一行派生的固定数量的行),或者运行当前的测试用例。typedef
StackTop
一些典型的边缘情况:将空指针传递给任何库函数,或弹出一个空堆栈都是未定义的行为,并将其参数保留为调用者处理的悬空指针(模仿)。StackDestroy
free
用法示例:
$ ./a.out tests
"" -> PASS
"([])" -> PASS
"(([()])))" -> PASS
"([()[]()])()" -> PASS
"(([()])" -> PASS
"(([()])" -> PASS
"(([()])))" -> PASS
"([()[]()])()" -> PASS
"(" -> PASS
"(]" -> PASS
")(" -> PASS
"][" -> PASS
$ ./a.out
[]
"[]" true
({[]})
"({[]})" true
int main(int argc, char *argv[]) { puts("Hello world!"); }
"int main(int argc, char *argv[]) { puts("Hello world!"); }" true
)()(((){}{})()
")()(((){}{})()" false
代码:
stack.h
:
#ifndef STACK_H
#define STACK_H
#include <stdbool.h>
struct stack;
struct stack *StackInitDefault(void);
bool StackIsEmpty(struct stack *);
bool StackPush(struct stack *, char);
char StackPop(struct stack *);
void StackDestroy(struct stack *);
#endif
stack.c
:
#include <stdlib.h>
#include "stack.h"
struct node {
char value;
struct node *prev;
};
struct stack {
struct node *top;
};
struct stack *StackInitDefault(void)
{
return calloc(1, sizeof (struct stack));
}
bool StackIsEmpty(struct stack *s)
{
return !s->top;
}
bool StackPush(struct stack *s, char c)
{
struct node *n = malloc(sizeof *n);
if (!n)
return false;
n->value = c;
n->prev = s->top;
s->top = n;
return true;
}
char StackPop(struct stack *s)
{
struct node *n = s->top;
char value = n->value;
s->top = n->prev;
free(n);
return value;
}
/* slightly inefficient being written in terms of `StackPop`,
* but keeps things simple */
void StackDestroy(struct stack *s)
{
while (!StackIsEmpty(s))
(void) StackPop(s);
free(s);
}
main.c
:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "stack.h"
#define stringify(b) ((b) ? "true" : "false")
/* running out of memory renders this program useless
* bail out, let the OS clean up */
static void fatal_memory(void)
{
fputs("CRITICAL: Out of memory.\n", stderr);
exit(EXIT_FAILURE);
}
static char invert(char c)
{
switch (c) {
case '(': return ')';
case '[': return ']';
case '{': return '}';
}
return '\0';
}
static bool is_balanced(const char *data)
{
struct stack *st = StackInitDefault();
if (!st)
fatal_memory();
for (char c; (c = *data); data++) {
switch (c) {
case '(':
case '[':
case '{':
if (!StackPush(st, c))
fatal_memory();
break;
case ')':
case ']':
case '}':
if (StackIsEmpty(st) || invert(StackPop(st)) != c) {
StackDestroy(st);
return false;
}
break;
}
}
bool result = StackIsEmpty(st);
StackDestroy(st);
return result;
}
static void do_basic_testcases(void)
{
const struct {
const char *string;
const bool expect;
} tests[] = {
{ "", true },
{ "([])", true },
{ "(([()])))", false },
{ "([()[]()])()", true },
{ "(([()])", false },
{ "(([()])", false },
{ "(([()])))", false },
{ "([()[]()])()", true },
{ "(", false },
{ "(]", false },
{ ")(", false },
{ "][", false }
};
for (size_t i = 0; i < sizeof tests / sizeof *tests; i++) {
bool expect = tests[i].expect;
bool actual = is_balanced(tests[i].string);
printf("\"%s\" -> ", tests[i].string);
if (expect == actual)
puts("PASS");
else
printf("FAIL: `%s` expected, got `%s`\n", stringify(expect), stringify(actual));
}
}
int main(int argc, char **argv)
{
if (argc > 1 && 0 == strcmp("tests", argv[1]))
do_basic_testcases();
else {
char line[4096];
while (fgets(line, sizeof line, stdin)) {
line[strcspn(line, "\n")] = '\0';
printf("\"%s\" %s\n", line, stringify(is_balanced(line)));
}
}
}
评论
PASS
评论