定义: 一棵二叉查找树是一棵二叉树,每一个节点都含有一个Comparable的键(以及对应的值)。 每一个节点的键都大于左子树中任意节点的键而小于右子树中任意节点的键。node
树的术语:ide
Name | Function |
---|---|
路径 | 顺着链接点的边从一个节点走向另外一个节点,所通过的节点的顺序排列就称为路径。 |
根 | 树顶端的节点就称为根,一棵树只有一个根,若是要把一个节点和边的集合定义为树,那么从根到其余任何一个节点都必须有一条路径。 |
父节点 | 每一个节点(除了根)都刚好有一条边向上链接到另外一个节点,上面的节点就称为下面节点的“父节点”。 |
子节点 | 每一个节点均可能有一条或多条边向下链接其余节点,下面的这些节点就称为它的“子节点”。 |
叶节点 | 没有子节点的节点称为“叶子节点”或简称“叶节点”。树只能有一个根,可是能够有不少叶节点。 |
子树 | 每一个节点均可以做为子树的根,它和它全部的子节点,子节点的子节点等都含在子树中。 |
访问 | 当程序控制流程到达某个节点的时候,就称为“访问”这个节点,一般是为了在这个节点处执行某种操做,例如查看节点某个数据字段的值或者显示节点。 |
遍历 | 遍历树意味着要遵循某种特定的顺序访问树中的全部节点。 |
层 | 一个节点的层数是指从根开始到这个节点有多少“代”。 |
关键字 | 能够看到,对象中一般会有一个数据域被指定为关键字值。这个值一般用于查询或者其余操做。 |
二叉树 | 若是树中的每一个节点最多只能有两个子节点,这样的树就称为“二叉树”。 |
性质:ui
根据其二叉树的特性,节点类以下:this
public class Node { public int index;//关键字段 public String data;//值 public Node leftNode;//左节点 public Node rightNode;//右节点 @Override public boolean equals(Object obj) { return EqualsBuilder.reflectionEquals(this, obj); } @Override public int hashCode() { return HashCodeBuilder.reflectionHashCode(this); } }
其中引用了commons-lang3包中的内容,做为对象进行比较code
查找某个节点,至关于二分查找,若是小于当前节点,则走左边,若是大于当前节点,则走右边。当最后叶子节点尚未找到,则没有找到对象
public Node findNode(int key){ Node current = root; while(current.index != key){ if(key < current.index){//左节点 current = current.leftNode; }else{//右节点 current = current.rightNode; } if(current == null){ return null; } } return current; }
插入节点,按照插入的节点都不会出现重复关键字。每一次插入都将变为根节点的子节点,例如根节点关键字为1,接下来插入的节点则变为根节点的右子节点。blog
public void insertNode(int key,String value){ Node node = new Node(); node.index = key; node.data = value; if(root == null){ root = node; return; } //找到插入节点的位置 Node parent = root; Node current = root; while(true){ parent = current; if(key == current.index){ return; } if(key < current.index){//左节点 current = current.leftNode; if(current == null){//当前节点已是叶子结点了 parent.leftNode = node; return; } }else{ current = current.rightNode; if(current == null){ parent.rightNode = node; return; } } } }
遍历节点,中序遍历.索引
public void inOrder(Node localRoot) { if (localRoot != null) { inOrder(localRoot.leftNode); System.out.println("索引:" + localRoot.index + ",值:" + localRoot.data); inOrder(localRoot.rightNode); } }
删除节点,分三种状况:hash
public boolean delete(int key) { Node current = root; Node parent = root; boolean isLeftChild = true; //找到被删除的节点,并标识该节点是否为左节点 while (current.index != key) { parent = current; if (key < current.index) { isLeftChild = true; current = current.leftNode; } else { isLeftChild = false; current = current.rightNode; } if (current == null) { return false; } } //第一种状况,删除节点为子节点 if (current.leftNode == null && current.rightNode == null) { if (current == root) { root = null; } else { if (isLeftChild) { parent.leftNode = null; } else { parent.rightNode = null; } } } else if ((current.leftNode != null && current.rightNode == null) || (current.leftNode == null && current.rightNode != null)) { //第二中状况,删除节点只包含一个子节点,则将子节点移动动当前节点中 if (current.rightNode == null) {//删除的节点的左节点有值,右节点为空 if (root == current) { root = current.leftNode; } else { if (isLeftChild) { parent.leftNode = current.leftNode; } else { parent.rightNode = current.leftNode; } } } else {//删除的节点的右节点有值,左节点为空 if (root == current) { root = current.rightNode; } else { if (isLeftChild) { parent.leftNode = current.rightNode; } else { parent.rightNode = current.rightNode; } } } } else if (current.leftNode != null && current.rightNode != null) { //第三种状况,删除节点中有左右两个节点 //找到后继节点 Node processer = processer(current); if (current == root) {//删除是根节点,则 root = processer; } else { if (isLeftChild) { parent.leftNode = processer; } else { parent.rightNode = processer; } } //选中的节点的左节点与删除节点的左节点相连 processer.leftNode = current.leftNode; } return true; } //找到后继节点 private Node processer(Node delNode) { Node parent = delNode; Node success = delNode; Node current = delNode.rightNode; while (current != null) { // 后继节点父节点首先保存后继节点的状态 parent = current; success = current; // 后继节点 不断的向左更新 current = current.leftNode; } // 假如咱们找到的后继节点不直接是 要删除节点的右节点 而是在其右节点那条子树上面最小的一个节点 if (success != delNode.rightNode) { //后继节点的父节点断开其与后继节点左边的引用,从新链接上后继节点的右子节点(由于后继节点是没有左子节点的,锁以要保存以前树的状态,还要把后继节点的右子节点处理一下,无论 其存在不存在) parent.leftNode = success.rightNode; // 这时候后继节点的右边已经空了 上一条语句已经将其给了本身父节点的左子节点 而后让后继节点的右边 链接要删除节点的右子树 success.rightNode = delNode.rightNode; } return success; }