Java 数据结构_树

来源:互联网 发布:python serial 模块 编辑:程序博客网 时间:2024/06/06 08:30

Java 数据结构_树


本文由 Luzhuo 编写,转发请保留该信息.
原文: http://blog.csdn.net/Rozol/article/details/78469973


树的基本概念

  • 树是结点的有限集合
  • 双亲: 根结点A是BCD的双亲, 下面的BCD都是A的孩子
  • 兄弟: 同一个双亲之间的结点, 互称为兄弟, BCD互为兄弟
  • 堂兄弟: 双亲在同一层的结点, 互称为堂兄弟, EFGHIJKL互为堂兄弟
  • 度: 连接他的结点数, A的度为3
  • 根结点: 无双亲, 且唯一的结点
  • 分支结点(非终端结点): 度不为0的结点, BCD都是分支结点, 也称中间结点(除A外)
  • 叶结点(终端结点): 度为0的结点, EFGHIJKL都是叶结点.
  • 祖先: 之前所有的结点都是祖先, G的祖先是BA
  • 子孙: 之后所有的结点都是子孙, B的子孙是EFG
  • 有序树(从左到右不能换顺序), 无序树(可换顺序)
  • 深度: 树的最大深度, 这颗树的深度为3
  • 森林: 多个独立的树(互不相交)放在一起就是森林
  • 二叉树: 每个结点的度最多为2的树
  • 树的遍历:

  • 用途:压缩软件-赫夫曼树 / 搜索-人机对战

二叉树的实现方式

数组实现方式, 删除指定索引位置的结点时, 不会删除他的所有孩子
链式实现方式, 删除指定结点时, 会删除他的所有孩子

二叉树的数组实现方式

二叉树的数组实现代码

