PTA(栈和队列)1-4 在一个数组中实现两个堆栈

1-4 在一个数组中实现两个堆栈

分数 4

作者 陈越

单位 浙江大学

本题要求在一个数组中实现两个堆栈。

函数接口定义:

1
2
3
Stack CreateStack( int MaxSize );
bool Push( Stack S, ElementType X, int Tag );
ElementType Pop( Stack S, int Tag );

其中Tag是堆栈编号,取1或2;MaxSize堆栈数组的规模;Stack结构定义如下:

1
2
3
4
5
6
7
typedef int Position;
struct SNode {
ElementType *Data;
Position Top1, Top2;
int MaxSize;
};
typedef struct SNode *Stack;

注意:如果堆栈已满,Push函数必须输出“Stack Full”并且返回false;如果某堆栈是空的,则Pop函数必须输出“Stack Tag Empty”(其中Tag是该堆栈的编号),并且返回ERROR。

裁判测试程序样例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <stdio.h>
#include <stdlib.h>

#define ERROR 1e8
typedef int ElementType;
typedef enum { push, pop, end } Operation;
typedef enum { false, true } bool;
typedef int Position;
struct SNode {
ElementType *Data;
Position Top1, Top2;
int MaxSize;
};
typedef struct SNode *Stack;

Stack CreateStack( int MaxSize );
bool Push( Stack S, ElementType X, int Tag );
ElementType Pop( Stack S, int Tag );

Operation GetOp(); /* details omitted */
void PrintStack( Stack S, int Tag ); /* details omitted */

int main()
{
int N, Tag, X;
Stack S;
int done = 0;

scanf("%d", &N);
S = CreateStack(N);
while ( !done ) {
switch( GetOp() ) {
case push:
scanf("%d %d", &Tag, &X);
if (!Push(S, X, Tag)) printf("Stack %d is Full!\n", Tag);
break;
case pop:
scanf("%d", &Tag);
X = Pop(S, Tag);
if ( X==ERROR ) printf("Stack %d is Empty!\n", Tag);
break;
case end:
PrintStack(S, 1);
PrintStack(S, 2);
done = 1;
break;
}
}
return 0;
}

/* 你的代码将被嵌在这里 */

输入样例:

1
2
3
4
5
6
7
8
9
10
11
12
5
Push 1 1
Pop 2
Push 2 11
Push 1 2
Push 2 12
Pop 1
Push 2 13
Push 2 14
Push 1 3
Pop 2
End

输出样例:

1
2
3
4
5
6
Stack 2 Empty
Stack 2 is Empty!
Stack Full
Stack 1 is Full!
Pop from Stack 1: 1
Pop from Stack 2: 13 12 11

此题用的是共享栈

  • 使用两个栈顶指针

image-20251021213555350

**定义:**利用栈底位置相对不变的特性,可以让==两个顺序栈共享==一个一维数组空间,将两个栈的栈底 分别设置在共享空间的两端,两个栈顶向共享空间的中间延伸。

正确答案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
Stack CreateStack( int MaxSize ) {
Stack s; // s是指向栈的指针
s = (Stack) malloc(sizeof (struct SNode)); // 给结构体分配内存
s->Data = (ElementType*) malloc(MaxSize * sizeof (ElementType)); // 给数组分配内存
s->MaxSize = MaxSize;
s->Top1 = -1; // Top1指针初始化指向-1
s->Top2 = MaxSize; // Top1指针初始化指向Maxsize
return s;
}

bool Push( Stack S, ElementType X, int Tag ) {
if (S->Top1 == S->Top2 - 1) { // 说明栈满了
// 修正 1: 必须先输出错误信息
printf("Stack Full\n");
return false; // 不能再放了,直接退出
}
if (Tag == 1) { //进入第一个栈
S->Top1++;
S->Data[S->Top1] = X;
} else if (Tag == 2) { //进入第二个栈
S->Top2--;
S->Data[S->Top2] = X;
}
return true;
}

ElementType Pop( Stack S, int Tag ) {
if (Tag == 1) { // 如果是第一个栈的栈顶元素出栈
if (S->Top1 == -1) { // 如果是空栈,返回ERROR,方便main中输出栈为空
printf("Stack %d Empty\n", Tag);
return ERROR;
} else { // 栈中有元素,返回该栈顶元素
return S->Data[S->Top1--]; // 返回元素之后,指针移动
}
} else { // 如果是第二个栈的栈顶元素出栈
if (S->Top2 == S->MaxSize) { // 如果是空栈,返回ERROR,方便main中输出栈为空
printf("Stack %d Empty\n", Tag);
return ERROR;
} else { // 栈中有元素,返回该栈顶元素
return S->Data[S->Top2++]; // 返回元素之后,指针移动
}
}
}

我的段错误答案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Stack CreateStack( int MaxSize ) {
Stack s; // s是指向栈的指针
s = (Stack) malloc(MaxSize * sizeof (ElementType));
s->Top1 = -1; // Top1指针初始化指向-1
s->Top2 = MaxSize; // Top1指针初始化指向Maxsize
return s;
}

