树形结构
-
树形结构简介
一对多的关系
-
树的相关术语
-
结点(Node)
使用树结构存储的每一个数据元素都被称为“结点”。 -
结点的度(Degree of Node)
某个结点所拥有的子树的个数。 -
树的深度(Degree of Tree)
树中结点的最大层次数。 -
叶子结点(Leaf Node)
度为0的结点,也叫终端结点。 -
分支结点(Branch Node)
度不为О的结点,t也叫非终端结点或内部结点。 -
孩子(Child)
也可称之为子树或者子结点,表示当前结点下层的直接结点。 -
双亲(Parent)
也可称之为父结点,表示当前结点的直接上层结点。 -
根节点(Root Node)
没有双亲结点的结点。在一个树形结构中只有一个根节点。 -
祖先(Ancestor)
从当前结点上层的所有结点。 -
子孙(Descendant)
当前结点下层的所有结点。 -
根节点(Root Node)
没有双亲结点的结点。在一个树形结构中只有一个根节点。 -
兄弟(Brother)
同—双亲的孩子.
- 二叉树简介
二叉树分类
-
满二叉树
满二叉树指除最后一层外,每一层上的所有节点都有两个子节点。
- 完全二叉树
完全二叉树,除最后一层可能不满以外,其他各层都达到该层节点的最大数,最后一层如果不满,该层所有节点都全部靠左排。
- 完全二叉树
-
二叉树遍历
-
前序遍历
-
中序遍历
-
后序遍历
-
层序遍历
- 二叉树排序分析
按如下树结构存储元素时(小的元素放左子树中,大的元素放右子树中),使用中序遍历即可获得元素从小到大排序
- 创建二叉树排序器类
import javax.print.attribute.IntegerSyntax;
/**
* 基于二叉树结构实现元素排序的排序器
* @author Lhk
* */
public class BinaryTreeSort<E extends IntegerSyntax> {
/**
* 将元素添加到排序器
*/
public void add(E element){
}
/**
* 对元素进行排序
*/
public void sort(){
}
public static void main(String[] args) {
}
}
- 创建结点类
/**
* 结点类
*/
class Node<E extends Integer>{
private E item;//存放元素值
private Node left;//存放左子树结点对象地址
private Node right;//存放右子树结点对象地址
public Node(E item, Node left, Node right) {
super();
this.item = item;
this.left = left;
this.right = right;
}
/**
* 添加结点
*/
public void addNode(Node node){
//完成新结点元素与当前结点元素的判断
//如果新结点元素小于当前结点元素,则新结点放到当前结点的左子树
if(node.item.intValue()<this.item.intValue()){
if(this.left==null)
this.left=node;
else
this.left.addNode(node);
}
//如果新结点元素大于当前结点元素,则新结点放到当前结点的右子树
else{
if(this.right==null)
this.right=node;
else
this.right.addNode(node);
}
}
/**
* 使用中序遍历遍历二叉树
*/
public void inorderTraversal(){
//找到最左侧的结点
if(this.left!=null) this.left.inorderTraversal();
System.out.println(this.item);
if(this.right!=null) this.right.inorderTraversal();
}
}
实现各个方法
private Node root ;//存放树的根节点
/**
* 将元素添加到排序器
*/
public void add(E element){
//实例化结点对象
Node<E> node=new Node<>(element);
//判断当前二叉树中是否有根节点,如果没有,则新结点为根节点
if(this.root==null){
this.root=node;
}else{
this.root.addNode(node);
}
}
/**
* 对元素进行排序
*/
public void sort(){
//判断根节点是否为空,为空则无序排序
if(this.root==null) return ;
this.root.inorderTraversal();
}
完整测试代码:
package CustomStructure;
import javax.print.attribute.IntegerSyntax;
/**
* 基于二叉树结构实现元素排序的排序器
* @author Lhk
*
*/
public class BinaryTreeSort<E extends Integer> {
/**
* 结点类
*/
class Node<E extends Integer>{
private E item;//存放元素值
private Node left;//存放左子树结点对象地址
private Node right;//存放右子树结点对象地址
public Node(E item) {
super();
this.item = item;
}
/**
* 添加结点
*/
public void addNode(Node node){
//完成新结点元素与当前结点元素的判断
//如果新结点元素小于当前结点元素,则新结点放到当前结点的左子树
if(node.item.intValue()<this.item.intValue()){
if(this.left==null)
this.left=node;
else
this.left.addNode(node);
}
//如果新结点元素大于当前结点元素,则新结点放到当前结点的右子树
else{
if(this.right==null)
this.right=node;
else
this.right.addNode(node);
}
}
/**
* 使用中序遍历遍历二叉树
*/
public void inorderTraversal(){
//找到最左侧的结点
if(this.left!=null) this.left.inorderTraversal();
System.out.println(this.item);
if(this.right!=null) this.right.inorderTraversal();
}
}
private Node root ;//存放树的根节点
/**
* 将元素添加到排序器
*/
public void add(E element){
//实例化结点对象
Node<E> node=new Node<>(element);
//判断当前二叉树中是否有根节点,如果没有,则新结点为根节点
if(this.root==null){
this.root=node;
}else{
this.root.addNode(node);
}
}
/**
* 对元素进行排序
*/
public void sort(){
//判断根节点是否为空,为空则无序排序
if(this.root==null) return ;
this.root.inorderTraversal();
}
public static void main(String[] args) {
BinaryTreeSort<Integer> i=new BinaryTreeSort<>();
//测试数据:15,21,18,3,55,4,32
i.add(15);
i.add(21);
i.add(18);
i.add(3);
i.add(55);
i.add(4);
i.add(32);
i.sort();
}
}
- 自定义树形结构容器
1. 树形结构的定义
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210512223317771.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzMzNzc3,size_16,color_FFFFFF,t_70
2.自定义树形结构分析
由于树形结构的结点比较复杂,每个结点的父结点、子节点数量不一,故我们使用Map和List容器来实现树结构的结点类,Map表示结点间的映射,List存储每个结点的子结点
3.实现自定义树形结构容器类
- 创建树形结构容器类
package CustomStructure;
import java.util.List;
/**
* 自定义基于树形结构实现元素存储的容器
* @author Lhk
*
*/
public class MyTree<E> {
/**
* 向容器中添加元素
*/
public void add(E parent,E item){
}
/**
* 获取当前结点的父结点
*/
public E getParents(E item){
return null;
}
/**
* 获取当前结点的子结点
*/
public List<E> getChilds(E item){
return null;
}
/**
* 获取当前结点的兄弟结点
*/
public List<E> getBrothers(E item){
return null;
}
/**
* 获取当前结点的祖先结点
*/
public List<E> getAncestors(E item){
return null;
}
/**
* 获取当前结点的子孙结点
*/
public List<E> getGrandchildren(E item){
return null;
}
public static void main(String[] args) {
}
}
- 实现各个方法
private Map<E, E> map1=new HashMap<>();//映射:E(child)------>E(parent)
private Map<E, List<E>> map2=new HashMap<>();//映射:E(parent)------>List(child)
/**
* 向容器中添加元素
*/
public void add(E parent,E item){
//完成单结点之间的映射(更容易获取父结点)
this.map1.put(item, parent);
//完成多结点之间的映射(更容易获取子结点)
List<E> list=this.map2.get(parent);
//判断当前结点下是否含有子结点,没有则创建一个新的List来存储子结点
if(list==null){
list=new ArrayList<>();
this.map2.put(parent, list);
}
//将新元素添加到list中
list.add(item);
}
/**
* 获取当前结点的父结点
*/
public E getParents(E item){
return this.map1.get(item);
}
/**
* 获取当前结点的子结点
*/
public List<E> getChilds(E item){
return this.map2.get(item);
}
/**
* 获取当前结点的兄弟结点
*/
public List<E> getBrothers(E item){
//获取当前结点的父结点
E parent=this.getParents(item);
//根据父结点获取子结点
List<E> list=map2.get(parent);
List<E> brother=new ArrayList<>();
if(list!=null){
brother.addAll(list);
brother.remove(item);
}
return brother;
}
/**
* 获取当前结点的祖先结点
*/
public List<E> getAncestors(E item){
//获取当前结点的父结点
E parent=this.getParents(item);
//结束递归的边界条件
if(parent==null){
return new ArrayList<>();
}
//递归调用,再次获取该父结点的父结点
List<E> list=this.getAncestors(parent);
list.add(parent);
return list;
}
/**
* 获取当前结点的子孙结点
*/
public List<E> getGrandchildren(E item){
//存放所有子孙结点中的元素
List<E> list=new ArrayList<>();
//获取当前结点的子结点
List<E> childs=this.getChilds(item);
//结束递归的边界条件
if(childs==null){
return list;
}
//遍历子结点
for(int i=0;i<childs.size();i++){
E child=childs.get(i);
List<E> temp= this.getGrandchildren(child);
list.add(child);
list.addAll(temp);
}
return list;
}
完整测试代码
package CustomStructure;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.w3c.dom.ls.LSInput;
/**
* 自定义基于树形结构实现元素存储的容器
* @author Lhk
*
*/
public class MyTree<E> {
private Map<E, E> map1=new HashMap<>();//映射:E(child)------>E(parent)
private Map<E, List<E>> map2=new HashMap<>();//映射:E(parent)------>List(child)
/**
* 向容器中添加元素
*/
public void add(E parent,E item){
//完成单结点之间的映射(更容易获取父结点)
this.map1.put(item, parent);
//完成多结点之间的映射(更容易获取子结点)
List<E> list=this.map2.get(parent);
//判断当前结点下是否含有子结点,没有则创建一个新的List来存储子结点
if(list==null){
list=new ArrayList<>();
this.map2.put(parent, list);
}
//将新元素添加到list中
list.add(item);
}
/**
* 获取当前结点的父结点
*/
public E getParents(E item){
return this.map1.get(item);
}
/**
* 获取当前结点的子结点
*/
public List<E> getChilds(E item){
return this.map2.get(item);
}
/**
* 获取当前结点的兄弟结点
*/
public List<E> getBrothers(E item){
//获取当前结点的父结点
E parent=this.getParents(item);
//根据父结点获取子结点
List<E> list=map2.get(parent);
List<E> brother=new ArrayList<>();
if(list!=null){
brother.addAll(list);
brother.remove(item);
}
return brother;
}
/**
* 获取当前结点的祖先结点
*/
public List<E> getAncestors(E item){
//获取当前结点的父结点
E parent=this.getParents(item);
//结束递归的边界条件
if(parent==null){
return new ArrayList<>();
}
//递归调用,再次获取该父结点的父结点
List<E> list=this.getAncestors(parent);
list.add(parent);
return list;
}
/**
* 获取当前结点的子孙结点
*/
public List<E> getGrandchildren(E item){
//存放所有子孙结点中的元素
List<E> list=new ArrayList<>();
//获取当前结点的子结点
List<E> childs=this.getChilds(item);
//结束递归的边界条件
if(childs==null){
return list;
}
//遍历子结点
for(int i=0;i<childs.size();i++){
E child=childs.get(i);
List<E> temp= this.getGrandchildren(child);
list.add(child);
list.addAll(temp);
}
return list;
}
public static void main(String[] args) {
//实例化自定义树容器
MyTree<String> myTree=new MyTree<>();
//在自定义树容器中添加元素
myTree.add("root", "生物");
myTree.add("生物", "植物");
myTree.add("生物", "动物");
myTree.add("生物", "菌类 ");
myTree.add("动物", "脊椎动物");
myTree.add("动物", "脊索动物");
myTree.add("动物", "腔肠动物");
myTree.add("脊椎动物", "哺乳动物");
myTree.add("脊椎动物", "鱼类");
myTree.add("哺乳动物", "牛");
myTree.add("哺乳动物", "人");
myTree.add("哺乳动物", "猫");
System.out.println("-----获取父结点-----");
System.out.println(myTree.getParents("鱼类"));
System.out.println("-----获取子结点-----");
System.out.println(myTree.getChilds("动物"));
System.out.println("-----获取兄弟结点-----");
List<String> brother=myTree.getBrothers("动物");
for(String str:brother){
System.out.println(str);
}
System.out.println("-----获取祖先结点-----");
List<String> ancestor=myTree.getAncestors("人");
for(String str:ancestor){
System.out.println(str);
}
System.out.println("-----获取子孙结点-----");
List<String> grandChildren=myTree.getGrandchildren("root");
System.out.println(grandChildren);
/*for(String str:grandChildren){
System.out.println(str);
}*/
}
}