Java基础深化和提高 ---- 数据结构(下)

简介: 树结构是一种非线性存储结构,存储的是具有“一对多”关系的数据元素的集合。

三、 树形结构

1 树形结构简介

树结构是一种非线性存储结构,存储的是具有“一对多”关系的数据元素的集合。

2345_image_file_copy_6.jpg

2 树的相关术语

2.1结点(Node)

使用树结构存储的每一个数据元素都被称为“结点”。

2.2结点的度(Degree of Node)

某个结点所拥有的子树的个数。

2.3树的深度(Degree of Tree)

树中结点的最大层次数。

2.4叶子结点(Leaf Node)

度为 0 的结点,也叫终端结点。

2.5分支结点(Branch Node)

度不为 0 的结点,也叫非终端结点或内部结点。

2.6孩子(Child)

也可称之为子树或者子结点,表示当前结点下层的直接结点。

2.7双亲(Parent)

也可称之为父结点,表示当前结点的直接上层结点。

2.8根节点(Root Node)

没有双亲结点的结点。在一个树形结构中只有一个根节点。

2.9祖先(Ancestor)

从当前结点上层的所有结点。

2.10子孙(Descendant)

当前结点下层的所有结点。

2.11兄弟(Brother)

同一双亲的孩子。

3 二叉树简

二叉树(Binary Tree)是树形结构的一个重要类型。许多实际问题抽象出来的数据结构 往往是二叉树形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其 算法都较为简单,因此二叉树显得特别重要。二叉树特点是每个结点最多只能有两棵子树, 且有左右之分。

3.1 二叉树分类

  3.1.1 满二叉

满二叉树指除最后一层外,每一层上的所有节点都有两个子节点。

2345_image_file_copy_7.jpg

3.1.2 完全二叉

完全二叉树,除最后一层可能不满以外,其他各层都达到该层节点的最大数,最后一层 如果不满,该层所有节点都全部靠左排。

2345_image_file_copy_8.jpg

3.2二叉树遍历

二叉树遍历的方式:

 前序遍历:根-左-右

 中序遍历:左-根-右

 后序遍历:左-右-根

 层序遍历:从上至下逐层遍

3.2.1 前序遍历

前序遍历顺序:根-左-右

2345_image_file_copy_9.jpg

3.2.2 中序遍历

中序遍历顺序:左-根-右

2345_image_file_copy_10.jpg 

3.2.3 后序遍历

后序遍历顺序:左-右-根

2345_image_file_copy_11.jpg

3.2.4 层序遍历

层序遍历顺序: 从根节点出发,依次访问左右孩子结点,再从左右孩子出发,依次它们的孩子结点,直 到节点访问完毕。

2345_image_file_copy_12.jpg

3.3二叉树排序

3.3.1 二叉树排序分析

利用二叉树结构以及遍历方式可以实现基于二叉树的元素排序处理。

2345_image_file_copy_13.jpg

3.3.2 二叉树排序实现

3.3.2.1 创建二叉树排序器类

/**
* 基于二叉树结构实现元素排序处理的排序器
*/
    public class BinaryTreeSort<E extends Integer> {
/**
* 将元素添加到排序器中
*/
    public void add(E element){ }
/**
* 对元素进行排序
*/
    public void sort(){ }
    public static void main(String[] args) { }
}

3.3.2.2 创建结点类

/**
* 定义结点类
*/
class Node<E extends Integer>{
    private E item;//存放元素
    private Node left;//存放左子树地址
    private Node right;//存放右子树地址
    Node(E item){
        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();
    }
}

3.3.2.3 实现向排序器中添加元素方法

/**
* 将元素添加到排序器中
*/
public void add(E element){
    //实例化结点对象
    Node<E> node = new Node<>(element);
    //判断当前二叉树中是否有根结点。如果没有那么新结点则为根结点
    if(this.root == null)
        this.root = node;
    else
        this.root.addNode(node);
}

3.3.2.4 实现排序器中排序方法

/**
* 对元素进行排序
*/
public void sort(){
    //判断根结点是否为空
    if(this.root == null)return ;
        this.root.inorderTraversal();
}

4 自定义树形结构容器

4.1树形结构定义

能够找到当前结点的父结点

能够找到当前结点的子结点

