Android 从零学数据结构与算法(5)——二叉树的建立、赫夫曼树、查找二叉树

    本博客的原创文章,都是本人平时学习所做的笔记,不做商业用途,如有侵犯您的知识产权和版权问题,请通知本人,本人会即时做出处理删除文章。

    这篇是接着上一篇的内容。

  • 二叉树的建立:

    通过前序遍历的数据序列反向生成二叉树。    

public class TreeNode {//树的节点
    public int index;
    public String date;
    public  TreeNode leftChild;
    public  TreeNode rightChild;
    
    public TreeNode(int index, String date) {
        this.index = index;
        this.date = date;
    }
    public int getIndex() {
        return index;
    }
    public String getDate() {
        return date;
    }
}
public class TreeTest {
    private TreeNode root;
    public  TreeNode createBinaryTree(int size,ArrayList<String> data){
        if (data==null) {
            return null;
        }
        String d = data.get(0);
        TreeNode treeNode;
        int index=size-data.size();
        if (d.equals("#")) {//遇到#代表没有子分支节点
            treeNode = null;
            data.remove(0);
            return treeNode;
        }
        treeNode=new TreeNode(index,d);
        if (index == 0) {
            //创建根节点
            root = treeNode;
        }
        
            data.remove(0);
            treeNode.leftChild=createBinaryTree(size,data);//创建左分支节点
            treeNode.rightChild=createBinaryTree(size,data);//创建右分支节点

        return treeNode;
    }
    //前序遍历
    public void printTreeNode(TreeNode treeNode){
        if (treeNode==null) {
            return;
        }
        System.out.println(treeNode.getDate());
        printTreeNode(treeNode.leftChild);
        printTreeNode(treeNode.rightChild);

    }
}
  @Test
    public void TreeTest() throws Exception {
        TreeTest treeTest = new TreeTest();
        String [] data={"A","B","#","D","#","#","C","#","#"};
        ArrayList<String> list = new ArrayList<>();
        for (String datum : data) {
            list.add(datum);
        }
        TreeNode binaryTree = treeTest.createBinaryTree(list.size(), list);
        treeTest.printTreeNode(binaryTree);
    }
    运行test程序,输出结果为ABDC。
  • 赫夫曼树

    给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。





    赫夫曼大叔说,从树中一个结点到另一个结点之间的分支构成两个结点之间的路径,路径上的分支数目称做路径长度。图二叉树a中,根结点到结点D的路径长度就为4,二叉树b中根结点到结点D的路径长度为2。树的路径长度就是从树根到每一结点的路径长度之和。二叉树a的树路径长度就为1+1+2+2+3+3+4+4=20。二叉树b的树路径长度就为1+2+3+3+2+1+2+2=16。

    如果考虑到带权的结点,结点的带权的路径长度为从该结点到树根之间的路径长度与结点上权的乘积。树的带权路径长度为树中所有叶子结点的带权路径长度之和。假设有n个权值{w1,w2,…"wn},构造一棵有n个叶子结点的二叉树,每个叶子结点带权wk,每个叶子的路径长度为lk,我们通记作,则其中带权路径长度WPL最小的二叉树称做赫夫曼树。

    二叉树a的WPL=5×1+15×2+40×3+30X4+10×4=315

    二叉树b的wPL=5X3+15X3+40×2+30×2+10×2=220

    赫夫曼树可以提高效率,赫夫曼编码还可以压缩文件。

  • 查找二叉树

    二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。


    创建查找二叉树

public class TreeNode {//双向链表
    public int key;
    public int date;
    public TreeNode leftChild;
    public TreeNode rightChild;
    public TreeNode parent;
    public TreeNode(int key, int date) {
        this.key = key;
        this.date = date;
    }
    public int getIndex() {
        return key;
    }
    public int getDate() {
        return date;
    }
}
public class TreeTest {
    public TreeNode root;
    //创建查找二叉树,添加节点
    public  TreeNode put(int data){
        TreeNode treeNode = null;
        TreeNode parent = null;
        if (root==null) {//创建根节点
            treeNode = new TreeNode(0, data);
            root=treeNode;
            return treeNode;
        }
        treeNode = root;//从根节点开始查找
        //查找添加元素父节点的位置
        while (treeNode != null) {
            parent=treeNode;
            if (data > treeNode.date) {//大于就往右找
                treeNode=treeNode.rightChild;
            } else if (data < treeNode.date) {//小于就往左找
                treeNode = treeNode.leftChild;
            } else {
                //相等跳出循环
                return treeNode;
            }

        }
        //循环完毕表示此节点添加到相应位置
        treeNode = new TreeNode(0, data);
        if (data < parent.date) {
            parent.leftChild = treeNode;
        } else {
            parent.rightChild = treeNode;
        }
        treeNode.parent=parent;
        return treeNode;
    }
    //中序遍历
    public void printTreeNode(TreeNode treeNode){
        if (treeNode==null) {
            return;
        }
        printTreeNode(treeNode.leftChild);
        System.out.println(treeNode.getDate());
        printTreeNode(treeNode.rightChild);

    }
}
 @Test
    public void TreeTest1() throws Exception {
        TreeTest treeTest = new TreeTest();
        int [] data={10,20,50,30,40,60};
        ArrayList<Integer> list = new ArrayList<>();
        for (int datum : data) {
            treeTest.put(datum);
        }
        treeTest.printTreeNode(treeTest.root);//中序打印
    }
    查找二叉树用中序打印是按数值的顺序打印,所以打印结果为10,20,30,40,50,60

    删除查找二叉树

public class TreeNode {
    public int key;
    public int data;
    public TreeNode leftChild;
    public TreeNode rightChild;
    public TreeNode parent;


    public TreeNode(int key, int date) {
        this.key = key;
        this.data = date;
    }
    public int getIndex() {
        return key;
    }
    public int getData() {
        return data;
    }
}
  public  void deleteNode(int key) throws Exception {
        //查找是否有这个节点
        TreeNode treeNode=searchNode(key);
        if (treeNode == null) {
            throw new Exception("该节点无法找到");
        } else {
            //删除节点
            delete(treeNode);
        }
    }

    private void delete(TreeNode treeNode) {
        TreeNode parent = treeNode.parent;
        //被删除的节点无左右孩子
        if (treeNode.leftChild==null&&treeNode.rightChild==null) {
            if (parent.rightChild==treeNode) {
                parent.rightChild=null;

            } else if (parent.leftChild==treeNode) {
                parent.leftChild = null;
            }
            treeNode.parent = null;
        }
        //被删除的节点有左无右
      else  if (treeNode.leftChild!=null&&treeNode.rightChild==null) {
            if (treeNode==root) {//删除无右孩子的根节点
                root=treeNode.rightChild;
                root.parent=null;
                return;
            }
            if (parent.rightChild==treeNode) {
                parent.rightChild=treeNode.leftChild;
                treeNode.leftChild.parent = parent;
            }else if (parent.leftChild==treeNode) {
                parent.leftChild = treeNode.leftChild;
                treeNode.leftChild.parent = parent;
            }
            treeNode.parent = null;
        }
        //被删除的节点有右无左
        else  if (treeNode.leftChild==null&&treeNode.rightChild!=null) {
            if (treeNode==root) {//删除无左孩子的根节点
                root=treeNode.rightChild;
                root.parent=null;
                return;
            }
            if (parent.rightChild==treeNode) {
                parent.rightChild=treeNode.rightChild;
                treeNode.rightChild.parent = parent;
            }else if (parent.leftChild==treeNode) {
                parent.leftChild = treeNode.rightChild;
                treeNode.rightChild.parent = parent;
            }
            treeNode.parent = null;
        }
        else //既有左孩子又有右孩子
        {      //找到该节点后继节点
             TreeNode next=getNextNode(treeNode);
             delete(next);
            treeNode.data = next.data;
        }
    }

    //获取一个节点的后继节点
    private TreeNode getNextNode(TreeNode treeNode) {
        if (treeNode == null) {
            return null;
        } else {
            if (treeNode.rightChild != null) {
                //查找右节点中最小节点
                return getMinTreeNode(treeNode.rightChild);
            } else {
                TreeNode parent=treeNode.parent;
                while (parent != null && treeNode == parent.rightChild) {
                    treeNode=parent;
                    parent = parent.parent;
                }
                return parent;
            }
        }
    }
    //查找最小节点
    private TreeNode getMinTreeNode(TreeNode node) {
        if (node == null) {
            return null;
        } else {
            while (node.leftChild != null) {
                node=node.leftChild;
            }
        }
        return node;
    }

    //查找节点
    private TreeNode searchNode(int key) {
        TreeNode node = root;
        if (node == null) {
            return null;
        } else {
            //如果node为空了代表没找到,或者找到了跳出循环
            while (node != null && key != node.data) {
                if (key < node.data) {
                    node=node.leftChild;
                } else {
                    node=node.rightChild;
                }
            }
        }
        return node;
    }
  @Test
    public void TreeTest() throws Exception {
        TreeTest treeTest = new TreeTest();
        int [] data={10,20,50,30,40,60};
        ArrayList<Integer> list = new ArrayList<>();
        for (int datum : data) {
            treeTest.put(datum);
        }
        treeTest.printTreeNode(treeTest.root);
        treeTest.deleteNode(60);
        treeTest.printTreeNode(treeTest.root);
    }
    上面是删除查找二叉树节点的全部代码。

------------------------------------------------       

    想要继续跟我一起学习一起成长,请关注我的公众号:程序员持续发展方案






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值