bool Push( Stack S, ElementType X, int Tag ) {
if (S->Top1 == S->Top2 - 1) { // 说明栈满了
return false; // 不能再放了,直接退出
}
if (Tag == 1) { //进入第一个栈
S->Top1++;
S->Data[S->Top1] = X;
} else if (Tag == 2) { //进入第二个栈
S->Top2--;
S->Data[S->Top2] = X;
}
return true;
}

ElementType Pop( Stack S, int Tag ) {
if (Tag == 1) { // 如果是第一个栈的栈顶元素出栈
if (S->Top1 == -1) { // 如果是空栈,返回1e8,方便main中输出栈为空
return 1e8;
} else { // 栈中有元素,返回该栈顶元素
return S->Data[S->Top1--]; // 返回元素之后,指针移动
}
} else { // 如果是第二个栈的栈顶元素出栈
if (S->Top2 == S->MaxSize) { // 如果是空栈,返回1e8,方便main中输出栈为空
return 1e8;
} else { // 栈中有元素,返回该栈顶元素
return S->Data[S->Top2++]; // 返回元素之后,指针移动
}
}
}

错误点1:CreateStack 函数内存分配错误

1
s = (Stack) malloc(MaxSize * sizeof (ElementType));
  • Stack是指向结构体的指针(包含Top1、Top2、Data、MaxSize等成员),则此处分配的内存大小错误:

    代码试图用MaxSize * sizeof(ElementType)分配内存,但这其实是给数据数组分配的大小,而非给栈结构体本身分配内存。

  • 后果:s 指向的内存空间过小,无法容纳结构体的 Top1Top2 等成员。后续访问 s->Top1s->Top2 时,会写入未分配的内存区域,导致内存越界,触发段错误。

错误点2:结构体 Data 数组未分配内存

代码中使用 S->Data[S->Top1] 访问数据,但从未给 Data 指针分配内存:

  • Data 是结构体中用于存储栈元素的数组指针,需要单独分配内存(大小为 MaxSize * sizeof(ElementType))。
  • 后果:S->Data 是野指针(未初始化的指针),访问 S->Data[...] 会操作非法内存,导致段错误。

错误点3:结构体 MaxSize 成员未初始化

1
s->MaxSize = MaxSize;

段错误解决后出现的答案错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Stack CreateStack( int MaxSize ) {
Stack s; // s是指向栈的指针
s = (Stack) malloc(sizeof (struct SNode)); // 给结构体分配内存
s->Data = (ElementType*) malloc(MaxSize * sizeof (ElementType)); // 给数组分配内存
s->MaxSize = MaxSize;
s->Top1 = -1; // Top1指针初始化指向-1
s->Top2 = MaxSize; // Top1指针初始化指向Maxsize
return s;
}

bool Push( Stack S, ElementType X, int Tag ) {
if (S->Top1 == S->Top2 - 1) { // 说明栈满了
return false; // 不能再放了,直接退出
}
if (Tag == 1) { //进入第一个栈
S->Top1++;
S->Data[S->Top1] = X;
} else if (Tag == 2) { //进入第二个栈
S->Top2--;
S->Data[S->Top2] = X;
}
return true;
}

ElementType Pop( Stack S, int Tag ) {
if (Tag == 1) { // 如果是第一个栈的栈顶元素出栈
if (S->Top1 == -1) { // 如果是空栈,返回1e8,方便main中输出栈为空
return 1e8;
} else { // 栈中有元素,返回该栈顶元素
return S->Data[S->Top1--]; // 返回元素之后,指针移动
}
} else { // 如果是第二个栈的栈顶元素出栈
if (S->Top2 == S->MaxSize) { // 如果是空栈,返回1e8,方便main中输出栈为空
return 1e8;
} else { // 栈中有元素,返回该栈顶元素
return S->Data[S->Top2++]; // 返回元素之后,指针移动
}
}
}

观察输出,要在函数中也有对应输出

1.Pop中

要加上

1
printf("Stack Full\n");

因为main中没有

2.Push中

要变为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ElementType Pop( Stack S, int Tag ) {
if (Tag == 1) { // 如果是第一个栈的栈顶元素出栈
if (S->Top1 == -1) { // 如果是空栈,返回ERROR,方便main中输出栈为空
printf("Stack %d Empty\n", Tag);
return ERROR;
} else { // 栈中有元素,返回该栈顶元素
return S->Data[S->Top1--]; // 返回元素之后,指针移动
}
} else { // 如果是第二个栈的栈顶元素出栈
if (S->Top2 == S->MaxSize) { // 如果是空栈,返回ERROR,方便main中输出栈为空
printf("Stack %d Empty\n", Tag);
return ERROR;
} else { // 栈中有元素,返回该栈顶元素
return S->Data[S->Top2++]; // 返回元素之后,指针移动
}
}
}

因为main中会输出的是Stack 2 is Empty!,而整个输出中会先输出一个Stack 2 Empty ,没有is,说明要在函数里面先输出一段