Tree

Tree

查找性能和插入性能都优于线性结构

二叉树

任何一个节点的子节点数量不超过2

满二叉树

所有叶子节点都在最后一层,而且节点的总数为2^n - 1,n是树的高度

完全二叉树

所有叶子结点都在最后一层或倒数第二层,且最后一层的叶子结点在左边连续,倒数第二层的叶子节点在右边连续

链式存储

public class TreeNode {
int value;

TreeNode lNode;
TreeNode rNode;
public TreeNode(int value){
    this.value = value;
}

public void setlNode(TreeNode lNode) {
    this.lNode = lNode;
}

public void setrNode(TreeNode rNode) {
    this.rNode = rNode;
}
//前序遍历
public void frontShow(){
    System.out.println(value);
    if (lNode != null)
        lNode.frontShow();
    if (rNode != null)
        rNode.frontShow();
}
//中序遍历
public void midShow(){
    if (lNode != null)
        lNode.midShow();
    System.out.println(value);
    if (rNode != null)
        rNode.midShow();
}
//后序遍历
public void afterShow(){
    if (lNode != null)
        lNode.afterShow();
    if (rNode != null)
        rNode.afterShow();
    System.out.println(value);
}
//前序查找
public TreeNode frontSearch(int tag){
    TreeNode target = null;
    if (this.value == tag){
        return this;
    }else {
        if (lNode != null)
            target = lNode.frontSearch(tag);

        if (target != null)
            return target;

        if (rNode != null)
            target = rNode.frontSearch(tag);
    }
    return target;
}
//中序查找
public TreeNode midSearch(int tag){
    TreeNode target = null;
    if (lNode != null)
        target = lNode.midSearch(tag);
    if (this.value == tag)
        return this;
    if (target != null)
        return target;
    if (rNode != null)
        target = rNode.midSearch(tag);
    return target;
}
//后序查找
public TreeNode afterSearch(int tag){
    TreeNode target = null;
    if (lNode != null)
        target = lNode.afterSearch(tag);
    if (target != null)
        return target;
    if (rNode != null)
        target = rNode.afterSearch(tag);
    if (this.value == tag)
        return this;
    return target;
}
//删除子树
public void delete(int tag){
    TreeNode parent = this;
    if (parent.lNode != null && parent.lNode.value == tag){
        parent.lNode = null;
        return;
    }
    if (parent.rNode != null && parent.rNode.value == tag){
        parent.rNode = null;
        return;
    }
    parent = lNode;
    if (parent != null)
        parent.delete(tag);
    parent = rNode;
    if (parent != null)
        parent.delete(tag);
}

顺序存储

顺序存储的二叉树通常情况只考虑完全二叉树

第n个元素的左子节点是:2^n + 1;

第n个元素的右子节点是:2^n + 2;

第n个元素的父节点是:(n - 1)/2;

public class ArrayBinaryTree {
int[] data;
public ArrayBinaryTree(int[] data){
    this.data = data;
}
public void show(){
    frontShow(0);
}
//前序遍历
public void frontShow(int index){
    if (data == null || data.length == 0){
        return;
    }
    System.out.println(data[index]);
    //2*n+1
    if (2 * index + 1 < data.length)
        frontShow(2 * index + 1);
    //2*n+2
    if (2 * index + 2 < data.length)
        frontShow(2 * index + 2);
}

线索二叉树

线索化二叉树,一个节点的前一个节点,叫做前驱节点

线索化二叉树,一个节点的后一个节点,叫做后继节点

public class ThreadedBinaryTree {
ThreadedNode root;

//存储前驱节点
ThreadedNode pre = null;

public void setRoot(ThreadedNode root) {
    this.root = root;
}
//遍历
public void threadIterate(){
    ThreadedNode node = root;
    while (node != null){
        while (node.leftType == 0){
            node = node.leftNode;
        }
        System.out.println(node.value);

        while (node.rightType == 1){
            node = node.rightNode;
            System.out.println(node.value);
        }

        node = node.rightNode;
    }
}

//中序线索化
public void midThread(ThreadedNode node){
    if (node == null)
        return;
    //left
    midThread(node.leftNode);
    if (node.leftNode == null){
        node.leftNode = pre;
        node.leftType = 1;
    }
    if (pre != null && pre.rightNode == null){
        pre.rightNode = node;
        pre.rightType = 1;
    }
    pre = node;
    //right
    midThread(node.rightNode);
}

public ThreadedNode getRoot() {
    return root;
}

霍夫曼树

是n个带权叶子节点构成的所有二叉树中,带权路径长度最小的二叉树

1,先排序

2,取最小两个,两两组合成一棵树,根节点权值为两节点之和

3,将根节点加入序列,重复1,2,过程,直至为零

HuffmanNode

public class HuffmanNode implements Comparable<HuffmanNode>{
int value;
HuffmanNode left;
HuffmanNode right;
public HuffmanNode(int value){
    this.value = value;
}

@Override
public int compareTo(HuffmanNode o) {
    return -(this.value - o.value);
}

@Override
public String toString() {
    return "HuffmanNode{" +
            "value=" + value +
            ", left=" + left +
            ", right=" + right +
            '}';
}

HuffmanTree

public class HuffmanTree {
public static void main(String[] args) {
    int[] arr = new int[] {3, 7, 8, 29, 5, 11, 23, 14};
    HuffmanNode root = createHuffmanTree(arr);

    System.out.println(root);
}
public static HuffmanNode createHuffmanTree(int[] arr){
    //先创建若干个节点
    List<HuffmanNode> nodes = new ArrayList<>();
    for (int value:arr)
        nodes.add(new HuffmanNode(value));

    while (nodes.size() > 1){
        //sort
        Collections.sort(nodes);
        //取出最小两个节点
        HuffmanNode left = nodes.get(nodes.size() - 1);
        HuffmanNode right = nodes.get(nodes.size() - 2);
        //创建新的二叉树
        HuffmanNode parent = new HuffmanNode(left.value + right.value);
        parent.left = left;
        parent.right = right;
        //移除取出的两个节点
        nodes.remove(left);
        nodes.remove(right);
        //放入原来二叉树
        nodes.add(parent);
    }
    return nodes.get(0);
}

霍夫曼编码

