大意
示例标签串:
处理结果:
题目1 根据标签串创建树
需求
需求:给出一个字符串,将这个字符串转换为一棵树。
字符串可以在代码里见到,是以#
开头,按照\
分割的字符串。
你需要将这个字符串,按照树存储为几个长标签串。
请自行编写存储完成后的展示代码。
package com.urfread.review.algorithm.tree;
import org.junit.jupiter.api.Test;
import java.util.List;
/**
* 1.定义标签结点
* 2.定义标签树
* 3.根据标签串创建一棵树(你需要保证父标签id的正确性)
* 4.输出一棵树的内容
*/
class TagNode {
Tag tag;
List<TagNode> children;
}
class Tag {
String label;
int parentId;
int tagId;
}
class TagTree{
Tag root;
}
public class TreeBuild {
@Test
public void buildTreeByStrTest(){
// 示例标签串
String tagString = "#计算机技术/编程语言/Java/注解/" +
"#计算机技术/数据结构与算法分析/树/"+
"#难度/基础/" +
"#重要程度/一般/";
TagNode rootNode =buildTreeByStr(tagString);
// 自行编写输出展示的代码
}
public static TagNode buildTreeByStr(String str){
TagNode rootNode = new TagNode();
// START
// 请在此编写代码
// END
return rootNode;
}
}
实现思路
(以下给出代码,不能匹配这个练习题,这是我实际开发的时候编写的代码)
(只能当做是伪代码)
- 处理根节点。根节点不需要考虑标签内容,直接创建即可。
// 创建根节点
TreeNode rootNode = new TreeNode(null); // 根节点无需标签
rootNode.setTag(new Tag(0,"",0));//但还是给一个,以防空指针异常
- 为了保证标签id的正确性,所以做了特殊处理
int id = 1; // 标签节点的ID从1开始
lastTagIdMap.put(rootNode, id);//在方法外定义的HashMap。含义为:下一个被添加的结点的id。
- 在开始处理字符串之前,我们需要考虑这样一个问题,如何在树中添加一个结点?
我们需要知道一些特征:添加到哪个结点的孩子中、添加的标签是什么。
比如现在我们已经创建了根结点,那我们肯定会把下一个结点添加在根结点的孩子中;
那么结点的内容怎么取?
我们的标签是以#
号开头的,所以去掉#
就可以了。但是后边还连着一堆按\
分割的子标签,那现在怎么办?
我们首先按\
将字符串分割为字符串数组,现在就可以放心的处理第一个结点了。 - 如何处理第二个结点?
分情况,我们是该另开辟一条路径,还是接着刚才的结点往后续。
区分依据就是看这个标签开头是不是#
,如果是,那么就应该另开辟一条路径;如果不是就直接续。
也就是说,我们需要保存上一个结点的引用,不然就不知道该把当前结点添加给谁当孩子了。 - 特殊情况处理
标签的id:记着手动增长。其实到后边,标签的id可以表示它加入到这课树中的顺序,在存到数据库时,可以进行特殊操作。
分叉:如果遇到两个标签串,前半部分一样,后来分叉怎么处理?如果一样,只移动结点指针,不再创建。
答案
package com.urfread.review.algorithm.tree;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.junit.jupiter.api.Test;
import java.util.List;
/**
* 1.定义标签结点
* 2.定义标签树
* 3.根据标签串创建一棵树 (你需要保证父标签id的正确性)
* 4.输出处理结果
*/
@Data
@NoArgsConstructor
@Getter
class TagNode {
Tag tag;
List<TagNode> children;
public TagNode(Tag tag) {
this.tag = tag;
}
public void addChild(TagNode child) {
if (children == null) {
children = new java.util.LinkedList<>();
}
children.add(child);
}
}
@Data
@AllArgsConstructor
class Tag {
int tagId;
String label;
int parentId;
}
class TagTree{
Tag root;
}
public class TreeBuild {
@Test
public void buildTreeByStrTest(){
// 示例标签串
String tagString = "#计算机技术/编程语言/Java/注解/" +
"#计算机技术/数据结构与算法分析/树/"+
"#难度/基础/" +
"#重要程度/一般/";
TagNode rootNode =buildTreeByStr(tagString);
// 自行编写输出展示的代码
printTree(rootNode);
}
public static TagNode buildTreeByStr(String tagStr){
TagNode rootNode = new TagNode();
// START
// 请在此编写代码
rootNode.setTag(new Tag(0,"",0));
int id=1;
String[]tags=tagStr.split("/");
TagNode currentNode=rootNode;
for(String tag:tags){
if (tag.startsWith("#")){
currentNode=rootNode;
tag=tag.substring(1);
}
boolean isExist=false;
if(currentNode.getChildren()!=null)
// 判断是否已经插入
for (TagNode child:currentNode.getChildren()){
if (child.getTag().getLabel().equals(tag)){
// 如果已经存在,则只做移动指针的操作
currentNode=child;
isExist=true;
break;
}
}
// 如果不存在,才会继续添加
if (!isExist){
TagNode newTagNode=new TagNode(new Tag(id++,tag,currentNode.getTag().getTagId()));
currentNode.addChild(newTagNode);
currentNode=newTagNode;
}
}
// END
return rootNode;
}
// 输出一棵树,请添加一些分级缩进
public static void printTree(TagNode rootNode){
// START
// 请在此编写代码
if (rootNode!=null&&rootNode.getChildren()!=null)
for (TagNode child:rootNode.getChildren()){
printTree(child,1);
}
// END
}
public static void printTree(TagNode rootNode,int level){
if (rootNode!=null){
for (int i=0;i<level;i++){
System.out.print(" ");
}
System.out.println(rootNode.getTag().getLabel());
if (rootNode.getChildren()!=null)
for (TagNode child:rootNode.getChildren()){
printTree(child,level+1);
}
}
}
}