能够找到当前结点的兄弟结点

能够找到当前结点的祖先结点

能够找到当前结点的子孙节点

4.2自定义树形结构分析

2345_image_file_copy_14.jpg

4.3实现自定义树形结构容器

4.3.1 创建树形结构容器类

/**
* 基于树形结构实现元素存储的容器
*/
    public class MyTree<E> {
/**
* 向容器中添加元素
*/
    public void add(E parent,E item){}
/**
* 获取当前结点的父结点
*/
    public E getParent(E item){
        return null;
    }
/**
* 获取当前结点的子结点
*/
    public List<E> getChild(E item){
        return null;
    }
/**
* 获取当前结点的兄弟结点
*/
    public List<E> getBrother(E item){
        return null;
    }
/**
* 获取当前结点的祖先结点
*/
    public List<E> getForefathers(E item){
        return null;
    }
/**
* 获取当前结点的子孙结点
*/
    public List<E> getGrandChildren(E item){
        return null;
    }
    public static void main(String[] args) {}
}

4.3.2 实现添加元素方法

private Map<E,E> map = new HashMap<>();//String--->String
private Map<E,List<E>> map2 = new HashMap<>();//String ---->List
/**
* 向容器中添加元素
*/
public void add(E parent,E item){
    //完成在单结点之间映射
    this.map.put(item,parent);
    //完成多结点之间映射
    List<E> list = this.map2.get(parent);
    //判断当前结点下是否含有子结点,如果没有则创建一个新的 List
    if(list == null){
        list = new ArrayList<>();
        this.map2.put(parent,list);
    }
    list.add(item);
}

4.3.3 获取当前结点的父结点与子结点

4.3.3.1 获取父结点

/**
* 获取当前结点的父结点
*/
public E getParent(E item){
    return this.map.get(item);
}

4.3.3.2 获取子结点

/**
* 获取当前结点的子结点
*/
public List<E> getChild(E item){
    return this.map2.get(item);
}

4.3.4 获取当前结点的兄弟结点

/**
* 获取当前结点的兄弟结点
*/
public List<E> getBrother(E item){
    //获取当前结点的父结点
    E parent = this.getParent(item);
    //获取当前父结点的所有的子结点
    List<E> list = this.getChild(parent);
    List<E> brother = new ArrayList<>();
    if(list != null){
        brother.addAll(list);
        brother.remove(item);
    }
   return brother;
}

4.3.5 获取当前结点的祖先结点

/**
* 获取当前结点的祖先结点
*/
public List<E> getForefathers(E item){
    //获取当前结点的父结点
    E parent = this.getParent(item);
    //结束递归的边界条件
    if(parent == null){
        return new ArrayList<>();
    }
    //递归调用,再次获取当前结点父结点的父结点
    List<E> list = this.getForefathers(parent);
    //将递归到的所有结点元素添加到返回的 List 中
    list.add(parent);
    return list;
}

4.3.6 获取当前结点的子孙节点

/**
* 获取当前结点的子孙结点
*/
public List<E> getGrandChildren(E item){
    //存放所有子孙结点中的元素
    List<E> list = new ArrayList<>();
    //获取当前结点的子结点
    List<E> child = this.getChild(item);
    //结束递归的边界条件
    if (child == null){
        return list;
}
    //遍历子结点
    for(int i=0;i<child.size();i++){
    //获取节点中的元素
    E ele = child.get(i);
    List<E> temp = this.getGrandChildren(ele);
    list.add(ele);
    list.addAll(temp);
    }
  return list;
}