/** * 二叉树(数组的表示方式) * @author Luzhuo *         A(0) *    B(1)       C(2) *  D(3) E(4)  F(5) G(6)     *  * |A(0)| B(1)|C(2) | D(3)|E(4) | F(5)|G(6) | ...|... | */public class ArrayTree {    // 树的数组表示方式    private Node[] nodes; // 树的指针    private int size; // 数组的大小    public ArrayTree(Node root){        init(1024, root);    }    public ArrayTree(int size, Node root){        init(size, root);    }    /**     * 创建二叉树<br>     * 创建存放结点的数组, 设置该数据结构的容量, 设置根结点     * @param size     * @param root     */    private void init(int size, Node root){        this.nodes = new Node[size];        this.size = size;        // 根结点        this.nodes[0] = root;    }    /**     * 销毁二叉树<br>     * 删除存放结点的数组     */    public void destory(){        nodes = null;    }    /**     * 根据索引搜索结点     * @param nodeIndex 索引     * @return 结点     */    public Node serchNode(int nodeIndex){        if(nodeIndex < 0 || nodeIndex >= this.size){            throw new ArrayIndexOutOfBoundsException("索引越界.");        }        return nodes[nodeIndex];    }    /**     * 添加结点<br>     * 添加在父结点的左边时, 添加到数组的奇数索引位置(1, 3, 5 ...), 添加在父结点的右边时, 添加到数组的偶数索引位置(2, 4, 6 ...)     * @param nodeIndex 结点索引(从0开始)     * @param direction 左边0还是右边1     * @param node 结点     * @return 是否添加成功     */    public boolean addNode(int nodeIndex, int direction, Node node){        if(nodeIndex < 0 || nodeIndex >= this.size){            throw new ArrayIndexOutOfBoundsException("索引越界.");        }        if(this.nodes[nodeIndex] == null){            throw new NullPointerException("该结点为空");        }        // 若某结点再父节点下标 * 2 + 1 ,则表示该结点在左        // 若某结点再父节点下标 * 2 + 2, 则表示该结点在右        int leftIndex = nodeIndex * 2 + 1;        int rightIndex = nodeIndex * 2 + 2;        if(direction == 0){            if(leftIndex >= this.size || this.nodes[leftIndex] != null) return false;            this.nodes[leftIndex] = node;        }else if(direction == 1){            if(rightIndex >= this.size || this.nodes[rightIndex] != null) return false;            this.nodes[rightIndex] = node;        }        return true;    }    /**     * 删除索引<br>     * @param nodeIndex     * @return 被删除的结点     */    public Node deleteNode(int nodeIndex){        if(nodeIndex < 0 || nodeIndex >= this.size){            throw new ArrayIndexOutOfBoundsException("索引越界.");        }        if(this.nodes[nodeIndex] == null){            throw new NullPointerException("该结点为空");        }        Node tempN = this.nodes[nodeIndex];        this.nodes[nodeIndex] = null;        return tempN;    }    /**     * 遍历<br>     * 之间从左向右遍历数组.     */    public void traverse(){        for(int i = 0; i < this.size; i++){            Node data = this.nodes[i];            if(data != null) System.out.print(data + " ");        }    }}class Node{    public char data;    public Node(char data){        this.data = data;    }    @Override    public String toString() {        return String.valueOf(data);    }}

数组方式测试代码

public class ArrayTreeTest {    public static void main(String[] args) {        // 测试        ArrayTree tree = new ArrayTree(new Node('A'));//      tree.addNode(0, 0, new Node('B'));//      tree.addNode(0, 1, new Node('C'));//      tree.addNode(1, 0, new Node('D'));//      tree.addNode(1, 1, new Node('E'));//      tree.addNode(2, 0, new Node('F'));//      tree.addNode(2, 1, new Node('G'));        // ↓ 简化        int nodeIndex = -1;        for(int i = 0; i < 10; i++){            int direction;            if(i%2 == 0){                direction = 0;                nodeIndex++;            }else{                direction = 1;            }            tree.addNode(nodeIndex, direction, new Node((char)(66+i)));        }        tree.traverse();        System.out.println();        System.out.println(tree.serchNode(3));        System.out.println(tree.deleteNode(3));        tree.traverse();        tree.destory();    }}

二叉树的链式实现方式

二叉树的链式实现代码

/** * 二叉树(链式实现方式) * @author Luzhuo *         (0) *    A(1)       B(2) *  C(3) D(4)  E(5) F(6)   * 前序遍历(根左右): 0 1 3 4 2 5 6  * 中序遍历(左根右): 3 1 4 0 5 2 6 * 后序遍历(左右根): 3 4 1 5 6 2 0  */public class LinkedTree {    Node_ root; // 根结点    public LinkedTree(){        init();    }    /**     * 创建链式二叉树<br>     * 初始化根结点的数据0, 索引0, 左孩子指针null, 右孩子指针null, 父节点指针null     */    private void init(){        root = new Node_();        root.data = 0;        root.index = 0;        root.lChildNode = null;        root.rChildNode = null;        root.parentNode = null;    }    /**     * 销毁链式二叉树<br>     * 递归删除所有孩子, 并指针重置为null     */    public void destory(){        this.root.deleteNode();        this.root = null;    }    /**     * 根据索引寻找结点<br>     * 递归查找指定索引位置的结点     * @param nodeindex 索引     * @return 结点     */    public Node_ searchNode(int nodeindex){        return this.root.searchNode(nodeindex);    }    /**     * 添加结点<br>     * 找到指定位置的结点, 将新结点添加到该结点的左边 / 右边, 并将该结点的指针交给新结点     * @param nodeindex 索引     * @param direction 左边0或右边1     * @param node 被挂在的结点     * @return 添加成功返回true,否则返回false;     */    public boolean addNode(int nodeindex, int direction, Node_ node){        Node_ curN = searchNode(nodeindex);        if(curN == null) return false;        // 加入到该结点的左边or右边        if(direction == 0){            curN.lChildNode = node;        }else if(direction == 1){            curN.rChildNode = node;        }        // 并该结点的指针交给插入的结点        node.parentNode = curN;        return true;    }    /**     * 删除指定索引的结点, 注意删除结点,会将挂在在该结点的所有结点同时删除<br>     * 找到指定的结点, 递归删除自己所有的孩子     * @param nodeindex 索引     * @return 被删除的结点, 该结点为空返回null     */    public Node_ deleteNode(int nodeindex){        Node_ curN = searchNode(nodeindex);        if(curN == null) return null;        Node_ tempN = curN;        curN.deleteNode();        curN = null;        return tempN;    }    /**     * 前序遍历(根左右, 根前)     */    public void preorderTraversal(){        this.root.preorderTraversal();    }    /**     * 中序遍历(左根右, 根中)     */    public void inorderTraversal(){        this.root.inorderTraversal();    }    /**     * 后序遍历(左右根, 根后)     */    public void postorderTraversal(){        this.root.postorderTraversal();    }}/** * 结点, 创建必须给index和data赋值 * @author Luzhuo * */class Node_{    public int index; // 索引    public char data; // 数据    public Node_ lChildNode; // 左结点指针    public Node_ rChildNode; // 右结点指针    public Node_ parentNode; // 父结点指针    public Node_(){ }    public Node_(int index, char data){        this.index = index;        this.data = data;    }    /**     * 根据索引寻找结点     * @param nodeindex 索引     * @return 找到结点返回结点, 否则返回null     */    public Node_ searchNode(int nodeindex){        // 是否是自身        if(this.index == nodeindex) return this;        Node_ tempN;        // 是否是左边的孩子,及其子结点        if(this.lChildNode != null){            if(this.lChildNode.index == nodeindex){                return this.lChildNode;            }else{                tempN = this.lChildNode.searchNode(nodeindex);                if(tempN != null) return tempN;            }        }        // 是否是右边的孩子,及其子结点        if(this.rChildNode != null){            if(this.rChildNode.index == nodeindex){                return this.rChildNode;            }else{                tempN = this.rChildNode.searchNode(nodeindex);                if(tempN != null) return tempN;            }        }        return null;    }    public void deleteNode(){        // 删除自己左右边的所有子结点        if(this.lChildNode != null){            this.lChildNode.deleteNode();        }        if(this.rChildNode != null){            this.rChildNode.deleteNode();        }        // 删除自己在父结点上的指针        if(this.parentNode != null){            if(this.parentNode.lChildNode == this){                this.parentNode.lChildNode = null;            }            if(this.parentNode.rChildNode == this){                this.parentNode.rChildNode = null;            }        }           }    /**     * 前序遍历(根左右)<br>     * 每个结点先输出自身(根), 然后递归左结点, 在递归右结点     */    public void preorderTraversal(){        // 根        System.out.println("index: " + this.index + " data: " + data + " === ");        // 左        if(this.lChildNode != null) this.lChildNode.preorderTraversal();        // 右        if(this.rChildNode != null) this.rChildNode.preorderTraversal();    }    /**     * 中序遍历(左根右)     */    public void inorderTraversal(){        // 左        if(this.lChildNode != null) this.lChildNode.inorderTraversal();        // 根        System.out.println("index: " + this.index + " data: " + data + " === ");        // 右        if(this.rChildNode != null) this.rChildNode.inorderTraversal();    }    /**     * 后序遍历(左右根)     */    public void postorderTraversal(){        // 左        if(this.lChildNode != null) this.lChildNode.postorderTraversal();        // 右        if(this.rChildNode != null) this.rChildNode.postorderTraversal();        // 根        System.out.println("index: " + this.index + " data: " + data + " === ");    }}

数组方式测试代码

public class LinkedTreeTest {    public static void main(String[] args) {        // 测试        /*         *         (0)         *    A(1)       B(2)         *  C(3) D(4)  E(5) F(6)           * 前序遍历(根左右): 0 1 3 4 2 5 6          * 中序遍历(左根右): 3 1 4 0 5 2 6         * 后序遍历(左右根): 3 4 1 5 6 2 0          */        LinkedTree tree = new LinkedTree();//      tree.addNode(0, 0, new Node_(1, 'A'));//      tree.addNode(0, 1, new Node_(2, 'B'));//      tree.addNode(1, 0, new Node_(3, 'C'));//      tree.addNode(1, 1, new Node_(4, 'D'));//      tree.addNode(2, 0, new Node_(5, 'E'));//      tree.addNode(2, 1, new Node_(6, 'F'));        // ↓ 简化        int nodeIndex = -1;        for(int i = 0; i < 10; i++){            int direction;            if(i%2 == 0){                direction = 0;                nodeIndex++;            }else{                direction = 1;            }            tree.addNode(nodeIndex, direction, new Node_(i + 1, (char)(65+i)));        }        tree.preorderTraversal();        System.out.println();        tree.inorderTraversal();        System.out.println();        tree.postorderTraversal();        System.out.println();        System.out.println(tree.deleteNode(3).data);        System.out.println(tree.deleteNode(2).data);        tree.preorderTraversal();        tree.destory();    }}