  • 定长编码

can

99 97 110

01100011 01100001 01101110

  • 非定长编码

ca n a n n

c:1 a:2 n:3 :4

定义: 0 = , 1=n, 10 = a, 11 = c,

11 10 0 1 0 10 0 1 0 1

注意:字符的编码都不能是其他字符编码的前缀,符合此要求的编码叫前缀编码

  • 霍夫曼编码

ca n a n n

c:1 a:2 n:3 :4

字符为叶子节点,次数为权重,左 0 ,右 1 ,构建霍夫曼树

public class Node implements Comparable<Node>{
int weight;
Node left;
Node right;
//字符
Byte data;
public Node(Byte data, int weight){
    this.weight = weight;
    this.data = data;
}

Huffman 解压缩文件源码:https://github.com/MAPENGMASK/Java/tree/master/src/datastructure/huffman

二叉排序树 BST

对于二叉树中的任何一个非叶子节点,要求左子节点比当前节点值小,右子节点比当前节点值大。

优化查找效率

BST 编码实现:https://github.com/MAPENGMASK/Java/tree/master/src/datastructure/bst

AVL树

进一步优化二叉排序树查找效率

左子树与右子树的高度差的绝对值不超过1

左子树和右子树都是平衡二叉树

多路查找树

页是计算机管理存储器的逻辑块,硬件及操作系统往往将主存和磁盘存储区分割为连续的大小相等的块,每个存储块称为一页(默认大小为 4 k),主存和磁盘以页为单位交换数据。

文件系统及数据库设计者利用磁盘预读原理,将一个节点的大小设为等于一页,这样每个节点只需一次I/O就可完全载入。


数据量较小时,存储在内存中

数据量较大时,存储到磁盘里,必须要面对多次磁盘I/O操作,耗时比较大的问题

如果扩展树中的节点,可以很好的解决上述问题

2-3树

在这里插入图片描述

1,所有叶子节点都在同一层

2,有二节点存在,二节点要么有两个子节点,要么没有节点

3,有三节点存在,三节点要么有三个子节点,要么没有节点

B树,B+树

B树:节点扩充,规则如2-3树,也可以是2-3-4 树

B树的阶为该树中最高节点规模数,如2-3树的阶为3

B+树:B树的变形,非叶子节点只存储索引信息,不存储数据

叶子节点最右边指针指向下一个相邻的叶节点

所有的叶节点组成一个有序链表

优点:便于搜索,通过读取非叶子节点,再通过一次I/O找到所要的数据

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Mr.Ma.01

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

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

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

打赏作者

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

抵扣说明:

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

余额充值