Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >字符串转树结构

字符串转树结构

作者头像
神奇的程序员
发布于 2022-10-30 06:24:13
发布于 2022-10-30 06:24:13
3.3K00
代码可运行
举报
运行总次数:0
代码可运行

前言

有一个多行字符串,每行开头会用空格来表示它的层级关系,每间隔一层它的空格总数为2,如何将它转为json格式的树型数据?本文就跟大家分享下这个算法,欢迎各位感兴趣的开发者阅读本文。

例如有一个字符串:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const text = `
Language
  JavaScript
    TypeScript
    NodeJS
  HTML
Server
  DataBase
    MongoDB
System
  Linux
  Window
`;

将其转换为有层次结构的json数据后为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
    "name":"root",
    "children":[
        {
            "name":"Language",
            "children":[
                {
                    "name":"JavaScript",
                    "children":[
                        {
                            "name":"TypeScript"
                        },
                        {
                            "name":"NodeJS"
                        }
                    ]
                },
                {
                    "name":"HTML"
                }
            ]
        },
        {
            "name":"Server",
            "children":[
                {
                    "name":"DataBase",
                    "children":[
                        {
                            "name":"MongoDB"
                        }
                    ]
                }
            ]
        },
        {
            "name":"System",
            "children":[
                {
                    "name":"Linux"
                },
                {
                    "name":"Window"
                }
            ]
        }
    ]
}

思路分析

乍一看,要对字符串进行处理,好像没有什么比较好的方法,理不出头绪。当我们遇到这种直接从数据结构出发想不出办法的问题时,这时可能就要换个思路了,能否将它转换为另一种数据结构呢?

审题后发现,我们需要的数据元素在字符串中总是独占一行的,那么我们就要对每一行进行处理,此时最好的方式就是将它切割成数组。

那么,我们就以换行符作为切割点来构造数组,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[
  "","Language","  JavaScript", "    TypeScript","    NodeJS",   "  HTML","Server","  DataBase","    MongoDB","System","  Linux","  Window",""
]

观察数组中的每个元素后,我们发现最顶层的数据开头无空格,每间隔一层,开头就会多两个空格。按照从前往后的顺序依次读取数据,将后一个数据与其之前的数据进行比较,进而确定他们之间的层次关系。

分析到这里,相信很多开发者已经看出了这个比较方式满足了“后入先出”原则,因此,我们可以用栈来解决这个问题,如下所示:

  • 准备2个栈,一个用于存放每层的字符串,另一个用于存放每层的空格数
  • 默认将root入栈,将它的空格数定为-1

image-20220923074054521

接下来,我们将每个元素逐一入栈,分析下它的过程。如下图所示,我们列举了部分元素的入栈比对过程,通过观察后,总结出了如下几条规律。

  • 获取入栈元素的空格总数
  • 获取栈顶(deepStack)元素,判断入栈元素的空格总数是否大于栈顶元素。
    • 满足条件则获取strStack的栈顶元素,将入栈元素元素放入它的子级
    • 否则,将两个栈的元素依次出栈。直至入栈元素的空格总数比deepStack的栈顶元素大,获取strStack的栈顶元素,将入栈元素元素放入它的子级
  • 将入栈元素以及它的空格总数分别放入对应的栈中
  • 直至所有元素都入栈比对完成,此问题得到解决

image-20220925084748469

注意:为了让读者更直观的看出规律,strStack栈中的元素用字符串直接代替了,实际上栈中存储的数据是一个对象,该对象包含了name属性和children属性。当前入栈元素也会构造成一个对象,得出栈顶元素(deepStack)与入栈元素空格总数的比对结果后,会将入栈元素对象放进栈顶元素(strStack)的children中。

实现代码

经过上面的分析,我们已经得出了完整的实现思路,接下来我们来看下代码的实现。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 字符串转树结构
 * @param text
 * @constructor
 */
