栈的运用:以简单的二进制转换为例

题目要求:

对任意输入的十进制正整数,写一程序将其转换成二进制表示。要求首先实现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,以免内存泄露。


  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值