4.3.7 测试自定义容器

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("---------获取父结点---------");
    String parent = myTree.getParent("鱼类");
    System.out.println(parent);
    System.out.println("---------获取子结点---------");
    List<String> child= myTree.getChild("动物");
    for(int i=0;i<child.size();i++){
        System.out.println(child.get(i));
    }
    System.out.println("---------获取兄弟结点---------");
    List<String> brother = myTree.getBrother("脊椎动物");
    for(int i=0;i<brother.size();i++){
        System.out.println(brother.get(i));
    }
    System.out.println("---------获取祖先结点---------");
    List<String> foreFathers = myTree.getForefathers("人");
    for(int i=0;i<foreFathers.size();i++){
        System.out.println(foreFathers.get(i));
    }
    System.out.println("---------获取子孙结点---------");
    List<String> grandChildren = myTree.getGrandChildren("root");
    for(int i =0;i<grandChildren.size();i++){
        System.out.println(grandChildren.get(i));
    }
}
目录
相关文章
|
3月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
106 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
3月前
|
存储 Java
Java中的HashMap和TreeMap,通过具体示例展示了它们在处理复杂数据结构问题时的应用。
【10月更文挑战第19天】本文详细介绍了Java中的HashMap和TreeMap,通过具体示例展示了它们在处理复杂数据结构问题时的应用。HashMap以其高效的插入、查找和删除操作著称,而TreeMap则擅长于保持元素的自然排序或自定义排序,两者各具优势,适用于不同的开发场景。
56 1
|
3月前
|
存储 Java
告别混乱!用Java Map优雅管理你的数据结构
【10月更文挑战第17天】在软件开发中,随着项目复杂度增加,数据结构的组织和管理至关重要。Java中的Map接口提供了一种优雅的解决方案,帮助我们高效、清晰地管理数据。本文通过在线购物平台的案例,展示了Map在商品管理、用户管理和订单管理中的具体应用,有效提升了代码质量和维护性。
100 2
|
3月前
|
存储 Java 开发者
Java Map实战:用HashMap和TreeMap轻松解决复杂数据结构问题!
【10月更文挑战第17天】本文深入探讨了Java中HashMap和TreeMap两种Map类型的特性和应用场景。HashMap基于哈希表实现,支持高效的数据操作且允许键值为null;TreeMap基于红黑树实现,支持自然排序或自定义排序,确保元素有序。文章通过具体示例展示了两者的实战应用,帮助开发者根据实际需求选择合适的数据结构,提高开发效率。
93 2
|
27天前
|
存储 缓存 安全
Java 集合江湖:底层数据结构的大揭秘!
小米是一位热爱技术分享的程序员,本文详细解析了Java面试中常见的List、Set、Map的区别。不仅介绍了它们的基本特性和实现类,还深入探讨了各自的使用场景和面试技巧,帮助读者更好地理解和应对相关问题。
44 5
|
2月前
|
缓存 算法 Java
本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制
在现代软件开发中,性能优化至关重要。本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制。通过调整垃圾回收器参数、优化堆大小与布局、使用对象池和缓存技术,开发者可显著提升应用性能和稳定性。
55 6
|
2月前
|
存储 Java 索引
Java中的数据结构:ArrayList和LinkedList的比较
【10月更文挑战第28天】在Java编程世界中,数据结构是构建复杂程序的基石。本文将深入探讨两种常用的数据结构:ArrayList和LinkedList,通过直观的比喻和实例分析,揭示它们各自的优势与局限,帮助你在面对不同的编程挑战时做出明智的选择。
|
3月前
|
存储 算法 Java
Java 中常用的数据结构
【10月更文挑战第20天】这些数据结构在 Java 编程中都有着广泛的应用,掌握它们的特点和用法对于提高编程能力和解决实际问题非常重要。
38 6
|
3月前
|
存储 Java 开发者
Java中的Map接口提供了一种优雅的方式来管理数据结构,使代码更加清晰、高效
【10月更文挑战第19天】在软件开发中,随着项目复杂度的增加,数据结构的组织和管理变得至关重要。Java中的Map接口提供了一种优雅的方式来管理数据结构,使代码更加清晰、高效。本文通过在线购物平台的案例,展示了Map在商品管理、用户管理和订单管理中的具体应用,帮助开发者告别混乱,提升代码质量。
38 1
|
3月前
|
存储 算法 Java
Java常用的数据结构
【10月更文挑战第3天】 在 Java 中,常用的数据结构包括数组、链表、栈、队列、树、图、哈希表和集合。每种数据结构都有其特点和适用场景,如数组适用于快速访问,链表适合频繁插入和删除,栈用于实现后进先出,队列用于先进先出,树和图用于复杂关系的表示和查找,哈希表提供高效的查找性能,集合用于存储不重复的元素。合理选择和组合使用这些数据结构,可以显著提升程序的性能和效率。

热门文章

最新文章

下一篇
开通oss服务