export function DataConversion(text: string): nodeObj {
  const splitArr = text.split("\n");

  const json = { name: "root" };
  const strStack = new Stack();
  const deepStack = new Stack();
  strStack.push(json);
  deepStack.push(-1);

  for (let i = 0; i < splitArr.length; i++) {
    let str = splitArr[i];
    if (!str) continue;
    // 获取空格总数
    const len = str.lastIndexOf(" ") + 1;
    str = str.replace(/\s/g, "");
    const curObj = { name: str };

    // 寻找当前入栈元素的父层级
    while (len <= deepStack.peek()) {
      deepStack.pop();
      strStack.pop();
    }
    const stackTop: nodeObj = strStack.peek();
    stackTop.children
      ? stackTop.children.push(curObj)
      : (stackTop.children = [curObj]);

    // 元素入栈,继续下一轮的比对
    strStack.push(curObj);
    deepStack.push(len);
  }

  return json;
}

注意:上述代码中声明了一个自定义类型nodeObj以及一个自定义类Stack,完整代码请在示例代码中查看。

最后,我们将开头的例子代入上述代码中,校验下它能否正确解决问题。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const text = `
Language
  JavaScript
    TypeScript
    NodeJS
  HTML
Server
  DataBase
    MongoDB
System
  Linux
  Window
`;

const textJSON = DataConversion(text);
console.log(JSON.stringify(textJSON));

image-20220925095216309

image-20220925095349312

示例代码

本文用到的代码完整版请移步:

  • DataConversion.ts
  • DataConversion-test.ts

写在最后

至此,文章就分享完毕了。

我是神奇的程序员,一位前端开发工程师。

如果你对我感兴趣,请移步我的个人网站,进一步了解。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-09-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 神奇的程序员 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
利用栈实现一个简易的计算器(数据结构之栈)
利用栈实现一个简易的计算器 实现了加减乘除运算(没有使用STL) 基本思想: 1.一个数据栈,一个符号栈 2.优先级判断 3.负号和减号的判别与处理 4.括号匹配 代码如下: #include<iostream> #include<string> #include<cstdlib> /*1、创建栈类,采用数组描述; 2、计算数学表达式的值。 输入数学表达式,输出表达式的计算结果。数学表达式由单个数字和 运算符“+”、“-”、“*”、“/”、“(”、“) ”构成,例如 2+3*(4+5)–6/4。 假定表达式
种花家的奋斗兔
2020/11/12
2.3K0
用栈实现字符串的倒转操作
栈和队列是两种常用的数据结构,其中栈是一种只能在同一端进行插入或删除操作的线性表。表中允许进行插入、删除操作的一端称为栈顶。栈顶的当前位置是动态的,可以用一个称为栈顶指针的位置指示器来指示。表的另一端称为栈底。当栈中没有数据元素时称为空栈。栈的插入操作通常称为进栈或入栈,栈的删除操作通常称为退栈或出栈,那如何用栈实现字符串的倒转呢?
算法与编程之美
2024/03/25
890
用栈实现字符串的倒转操作
【数据结构和算法】--- 栈
栈是一种特殊的线性表。相比于链表和顺序表,栈只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
用户11029269
2024/03/19
1430
【数据结构和算法】--- 栈
Js算法与数据结构拾萃(2)
Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.
一粒小麦
2020/02/25
5220
翻转字符串
题意 给定一个字符串,逐个翻转字符串中的每个单词。 单词的构成:无空格字母构成一个单词 输入字符串是否包括前导或者尾随空格?可以包括,但是反转后的字符不能包括 如何处理两个单词间的多个空格?在反转字符串中间空格减少到只含一个 样例 传入一个字符串 " Hello World! ",返回 "World! Hello" 思路 首先 目标字符串 为 null 或者长度为 0,则直接返回空字符串; 先去除两端的空格之后,再找到 目标字符串 的第一个空格的位置 然后用 subString() 将第一个空格之前的
一份执着✘
2018/06/04
5810
JS数据结构第四篇 --- 栈
  在数据结构中有一个栈结构,在内存空间中也有一个栈空间,这两个”栈“是两个不同的概念。这篇我们说的是数据结构中的栈。栈是一种特殊的线性表,特殊性体现在只能在栈顶进行操作,往栈顶添加元素,一般叫push, 入栈;从栈顶移除元素,一般叫pop, 出栈,操作如图:
