数据结构(C语言)代码实现(八)——顺序栈实现数值转换行编辑程序括号分配汉诺塔

news2024/11/21 2:30:01

目录

 参考资料

顺序栈的实现

头文件SqStack.h(顺序栈函数声明)

源文件SqStack.cpp(顺序栈函数实现)

顺序栈的三个应用

数值转换

行编辑程序

顺序栈的实现测试

栈与递归的实现(以汉诺塔为例)


 参考资料

1.本文文章结构参考这篇博客,部分代码也引用自这篇博客。

2021-9-22【数据结构/严蔚敏】【顺序栈&链式栈&迷宫求解&表达式求值】【代码实现算法3.1-3.5】_数据结构表达式求值代码严老师-CSDN博客

2.又搜到一个更靠谱的,这个的引用也用指针替代了。

栈和队列-数据结构与算法(C语言版)_调用pop(&s,&e)函数,让队头数据出队,赋值给参数e,printf输出e-CSDN博客3. 数据结构课本严蔚敏版。

顺序栈的实现

头文件SqStack.h(顺序栈函数声明)

#pragma once
#include <cstdio>
#include <cstdlib>
#include <cstring>

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;//Status是函数的类型,其值是函数结果状态代码
typedef int SElemType;

//-----栈的顺序存储表示-----
#define STACK_INIT_SIZE 100  //存储空间初始分配量
#define STACKINCREMENT 10    //存储空间分配增量
typedef struct SqStack {
	SElemType* base;//在栈构造之前和销毁之后,base的值为NULL
	SElemType* top; //栈顶指针
	int stacksize;  //当前已分配的存储空间,以元素为单位
}SqStack;
//-----基本操作的函数原型说明-----
Status InitStack(SqStack& S);
//构造一个空栈S
Status DestroyStack(SqStack& S);
//销毁栈S,S不再存在
Status ClearStack(SqStack& S);
//把S置为空栈
Status StackEmpty(SqStack S);
//若栈S为空栈,则返回TRUE,否则返回FALSE
int StackLength(SqStack S);
//返回S的元素个数,即栈的长度
Status GetTop(SqStack S, SElemType& e);
//若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR
Status Push(SqStack& S, SElemType e);
//插入元素e为新的栈顶元素
Status Pop(SqStack& S, SElemType& e);
//若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR
Status StackTraverse(SqStack S, void(*visit)(SElemType));
//从栈顶到栈底依次对栈中每个元素调用函数visit()。一旦visit()失败,则操作失败

源文件SqStack.cpp(顺序栈函数实现)

源文件SqStack.cpp是头文件SqStack.h的实现。

#include "SqStack.h"

//-----基本操作的函数算法描述(部分)-----
Status InitStack(SqStack& S) {
	//构造一个空栈S
	S.base = (SElemType*)malloc(STACK_INIT_SIZE * sizeof(SElemType));
	if (!S.base)exit(OVERFLOW);//存储分配失败,警告C6011
	S.top = S.base;
	S.stacksize = STACK_INIT_SIZE;
	return OK;
}

Status DestroyStack(SqStack& S) {
	free(S.base);
	S.top = S.base = NULL;
	S.stacksize = 0;
	return OK;
}

Status ClearStack(SqStack& S) {
	if (!S.base)return ERROR;
	S.top = S.base;
	return OK;
}

Status StackEmpty(SqStack S) {
	if (S.base == S.top)
		return OK;
	return ERROR;
}

int StackLength(SqStack s) {
    if (!s.base)
        return ERROR;
    return (int)(s.top - s.base);
}

Status GetTop(SqStack s, SElemType& e) {
    //若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR
    if (s.base == s.top)
        return ERROR;
    e = *(s.top - 1);
    return OK;
}

Status Push(SqStack& s, SElemType e) {
    //插入元素e为新的栈顶元素
    if (!s.base)return ERROR;
    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;//*s.top=e; s.top++;
    return OK;
}

Status Pop(SqStack& s, SElemType& e) {
    //若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR
    if (!s.base || s.top == s.base) return ERROR;
    e = *--s.top;//--s.top; e=*s.top;
    return OK;
}

Status StackTraverse(SqStack s, void (*visit)(SElemType)) {
	SElemType* p = s.base;
	if (!s.base)return ERROR;
	while (p < s.top)
		visit(*p++);
	printf("\n");
	return OK;
}

顺序栈的四个应用

数值转换

源文件conversion.cpp

#include "SqStack.h"

