题目要求:
对任意输入的十进制正整数,写一程序将其转换成二进制表示。要求首先实现Stack ADT, 然后用栈的基本操作完成该程序。请分别用顺序存储结构表示和链式存储结构表示,并相应完成数据转换。
输入:
输出:
代码实现:
①用顺序存储的方式解决问题:
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100 //栈的最大容量
#define OVERFLOW -2 //溢出标识
#define ERROR -1 //操作失败标识
#define OK 1 //操作成功标识
/************************************************************************/
//定义栈的结构体:
typedef struct {
int *base;
int *top;
int stacksize;
} SqStack;
//函数声明:
int GetBinary(int data);//返回一个十进制整数的二进制
int InitStack(SqStack &S);//初始化一个栈
bool StackEmpty(SqStack S);//判断一个栈是否为空
int StackLength(SqStack S);//求栈的长度
int ClearStack(SqStack S);//清除顺序栈
int DestoryStack(SqStack S);//销毁顺序栈
int Pop(SqStack &S, int &e); //出栈
int Push(SqStack &S, int &e);//入栈
int Gettop(SqStack &S, int e); //获取栈顶元素
/************************************************************************/
//主程序:
int main() {
/*
*num:暂时存储从输入文件读取的数字
*size:记录读入数据的个数
*data:用于存放读入数据的数组
*/
int num;
int size = 0;
int data[100];
//以只读方式打开文件input.txt通道
FILE *fp = NULL;
fp = fopen("input.txt", "r");
//遍历文件内容,读取数据存入data[]
fscanf(fp, "%d", &data[size]);
while (data[size] != -1) {
size++;
fscanf(fp, "%d", &data[size]);
}
fclose(fp);//关闭通道
//打开文件output.txt通道
fp = fopen("output.txt", "a");
//遍历数组data,并调用GetBinary函数获取二进制并输出到文件output.txt中
for (int i = 0; i < size; ++i)
fprintf(fp, "%d-->%d\n", data[i], GetBinary(data[i]));
fclose(fp);//关闭通道
return 0;
}
/*****************************************************************/
//自定义函数具体实现:
//GetBinary:从一个十进制整数的输入返回它的二进制
int GetBinary(int data) {
/*
*sum:最后返回的整个二进制数
*bin:从栈binary取出的单个二进制数
*quotient:二进制除法步骤中的单个商
*remainder:二进制除法每一步的余数
*binary:以栈为结构的二进制存储器
*/
int sum = 0;
int bin = 0;
int quotient;
int remainder;
SqStack binary;
InitStack(binary);//初始化一个存储二进制的栈binary
//二进制计算:轮番整除和取余,其中每一步将商存入栈binary
remainder = data;
for (int i = 0; remainder != 0; ++i) {
quotient = remainder % 2;
Push(binary, quotient);
remainder = remainder / 2;
}
//while中不断出栈并×10,得到最后的二进制结果sum
while (!StackEmpty(binary)) {
Pop(binary, bin);
sum = sum * 10 + bin;
}
return sum;
};
//初始化一个栈
int InitStack(SqStack &S) {
S.base = (int*)malloc(MAXSIZE * sizeof(int));
if (!S.base)return OVERFLOW;//判断S是否溢出
S.top = S.base;
S.stacksize = MAXSIZE;
return OK;
}
//判断一个栈是否为空
bool StackEmpty(SqStack S) {
if (S.base == S.top)return true;
else return false;
}
//求栈的长度
int StackLength(SqStack S) {
return S.top - S.base;
}
//清除顺序栈
int ClearStack(SqStack S) {
if (S.base)S.top = S.base;
return OK;
}
//销毁顺序栈 ?可能错误
int DestoryStack(SqStack S) {
if (S.base) {
S.top = S.base = NULL;
S.stacksize = 0;
free(S.base);
S.base = NULL;
}
}
//出栈
int Pop(SqStack &S, int &e) {
if (S.top == S.base)//栈满判断
return ERROR;
--S.top;
e = *S.top;
return OK;
}
//入栈
int Push(SqStack &S, int &e) {
if (S.top - S.base == MAXSIZE) //栈满判断
return ERROR;
*S.top++ = e; //*S.top++=等同于(*S.top=e;S.top++);
return OK;
}
//获取栈顶元素
int Gettop(SqStack &S, int e) {
if (S.top == S.base)
return ERROR;
e = *(S.top--);
return OK;
}
/*****************************************************************/
②用链式储存解决问题:
#include <stdio.h>
#include <stdlib.h>
#define OVERFLOW -2 //溢出标识
#define ERROR -1 //操作失败标识
#define OK 1 //操作成功标识
/************************************************************************/
//定义栈的节点:
typedef struct StackNode {
int data;//存放数据
struct StackNode *next;//存放下个节点的地址
} StackNode, *LinkStack;
//函数声明:
int GetBinary(int data);//返回一个十进制整数的二进制
void InitStack(LinkStack &S);//初始化一个栈
bool StackEmpty(LinkStack S);//判断一个栈是否为空
int Push(LinkStack &S , int e); //入栈
int Pop (LinkStack &S, int &e); //出栈
int GetTop(LinkStack S);//获取栈顶元素
int DestoryStack(LinkStack &S);//销毁顺序栈
int TraverseStack(LinkStack S);//遍历输出链表
int StackLength(LinkStack S);//求栈的长度
/************************************************************************/
//主程序:
int main() {
/*
*num:暂时存储从输入文件读取的数字
*size:记录读入数据的个数
*data:用于存放读入数据的数组
*/
int num;
int size = 0;
int data[100];
//以只读方式打开文件input.txt通道
FILE *fp = NULL;
fp = fopen("input.txt", "r");
//遍历文件内容,读取数据存入data[]
fscanf(fp, "%d", &data[size]);
while (data[size] != -1) {
size++;
fscanf(fp, "%d", &data[size]);
}
fclose(fp);//关闭通道
//打开文件output.txt通道
fp = fopen("output.txt", "a");
//遍历数组data,并调用GetBinary函数获取二进制并输出到文件output.txt中
for (int i = 0; i < size; ++i)
fprintf(fp, "%d-->%d\n", data[i], GetBinary(data[i]));
fclose(fp);//关闭通道
return 0;
}
/*****************************************************************/
//自定义函数具体实现:
//GetBinary:从一个十进制整数的输入返回它的二进制
int GetBinary(int data) {
/*
*sum:最后返回的整个二进制数
*bin:从栈binary取出的单个二进制数
*quotient:二进制除法步骤中的单个商
*remainder:二进制除法每一步的余数
*binary:以栈为结构的二进制存储器
*/
int sum = 0;
int bin = 0;
int quotient;
int remainder;
LinkStack binary;
InitStack(binary);//初始化一个存储二进制的栈binary
//二进制计算:轮番整除和取余,其中每一步将商存入栈binary
remainder = data;
for (int i = 0; remainder != 0; ++i) {
quotient = remainder % 2;
Push(binary, quotient);
remainder = remainder / 2;
}
//while中不断出栈并×10,得到最后的二进制结果sum
while (!StackEmpty(binary)) {
Pop(binary, bin);
sum = sum * 10 + bin;
}
return sum;
};
//初始化一个栈
void InitStack(LinkStack &S ) {
S = NULL;
}
//判断一个栈是否为空
bool StackEmpty(LinkStack S) {
if (S == NULL)return true;
else return false;
}
//销毁顺序栈
int DestoryStack(LinkStack &S) {
if (!S)return ERROR;
LinkStack p = S;
while (S) {
S = S->next;
free(p);
p = S;
}
}
//出栈
int Pop(LinkStack &S, int &e) {
LinkStack p = S;
if (S == NULL)return ERROR;
e = S->data;
S = S->next;
free(p);
return OK;
}
//入栈
int Push(LinkStack &S , int e) {
LinkStack p = (StackNode*)malloc(sizeof(StackNode));
if (!p)return OVERFLOW;
p->data = e;
p->next = S;
S = p;
return OK;
}
//获取栈顶元素
int GetTop(LinkStack S) {
if (!S)return ERROR;
return S->data;
}
//遍历链栈
int TraverseStack(LinkStack S) {
LinkStack p = S;
if (!S)return ERROR;
while (p) {
printf("%d->", p->data );
p = p->next;
}
printf("NULL\n");
return OK;
};
//返回链表长度
int StackLength(LinkStack S) {
LinkStack p = S;
int length = 0;
if (!S)return ERROR;
while (p) {
length++;
p = p->next;
}
return length;
}
/*****************************************************************/
解决思路:
①首先分析问题,解决这个问题我们要分成四步:读取数据、存储数据、编写处理数据的函数、处理数据。
②解决如何读取输出,很明显这会用到文件的I/O知识。首先写好读取文件的代码块。
③解决完如何读取,接下来就是如何存储,这里题目要求我们用两种存储结构,我们就分别两份代码解决顺序结构和链式结构,为两种结构分别定义结构体并将数据入栈。
④定义完两种结构的栈后,我们应该着手编写栈的各类函数以便接下来数据的处理,最经典的就是“增删查改”。
⑤万事俱备后就可以对数据进行处理了。由题可知我们需要对每个数据进行二进制的转换。十进制转换成二进制就需要我们为其编写函数,按照二进制的算法,对数据进行2的整除,商的逆序就为答案。这里才是我们用到栈的地方。
涉及知识点:
①文件的I/O
②对栈的理解以及对栈操作的实践
③结构体的创建和运用以及作为函数参数传入。
④十进制转二进制算法
总结:
有了上次实验的基础这次实验完成起来就相对简单。因为文件读入输出和结构体的创建在上个实验已经温习过一遍。完成这次实验的主要难点仅在于对栈的理解和对栈操作的编写。我们应当理解在将十进制转化为二进制要用到栈,是因为在二进制算法中,商的取得是逆序输出的,正好满足栈先入先出的特点。这才是我们要选择用栈的原因,而非盲目用栈。
也许因为问题的简单,我也更能理解了如何解决一个计算机问题,以下内容纯属个人杜撰:解决计算机问题大体脱不开对数据的读入,存储,处理,输出。而这里我们用自定义了结构体,没有现成的处理工具,所以还要自己制作处理工具。如果这样分析,面对一个新问题就不会手足无措了。
此外,在编写函数时也一定要判断各种非法操作,例如:入栈要先判断栈是否满了,出栈要判断栈是否是空的,申请空间要判断是否申请成功(有内存不足,溢出的可能性)以及有malloc的地方一定要有free,以免内存泄露。