文章为作者记录学习过程,小白一枚,各路大佬多多提建议,感激不尽
题目
前言
本文是作者在学习数据结构时写在课程OJ的代码,在OJ上运行答案正确,编译器版本为GCC5.4,如有不足还望指正。
一、3.17-逆序列
试写一算法,识别依次读入的一个以 @ @ @ 为结束符的字符序列是否为形如 “ “ “序列 1 & 1\ \& 1 & 序列 2 ” 2” 2”模式的字符序列。其中序列 1 1 1 和序列 2 2 2 中都不包含字符 “ & ” “\&” “&”,且序列 2 2 2 是序列 1 1 1 的逆序列。例如, “ a + b & b + a ” “a+b\&b+a” “a+b&b+a” 是属于该模式的字符序列,而 “ 1 + 3 & 3 − 1 ” “1+3\&3-1” “1+3&3−1” 则不是。
输入: 输入字符序列。
输出: 如果序列符合模式则输出 1 1 1,不符合则输出 0 0 0。
输入示例:
a+b&b+a@
输出示例:
1
代码:
/* 试写一算法,识别依次读入的一个以@为结束符的字符序列是否为形如“序列1&序列2”模式的字符
* 序列。其中序列1和序列2中都不包含字符“&”,且序列2是序列1的逆序列。例如,“a+b&b+a”是
* 属于该模式的字符序列,而“1+3&3-1”则不是。*/
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i = 0;
char c = '0';
char *Str;
Str = (char *)malloc((i + 1) * sizeof(char));
while ((c = getchar()) != '&') {
Str[i++] = c;
}
i--;
while ((c = getchar()) != '@' && i != -1) {
if (Str[i--] == c)
continue;
else {
printf("0\n");
return 0;
}
}
printf("1\n");
return 0;
}
二、3.18-括号配对
试写一个判别表达式中开,闭括号是否配对出现的算法。
比如: ( a + b ( c − d ) ) (a+b(c-d)) (a+b(c−d)) 是配对出现的,而 ( d − e ) ) (d-e)) (d−e)) 不是配对出现的。
输入: 表达式,如: a + b ( c − d ) a+b(c-d) a+b(c−d)。
输出: 表达式中的括号配对出现,则输出 1 1 1,否则输出 0 0 0。
输入示例1:
(a+b(c-d))
输出示例1:
1
输入示例2:
(d-e))
输出示例2:
0
代码:
/* 试写一个判别表达式中开,闭括号是否配对出现的算法。比如:'(a+b(c-d))'是配对出现的,
* 而'(d-e))'不是配对出现的。*/
#include <stdio.h>
#include <stdlib.h>
#define ERROR 1
#define OK 0
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
typedef char SElemtype;
typedef struct {
SElemtype* base;
SElemtype* top;
int stacksize;
} SqStack;
// 构造一个空栈 S
extern Status InitStack(SqStack *S);
// 若栈不空,则用 e 返回 S 的栈顶元素,并返回 OK;否则返回 ERROR
extern Status GetTop(SqStack S, SElemtype *e);
// 插入元素 e 为新的栈顶元素
extern Status Push(SqStack *S, SElemtype *e);
// 若栈不空,则删除栈顶元素,用 e 返回其值,并返回 OK;否则返回 ERROR
extern Status Pop(SqStack *S, SElemtype *e);
// 若栈 S 为空栈,则返回 TRUE,否则返回 FAUSE
extern Status StackEmpty(SqStack *S);
int main()
{
SqStack S;
InitStack(&S);
char c = '0', e;
while ((c = getchar()) != EOF && c != '\n') {
switch (c)
{
case '(':
Push(&S, '(');
break;
case '[':
Push(&S, '[');
break;
case '{':
Push(&S, '{');
break;
case ')':
if (StackEmpty(&S)) {
printf("0\n");
return 0;
}
GetTop(S, &e);
if (e == '(') {
Pop(&S, &e);
break;
}
else {
printf("0\n");
return 0;
}
case ']':
if (StackEmpty(&S)) {
printf("0\n");
return 0;
}
GetTop(S, &e);
if (e == '[') {
Pop(&S, &e);
break;
}
else {
printf("0\n");
return 0;
}
case '}':
if (StackEmpty(&S)) {
printf("0\n");
return 0;
}
GetTop(S, &e);
if (e == '{') {
Pop(&S, &e);
break;
}
else {
printf("0\n");
return 0;
}
default:
break;
}
}
if (StackEmpty(&S)) {
printf("1\n");
}
else {
printf("0\n");
}
return 0;
}
Status InitStack(SqStack* S)
{
S->base = (SElemtype*)malloc(STACK_INIT_SIZE * sizeof(SElemtype));
if (!S->base) exit(OVERFLOW);
S->top = S->base;
S->stacksize = STACK_INIT_SIZE;
return OK;
}// InitStack
Status GetTop(SqStack S, SElemtype *e)
{
if (S.top == S.base) return ERROR;
*e = *(S.top - 1);
return OK;
}// GetTop
Status Push(SqStack* S, SElemtype *e)
{
if (S->top - S->base >= S->stacksize) {
S->base = (SElemtype*)realloc(S->base,
(S->stacksize + STACKINCREMENT) * sizeof(SElemtype));
if (!S->base) exit(OVERFLOW);
S->top = S->base + S->stacksize;
S->stacksize += STACKINCREMENT;
}
*S->top++ = e;
return OK;
}// Push
Status Pop(SqStack* S, SElemtype *e)
{
if (S->top == S->base) return ERROR;
*e = *--S->top;
return OK;
}// Pop
Status StackEmpty(SqStack* S)
{
if (S->top == S->base) return ERROR;
else return OK;
}// StackEmpty
三、3.20-图像区域颜色置换
假设以二维数组 g ( 1.. m , 1.. n ) g(1..m, 1..n) g(1..m,1..n) 表示一个图像区域, g [ i , j ] g[i, j] g[i,j] 表示该区域中点 ( i , j ) (i, j) (i,j) 所具颜色,其值为从 0 0 0 到 k k k 的整数。
编写算法置换点 ( i , j ) (i, j) (i,j) 所在区域的颜色。约定和 ( i , j ) (i, j) (i,j) 同色的上、下、左、右的邻接点为同色区域的点。
输入: 输入分为两部分,第一部分为第一行输入二维数组的行数、列数、染色起点位置的行坐标与列坐标以及染色开始方向。
中间以空格隔开,其中,行坐标与列坐标均以 0 0 0 开始,染色方向为上下左右,为枚举结构 ( 0 , 1 , 2 , 3 ) (0,1,2,3) (0,1,2,3)。
第二部分为二维数组形状输入,开始图像着色,用数字 2 2 2 来替换二维数组中 1 1 1 的位置。
输出: 着色完成的图像(即二维数组)
输入示例:
10 17 9 8 3
0 0 1 1 1 0 0 0 0 0 0 0 1 1 1 0 0
0 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 0
0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0
0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
输出示例:
00222000000022200
02222220002222220
22222222222222222
22222222222222222
02222222222222220
00022222222222000
00002222222220000
00000022222000000
00000002220000000
00000000200000000
代码:
题目是这样的,但是OJ上判定方式仅仅是输出,我就用一个动态二维数组草草了事了,毕竟,懒啊。
/* 假设以二维数组g(1..m, 1..n)表示一个图像区域, g[i, j]表示该区域中点(i, j)
* 所具颜色,其值为从0到k的整数。编写算法置换点(i_, j_)所在区域的颜色。约定和
* (i_, j_)同色的上、下、左、右的邻接点为同色区域的点。*/
#include <stdio.h>
#include <stdlib.h>
typedef int AElemtype;
int main()
{
AElemtype** p;
int i = 0, j = 0, c = 0;
scanf("%d %d", &i, &j);
while ((c = getchar()) != '\n');
p = (AElemtype**)malloc((j+1) * sizeof(AElemtype *));
for (int k = 0; k < j; k++) {
p[k] = (AElemtype*)malloc((i+1) * sizeof(AElemtype));
}
for (int n = 0; n < i; n++)
for (int m = 0; m < j; m++)
scanf("%d", &p[m][n]);
for (int n = 0; n < i; n++) {
for (int m = 0; m < j; m++) {
if (p[m][n] == 1)
printf("2");
else
printf("0");
}
printf("\n");
}
return 0;
}
四、3.21-逆波兰式
假设表达式由单字母变量和双目四则运算符构成。试写一个算法,将一个通常书写形式且书写正确的表达式转换为逆波兰式。
输入: 常规运算表达式,比如 a + b a+b a+b。
输出: 逆波兰式,比如 a b + ab+ ab+。
输入示例1:
A+B*(C-D)-E*F
输出示例1:
ABCD-*+EF*-
输入示例2:
b*c/d
输出示例2:
bc*d/
代码:
/* 假设表达式由单字母变量和双目四则运算符构成。试写一个算法,将一个通常书写形式且
* 书写正确的表达式转换为逆波兰式。*/
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define ERROR 1
#define OK 0
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
typedef char SElemtype;
typedef struct {
SElemtype* base;
SElemtype* top;
int stacksize;
} SqStack;
// 构造一个空栈 S
extern Status InitStack(SqStack* S);
// 若栈 S 为空栈,则返回 TRUE,否则返回 FAUSE
extern Status StackEmpty(SqStack* S);
// 若栈不空,则用 e 返回 S 的栈顶元素,并返回 OK;否则返回 ERROR
extern Status GetTop(SqStack S, SElemtype* e);
// 插入元素 e 为新的栈顶元素
extern Status Push(SqStack* S, SElemtype* e);
// 若栈不空,则删除栈顶元素,用 e 返回其值,并返回 OK;否则返回 ERROR
extern Status Pop(SqStack* S, SElemtype* e);
// 打印栈,若栈为空则返回 ERROR
extern Status PrintStack(SqStack S);
int main()
{
SqStack S, tmp;
InitStack(&S);
InitStack(&tmp);
char e = '0', c = '0';
while ((e = getchar()) != '\n' && e != EOF) {
if ((e >= 'A' && e <= 'Z') || e >= 'a' && e <= 'z') {
Push(&S, &e);
}
else if (StackEmpty(&tmp))
Push(&tmp, &e);
else {
switch (e)
{
case '+':
GetTop(tmp, &c);
while ((c == '*' || c == '/' || c == '+') && !StackEmpty(&tmp)) {
Pop(&tmp, &c);
Push(&S, &c);
GetTop(tmp, &c);
}
Push(&tmp, &e);
break;
case '-':
GetTop(tmp, &c);
while ((c == '*' || c == '/' || c == '+') && !StackEmpty(&tmp)) {
Pop(&tmp, &c);
Push(&S, &c);
GetTop(tmp, &c);
}
Push(&tmp, &e);
break;
case '*':
GetTop(tmp, &c);
while (c == '/' && !StackEmpty(&tmp)) {
Pop(&tmp, &c);
Push(&S, &c);
GetTop(tmp, &c);
}
Push(&tmp, &e);
break;
case '/':
GetTop(tmp, &c);
while (c == '*' && !StackEmpty(&tmp)) {
Pop(&tmp, &c);
Push(&S, &c);
GetTop(tmp, &c);
}
Push(&tmp, &e);
break;
case '(':
Push(&tmp, &e);
break;
case ')':
GetTop(tmp, &c);
while (c != '(') {
Pop(&tmp, &c);
Push(&S, &c);
GetTop(tmp, &c);
}
Pop(&tmp, &c);
break;
default:
break;
}
}
}
GetTop(tmp, &c);
while (!StackEmpty(&tmp)) {
Pop(&tmp, &c);
Push(&S, &c);
GetTop(tmp, &c);
}
PrintStack(S);
return 0;
}
Status InitStack(SqStack* S)
{
S->base = (SElemtype*)malloc(STACK_INIT_SIZE * sizeof(SElemtype));
if (!S->base) exit(OVERFLOW);
S->top = S->base;
S->stacksize = STACK_INIT_SIZE;
return OK;
}// InitStack
Status GetTop(SqStack S, SElemtype* e)
{
if (S.top == S.base) return ERROR;
*e = *(S.top - 1);
return OK;
}// GetTop
Status Push(SqStack* S, SElemtype* e)
{
if (S->top - S->base >= S->stacksize) {
S->base = (SElemtype*)realloc(S->base,
(S->stacksize + STACKINCREMENT) * sizeof(SElemtype));
if (!S->base) exit(OVERFLOW);
S->top = S->base + S->stacksize;
S->stacksize += STACKINCREMENT;
}
*S->top++ = *e;
return OK;
}// Push
Status Pop(SqStack* S, SElemtype* e)
{
if (S->top == S->base) return ERROR;
*e = *--S->top;
return OK;
}// Pop
Status StackEmpty(SqStack* S)
{
if (S->top == S->base) return ERROR;
else return OK;
}// StackEmpty
Status PrintStack(SqStack S)
{
if (StackEmpty(&S)) return ERROR;
while (!StackEmpty(&S))
printf("%c", *(S.base++));
printf("\n");
return OK;
}// PrintStack
五、3.24-递归函数计算
试编写如下定义的递归函数的递归算法,并根据算法画出求 g ( 5 , 2 ) g(5,2) g(5,2) 时栈的变化过程。
g ( m , n ) = 0 ( m = 0 , n > = 0 ) g ( m , n ) = g ( m − 1 , 2 n ) + n ( m > 0 , n > = 0 ) g(m, n) = 0 (m = 0, n>=0) g(m, n) = g(m-1, 2n) + n (m>0, n>=0) g(m,n)=0(m=0,n>=0)g(m,n)=g(m−1,2n)+n(m>0,n>=0)
输入: 输入 m m m 与 n n n 的数值,中间以逗号隔开。
输出: 递归计算后, g ( m , n ) g(m, n) g(m,n) 的值。
输入样例:
5,2
输出样例:
62
代码:
/* 试编写如下定义的递归函数的递归算法,并根据算法画出求g(5, 2)时栈的变化过程。
* g(m, n) = 0 (m = 0, n>=0) g(m, n) = g(m-1, 2n) + n (m>0, n>=0) */
#include <stdio.h>
extern int g(int m, int n);
int main()
{
int m = 0, n = 0;
scanf("%d,%d", &m, &n);
printf("%d\n", g(m, n));
return 0;
}
int g(int m, int n)
{
if (m > 0) return (g(m-1, 2*n) + n);
else return 0;
}
六、3.25-递归函数非递归法计算
试写出求递归函数
F
(
n
)
F(n)
F(n) 的递归算法,并消除递归:
F
(
n
)
=
n
+
1
(
n
=
0
)
,
F
(
n
)
=
n
∗
F
(
n
/
2
)
(
n
>
0
)
F(n ) = n + 1 (n = 0),F(n) = n * F(n / 2) (n > 0)
F(n)=n+1(n=0),F(n)=n∗F(n/2)(n>0)
输入: 输入非负整数 n n n。
输出: 计算出的 F ( n ) F(n) F(n) 函数的值。
输入样例:
10
输出样例:
100
代码:
/* 试写出求递归函数F(n)的递归算法,并消除递归:
* F(n) = n + 1 (n = 0)
* F(n) = n * F(n / 2) (n > 0) */
#include <stdio.h>
extern int F(int n);
int main()
{
int n = 0;
scanf("%d", &n);
printf("%d\n", F(n));
return 0;
}
int F(int n)
{
if (n > 0) return (n * F(n/2));
else return (n + 1);
}
七、3.28-队列实现
假设以带头结点的循环链表表示队列,并且只设一个指针指向队尾元素结点(注意不设头指针),试编写相应的队列初始化、入队列和出队列的算法。
输入: 输入分为两行,第一行表示队列个数,第二行表示入队列的元素序列,中间以逗号隔开。
输出: 队列出队列的元素序列,中间以逗号隔开。
输入示例:
5
1,2,3,4,5
输出示例:
1,2,3,4,5
代码:
/* 假设以带头结点的循环链表表示队列,并且只设一个指针指向队尾元素结点(注意
* 不设头指针),试编写相应的队列初始化、入队列和出队列的算法 */
#include <stdio.h>
#include <stdlib.h>
#define OK 0
#define ERROR 1
#define OVERFLOW -2
#define MAXQSIZE 100
typedef int QElemtype;
typedef int Status;
typedef struct {
QElemtype *base;
int rear;
} SqQueue;
// 插入队列并初始化
extern Status InitQueue(SqQueue *Q);
// 插入元素 e 为 Q 新的队尾元素
extern Status EnQueue(SqQueue *Q, QElemtype e);
// 若队列不空,则删除 Q 的队头元素,用 e 返回其值,并返回 OK,否则返回 ERROR
extern Status DeQueue(SqQueue *Q, QElemtype *e);
int main()
{
int len = 0;
QElemtype e = 0;
scanf("%d", &len); getchar();
SqQueue Q;
InitQueue(&Q);
for (int i = 0; i < len; i++) {
scanf("%d", &e); getchar();
EnQueue(&Q, e);
}
DeQueue(&Q, &e);
int s[MAXQSIZE];
for (int i = 0; i < len; i++) {
DeQueue(&Q, &e);
s[len - i] = e;
}
for (int i = 0; i < len; i++) {
printf("%d", s[i + 1]);
if (i < len - 1) printf(",");
else printf("\n");
}
return 0;
}
Status InitQueue(SqQueue *Q)
{
Q->base = (QElemtype *)malloc(MAXQSIZE * sizeof(QElemtype));
if (!Q->base) exit(OVERFLOW);
Q->rear = 0;
return OK;
}// InitQueue
Status EnQueue(SqQueue *Q, QElemtype e)
{
Q->base[Q->rear] = e;
Q->rear = (Q->rear + 1) % MAXQSIZE;
return OK;
}
Status DeQueue(SqQueue *Q, QElemtype *e)
{
*e = Q->base[Q->rear];
Q->rear = (Q->rear - 1) % MAXQSIZE;
return OK;
}
八、3.31-回文字符串
假设称正读和反读都相同的字符序列为回文,例如, a b b a abba abba 和 a b c b a abcba abcba 是回文,而 a b c d e abcde abcde 和 a b a b a b ababab ababab 则不是回文。
试写一个算法判别读入的一个以 @ @ @ 为结束符的字符序列是否为回文。
输入: 输入字符串,以@结尾。
输出: 是回文则输出 1 1 1,否则输出 0 0 0。
输入样例1:
abba@
输出样例1:
1
输入样例2:
abcde@
输出样例2:
0
代码:
/* 假设称正读和反读都相同的字符序列为"回文",例如,'abba'和'abcba'是回文,
* 而'abcde'和'ababab'则不是回文。
* 试写一个算法判别读入的一个以'@'为结束符的字符序列是否为回文。*/
#include <stdio.h>
#include <stdlib.h>
#define OK 0
#define ERROR 1
#define OVERFLOW -2
#define MAXQSIZE 100
typedef char QElemtype;
typedef int Status;
typedef struct {
QElemtype* base;
int front;
int rear;
} SqQueue;
// 插入队列并初始化
extern Status InitQueue(SqQueue* Q);
// 返回 Q 的元素个数,即队列的长度
extern Status QueueLength(SqQueue Q);
// 插入元素 e 为 Q 新的队尾元素
extern Status EnQueue(SqQueue* Q, QElemtype e);
// 若队列不空,则删除 Q 的队头元素,用 e 返回其值,并返回 OK,否则返回 ERROR
extern Status DeQueue(SqQueue* Q, QElemtype* e);
// 若队列不空,则删除 Q 的队尾元素,用 e 返回其值,并返回 OK,否则返回 ERROR
extern Status UnEnQueue(SqQueue* Q, QElemtype* e);
int main()
{
SqQueue Q;
InitQueue(&Q);
char c = '0';
while ((c = getchar()) != '@') {
EnQueue(&Q, c);
}
char tmp1, tmp2;
do {
DeQueue(&Q, &tmp1);
UnEnQueue(&Q, &tmp2);
} while (tmp1 == tmp2 && QueueLength(Q) > 1);
if (QueueLength(Q) <= 1) {
printf("1\n");
return 0;
}
else {
printf("0\n");
return 0;
}
}
Status InitQueue(SqQueue* Q)
{
Q->base = (QElemtype*)malloc(MAXQSIZE * sizeof(QElemtype));
if (!Q->base) exit(OVERFLOW);
Q->front = Q->rear = 0;
return OK;
}// InitQueue
Status QueueLength(SqQueue Q)
{
return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
}// QueueLength
Status EnQueue(SqQueue* Q, QElemtype e)
{
if ((Q->rear + 1) % MAXQSIZE == Q->front) return ERROR;
Q->base[Q->rear] = e;
Q->rear = (Q->rear + 1) % MAXQSIZE;
return OK;
}// EnQueue
Status DeQueue(SqQueue* Q, QElemtype* e)
{
if (Q->front == Q->rear) return ERROR;
*e = Q->base[Q->front];
Q->front = (Q->front + 1) % MAXQSIZE;
return OK;
}// DeQueue
Status UnEnQueue(SqQueue* Q, QElemtype* e)
{
if (Q->front == Q->rear) return ERROR;
*e = Q->base[Q->rear - 1];
Q->rear = (Q->rear - 1) % MAXQSIZE;
return OK;
}// UnEnQueue
总结
本章学习栈与队列,在调试时不能直观看到数据,必须依靠自己大脑推理,但是题目本身比较简单,花费时间不多。