void conversion() {
	//对于输入的任意一个非负十进制整数,打印输出与其等值的八进制数
	SqStack S;
	InitStack(S);//构造空栈
	SElemType N,e;
	scanf_s("%d", &N);
	if (N == 0)//当N为0时下面的while循环不输出
	{
		printf("%d", N);
		return;
	}
	while (N) {
		Push(S, N % 8);
		N = N / 8;
	}
	while (!StackEmpty(S)) {
		Pop(S, e);
		printf("%d", e);
	}
}
int main()
{
	conversion();
	return 0;
}//算法3.1

测试结果(课本样例)

括号匹配

栈和队列-数据结构与算法(C语言版)_调用pop(&s,&e)函数,让队头数据出队,赋值给参数e,printf输出e-CSDN博客源文件 MatchBrackets.cpp

完整代码

#include "SqStack.h"

/*
 * 括号匹配
 * 注意将ElemType 修为 char
 */
Status MatchBrackets(SqStack& S, char* brackets) {
    SElemType ch;
    int len = strlen(brackets);
    for (int i = 0; i < len; i++) {
        if (brackets[i] == '{' || brackets[i] == '[' || brackets[i] == '(') {
            Push(S, brackets[i]);
        }
        if (brackets[i] == '}' || brackets[i] == ']' || brackets[i] == ')') {

            if (StackEmpty(S)) {
                printf("右括号多于左括号\n");
                return ERROR;
            }
            else {
                GetTop(S, ch);
                if (ch == '{' && brackets[i] == '}' || ch == '[' && brackets[i] == ']' || ch == '(' && brackets[i] == ')') {
                    Pop(S, ch);
                }
            }

        }
    }
    if (!StackEmpty(S))
        printf("左括号多于右括号\n");
    else
        printf("括号匹配成功!");
    return OK;
}

int main()
{
    SqStack S;
    char brackets[81] = { 0 };
    //用char* brackets;会报错
    InitStack(S);
    scanf_s("%s", brackets,sizeof(brackets));
    //不知道为什么,不加sizeof(),括号匹配函数len一直为0,
    //导致输出总是“括号匹配成功”。
    MatchBrackets(S, brackets);
    return 0;
}

 测试结果

行编辑程序

源文件LineEdit.cpp

本来想两个主函数能不能在同一个工程下运行,结果不可以。接着我把数值转换这个主函数移除,发现可以运行行编辑程序这个代码了。

右键conversion.cpp,点击移除。

接着打开LineEdit.cpp。右键点击源文件,在添加中找到现有项,点击现有项寻找即可(前提是你写了)

下面是完整代码

#include "SqStack.h"

void visit(SElemType e) {
	printf("%d ", e);
}

void LineEdit() {
	//利用字符栈S,从终端接收一行并传送至调用过程的数据区
	SqStack S;
	InitStack(S);//构造空栈S
	SElemType c;
	char ch = getchar();//从终端接收第一个字符
	while (ch != EOF) {//EOF为全文结束符,Ctrl+z+回车键对应EOF
		while (ch != EOF && ch != '\n') {//一行内
			switch (ch) {
			case'#':Pop(S, c);
				break;//仅当栈非空时退栈
			case'@':ClearStack(S);
				break;//重置S为空栈
			default:Push(S, ch);
				break;//有效字符进栈,未考虑栈满情形
			}
			ch = getchar();//从终端接收下一个字符
		}
		//将从栈底到栈顶的栈内字符传送至调用过程中的数据区
		StackTraverse(S, visit);//课本没有,但我看不到结果,便加上了这个函数
		ClearStack(S);//重置S为空栈
		if (ch != EOF)ch = getchar();
	}
	DestroyStack(S);
}
int main()
{
	LineEdit();
	return 0;
}

测试样例选自课本P49页右下角两行字符,测试结果如下:

此时正常返回。从元素个数看,结果正确,但不直观,所以将SElemType改为char类型。

为了实现行编辑程序,特别修改两处代码(仅在行编辑程序中使用)。

typedef char SElemType;//修改SqStack.h第13行

void visit(SElemType e) {
	printf("%c", e);
}//修改LineEdit.cpp第4行

最终结果 

顺序栈的实现测试

源文件test.cpp ,这个是我复制粘贴的我参考的博客。

#include "SqStack.h"
#include <iostream>
using namespace std;

