数据结构:树结构、自定义树结构存储容器

树形结构

  • 树形结构简介
    一对多的关系
    在这里插入图片描述

  • 树的相关术语

  • 结点(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);
		}*/
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

The Mutents

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值