tandaxia
2019/07/03
1.1K0
JS数据结构第四篇 --- 栈
数据结构知否知否系列之 — 栈篇
栈,英文 Last In First Out 简称 LIFO,遵从后进先出的原则,与 “队列” 相反,在栈的头部添加元素、删除元素,如果栈中没有元素就称为空栈。
五月君
2019/08/30
6540
​LeetCode 394:字符串解码 Decode String
给定一个经过编码的字符串,返回它解码后的字符串。 Given an encoded string, return its decoded string.
爱写bug
2019/08/19
1.4K0
每日一刷《剑指offer》字符串篇之左旋转字符串
汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列  S ,请你把其循环左移 K 位后的序列输出。例如,字符序列 S = ”abcXYZdef” , 要求输出循环左移 3 位后的结果,即 “XYZdefabc”
终有救赎
2023/11/18
1610
每日一刷《剑指offer》字符串篇之左旋转字符串
【数据结构和算法】字符串解码
这是力扣的 394 题,难度为中等,解题方案有很多种,本文讲解我认为最奇妙的一种。
绿毛龟
2024/01/19
1720
【数据结构和算法】字符串解码
【栈与队列】字符串解码
​ 编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。
利刃大大
2025/02/22
1120
「数据结构与算法Javascript描述」栈
栈是一种特殊的列表,栈内的元素只能通过列表的一端访问,这一端称为栈顶。咖啡厅内的一摞盘子是现实世界中常见的栈的例子。只能从最上面取盘子,盘子洗净后,也只能摞在这一摞盘子的最上面。栈被称为一种后入先出(LIFO,last-in-fifirst-out)的数据结构。
用户8921923
2022/10/24
4230
「数据结构与算法Javascript描述」栈
10w字!前端知识体系+大厂面试总结(算法篇)
但是在两个月的算法练习中,第一次体会到编程不仅仅是技术,还是艺术,感受到了编程是一件很酷的事情
zz_jesse
2023/01/30
6030
10w字!前端知识体系+大厂面试总结(算法篇)
【LeetCode】括号问题——2116. 判断一个括号字符串是否有效(解法一)
相关标签:栈、贪心、字符串 题目难度:中等 题目描述 一个括号字符串是只由 '(' 和 ')' 组成的 非空 字符串。 如果一个字符串满足下面 任意 一个条件,那么它就是有效的:
蒙奇D索隆
2025/03/24
730
【LeetCode】括号问题——2116. 判断一个括号字符串是否有效(解法一)
数据结构与算法(八)——栈思想下的算法题目解析
假设表达式中允许包含两种括号:圆括号与方括号,其嵌套顺序随意,即([]())或者[([][])]都是正确的,而[(]或者(()])或者([())都是不正确的格式。请设计一个算法来检验括号是否正确匹配。
拉维
2022/04/19
3590
数据结构与算法(八)——栈思想下的算法题目解析
TypeScript 实战算法系列(一):实现数组栈与对象栈
栈作为一种数据结构,它可以应用在很多地方,当你需要经常获取刚存放进去的数据时,那么栈这种数据结构将是你的首选。 栈的实现方式一般有两种:数组实现和对象实现,这两种实现方式最终实现的功能都是一样的,但是在性能上却有着很大的差别。 本文将详细讲解这两种实现方式的差异并用TypeScript将其实现,欢迎各位感兴趣的开发者阅读本文。
一只图雀
2020/08/27
1.3K0
【栈】删除字符串中的所有相邻重复项 && 比较含退格的字符串
​ 给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
利刃大大
2025/02/20
900
Leetcode | 第C节:字符串综合题(2)
东京奥运会圆满收官!当然我自己也将迎来留学前的最后准备,所以更新速度可能还是会比较慢……但还好,大部分的内容都已经在之前写的差不多了,也希望最后这几篇我也能够尽快更完,当然也希望大家可以谅解~
学弱猹
2021/09/07
7130
比较含退格的字符串!
力扣题目链接:https://leetcode-cn.com/problems/backspace-string-compare
代码随想录
2021/12/24
3K0
比较含退格的字符串!
LeetCode 151. 翻转字符串里的单词(栈)
无空格字符构成一个单词。 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
Michael阿明
2021/02/20
3800
LeetCode 151. 翻转字符串里的单词(栈)
相关推荐
利用栈实现一个简易的计算器(数据结构之栈)
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验