void visit(SElemType e) {
	printf("%d ", e);
}
//简单测试主函数
int main() {
	SqStack s;
	cout << "InitStack" << endl;
	InitStack(s);
	cout << "StackEmpty" << endl;
	StackEmpty(s) ? cout << "yes\n" : cout << "no\n";
	cout << "Push" << endl;
	for (int i = 1; i <= 6; i++)
		Push(s, i);
	cout << "StackTraverse" << endl;
	StackTraverse(s, visit);
	cout << "StackLength" << endl;
	cout << StackLength(s) << endl;
	cout << "Pop" << endl;
	SElemType e;
	Pop(s, e);
	cout << e << endl;
	StackTraverse(s, visit);
	cout << "GetTop" << endl;
	GetTop(s, e);
	cout << e << endl;

	return 0;
}

测试结果

栈与递归的实现(以汉诺塔为例)

这里课本的代码没有用栈实现递归,但一直在强调递归函数是通过栈实现的,并从栈的角度解释了递归函数的原理。

源文件hanoi.cpp

#include <cstdio>
#include <cstdlib>
#include <cstring>

int C = 0;
void move(char x, int n, char z) {
	printf("%d. Move disk %d from %c to %c\n", ++C, n, x, z);
}
void hanoi(int n, char x, char y, char z)
//将塔座x上按直径由小到大且自上而下编号为1至n的n个圆盘按规则搬到
//塔座z上,y可用作辅助塔座。
//搬动操作move(x, n, z) 可定义为(c是初值为0的全局变量,对搬动计数):
//printf(" %i. Move disk %i from %c to %c\n", ++c, n, x, z);
{
	if (n == 1)
		move(x, 1, z);//将编号为1的圆盘从x移到z
	else {
		hanoi(n - 1, x, z, y);//将x上编号为1至n-1的圆盘移到y,z作辅助塔
		move(x, n, z);        //将编号为n的圆盘从x移到z
		hanoi(n - 1, y, x, z);//将y上编号为1至n-1的圆盘移到z,x做辅助塔
	}
}
int main()
{
	int n=3;
	char A='a', B='b', C='c';
	hanoi(n, A, B, C);
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1442318.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端工程化面试题 | 02.精选前端工程化高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

秒杀相关问题解决

秒杀 超卖问题 如下,我们先来复现问题,抢购秒杀券的代码逻辑也是很简单, 先判断优惠券是否开始了,是的化,判断库存是否充足,如果是的化,扣减库存,最后创建订单 如下是代码 Override Transactional public Result seckillVoucher(Long voucherId) {//1.查询优惠券SeckillVo…

备战蓝桥杯---动态规划之背包问题引入

先看一个背包问题的简单版&#xff1a; 如果我们暴力枚举可能会超时。 但我们想一想&#xff0c;我们其实不关心怎么放&#xff0c;我们关心的是放后剩下的体积。 用可行性描述即可。 于是我们令f[i][j]表示前i个物品能否放满体积为j的背包。 f[i][j]f[i-1][j]||f[i-1][j-v…

数据结构-->线性表-->单链表

链表的定义 链表&#xff1a;链表是一种物理存储结构上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 与顺序表不同的是&#xff0c;链表里的每节都是独立申请下来的空间&#xff0c;我们称之为“节点、结点”。 节点的组成主要由…

Electron+Vue实现仿网易云音乐实战

前言 这个项目是我跟着官方文档的那个Electron入门教程大致跑了一遍,了解了下Electron开发流程之后的实战项目,所以中间应该是会有很多写法不是很规范,安全性有可能也没考虑到,可实现的各种api也不是很了解,适合初学者。 必须感谢 https://github.com/Binaryify/NeteaseC…

小白水平理解面试经典题目LeetCode 71. Simplify Path【Stack类】

71. 简化路径 小白渣翻译 给定一个字符串 path &#xff0c;它是 Unix 风格文件系统中文件或目录的绝对路径&#xff08;以斜杠 ‘/’ 开头&#xff09;&#xff0c;将其转换为简化的规范路径。 在 Unix 风格的文件系统中&#xff0c;句点 ‘.’ 指的是当前目录&#xff0c;…

每日五道java面试题之java基础篇(二)

第一题. 为什么说 Java 语⾔“编译与解释并存”&#xff1f; ⾼级编程语⾔按照程序的执⾏⽅式分为编译型和解释型两种。 简单来说&#xff0c;编译型语⾔是指编译器针对特定的操作系统将源代码⼀次性翻译成可被该平台执⾏的机器码&#xff1b;解释型语⾔是指解释器对源程序逐…

vue全家桶之状态管理Pinia

一、Pinia和Vuex的对比 1.什么是Pinia呢&#xff1f; Pinia&#xff08;发音为/piːnjʌ/&#xff0c;如英语中的“peenya”&#xff09;是最接近pia&#xff08;西班牙语中的菠萝&#xff09;的词&#xff1b; Pinia开始于大概2019年&#xff0c;最初是作为一个实验为Vue重新…

基于Spark+Springboot的电商用户行为分析系统设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行交流合作✌ 主要内容&#xff1a;SpringBoot、Vue、SSM、HLM…

Jupyter Notebook如何在E盘打开

Jupyter Notebook如何在E盘打开 方法1&#xff1a;方法2&#xff1a; 首先打开Anaconda Powershell Prompt, 可以看到默认是C盘。 可以对应着自己的界面输入&#xff1a; 方法1&#xff1a; (base) PS C:\Users\bella> E: (base) PS E:\> jupyter notebook方法2&#x…

Python爬虫实战:抓取猫眼电影排行榜top100#4

爬虫专栏系列&#xff1a;http://t.csdnimg.cn/Oiun0 抓取猫眼电影排行 本节中&#xff0c;我们利用 requests 库和正则表达式来抓取猫眼电影 TOP100 的相关内容。requests 比 urllib 使用更加方便&#xff0c;而且目前我们还没有系统学习 HTML 解析库&#xff0c;所以这里就…

[WinForm开源]概率计算器 - Genshin Impact(V1.0)

创作目的&#xff1a;为方便旅行者估算自己拥有的纠缠之缘能否达到自己的目的&#xff0c;作者使用C#开发了一款小型软件供旅行者参考使用。 创作说明&#xff1a;此软件所涉及到的一切概率与规则完全按照游戏《原神》(V4.4.0)内公示的概率与规则&#xff08;包括保底机制&…

vscode +git +gitee 文件管理

文章目录 前言一、gitee是什么&#xff1f;2. Gitee与VScode连接大概步骤 二、在vscode中安装git1.安装git2.安装过程3.安装完后记得重启 三、使用1.新建文件夹first2.vscode 使用 四、连接git1.初始化仓库2.设置git 提交用户和邮箱3.登陆gitee账号新建仓库没有的自己注册一个4…

ElasticSearch之search API

写在前面 本文看下查询相关内容&#xff0c;这也是我们在实际工作中接触的最多的&#xff0c;所以有必要好好学习下&#xff01; 1&#xff1a;查询的分类 主要分为如下2类&#xff1a; 1:基于get查询参数的URI search 2&#xff1a;基于post body的request body search&am…

移动端设置position: fixed;固定定位,底部出现一条缝隙,不知原因,欢迎探讨!!!

1、问题 在父盒子中有一个子盒子&#xff0c;父盒子加了固定定位&#xff0c;需要子盒子上下都有要边距&#xff0c;用margin或者padding挤开时&#xff0c;会出现缝隙是子盒子背景颜色的。 测试过了&#xff0c;有些手机型号有&#xff0c;有些没有&#xff0c;微信小程序同移…

高防服务器出租的优势及特点

高防服务器出租是指租用具备高防御能力的服务器&#xff0c;用于应对网络攻击、保护网站和数据安全。那么为什么会选择高防服务器出租&#xff0c;小编为您整理发布高防服务器出租的优势及特点。 高防服务器通常具备以下特点&#xff1a; 1. 高性能硬件配置&#xff1a;高防服务…

在屏蔽任何FRP环境下从零开始搭建安全的FRP内网穿透服务

背景 本人目前在境外某大学读博&#xff0c;校园网屏蔽了所有内网穿透的工具的数据包和IP访问&#xff0c;为了实现在家也能远程访问服务器&#xff0c;就不得不先开个学校VPN&#xff0c;再登陆。我们实验室还需要访问另一个大学的服务器&#xff0c;每次我都要去找另一个大学…

JUC-并发面试题

一、基础 1、为什么要并发编程 充分利用多核CPU的资源2、并发编程存在的问题 上下文切换:PU通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个任务。在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再加载这个任务的状态。任务从保…

配置git环境与项目创建

项目设计 名称&#xff1a;KOB 项目包含的模块 PK模块&#xff1a;匹配界面&#xff08;微服务&#xff09;、实况直播界面&#xff08;WebSocket协议&#xff09; 对局列表模块&#xff1a;对局列表界面、对局录像界面 排行榜模块&#xff1a;Bot排行榜界面 用户中心模块&…

神经网络(Nature Network)

最近接触目标检测较多&#xff0c;再此对最基本的神经网络知识进行补充&#xff0c;本博客适合想入门人工智能、其含有线性代数及高等数学基础的人群观看 1.构成 由输入层、隐藏层、输出层、激活函数、损失函数组成。 输入层&#xff1a;接收原始数据隐藏层&#xff1a;进行…