二叉树
原文链接:http://www.orlion.ga/267/
为什么使用二叉树呢?因为它通常结合了另外两种数据结构的优点:一种是有序数组,另一种是链表。在树中查找数据项的速度和在有序数组中查找一样快,并且插入数据项和删除数据项的速度也和链表一样。
二叉搜索树:
非平衡树:树的大部分的节点是在根的一边或者是另一边,如下图所示
树变得不平衡是由数据项插入的顺序造成的。
用java代码来表示树
像其他数据结构一样,有很多方法可以在计算机内存中表示树,最常用的方法是把节点存储在无关联的存储器中,而通过每个节点中指向自己子节点的引用来连接。
还可以在内存中用数组来表示树,用存储在数组中相对的位置来表示节点在树中的位置。实例中的java代码采用的是引用连接节点的方法。
Node类
首先,需要一个节点对象的类,这些对象包含数据,数据代表要存储的内容,而且还有指向节点的两个子节点的引用。类代码如下:
package ga.orlion.btree; public class Node { int iData; // 节点数 double fData; // 其他数 Node leftChild; // 左节点 Node rightChild;// 右节点 public void displayNode(){ // 显示节点数据 } }
还需要一个类来表示树本身:Tree类
package ga.orlion.btree; public class Tree { private Node root; // 根节点 public Node find(int key){ // 查询 } public void insert(int id , double dd){ // 插入 } public void delete(int id){ // 删除 } }
最后是一个操作树的类TreeApp:
package ga.orlion.btree; public class TreeApp { public static void main(String[] args) { Tree theTree = new Tree(); theTree.insert(50, 1.5); theTree.insert(25, 1.7); theTree.insert(75, 1.9); Node found = theTree.find(25); // 查找key为25的节点 if (found == null) System.out.println("未找到key25"); else System.out.println("找到key25"); } }
查找节点
Tree中的查找方法find():
public Node find(int key){ Node current = root; while (current.iData != key) { if (key < current.iData) current = current.leftChild; else current = current.rightChild; if (current == null) return null; } return current; }
树的效率
查找节点的时间取决于这个节点所在的层数。
插入一个节点
insert()方法从创建新节点开始,用提供的数据作为参考。下一步insert()必须先确定新节点插入的位置,这段代码与查找代码大致相同,区别是查找节点时遇到null直接返回现在要插入节点就是在返回前插入节点。
java代码:
public void insert(int id , double dd){ Node newNode = new Node(); newNode.iData = id; newNode.fData = dd; if (root == null) root = newNode; else { Node current = root; Node parent; while(true){ parent = current; if (id < current.iData) { current = current.leftChild; if (current == null) { parent.leftChild = newNode; return; } } else { current = current.rightChild; if (current == null) { parent.rightChild = newNode; return; } } } } }
中序遍历的java代码:
public void inOrder(Node localRoot){ if (localRoot != null) { inOrder(localRoot.leftChild); System.out.print(localRoot.iData + "|"); inOrder(localRoot.rightChild); } }
查找最大值和最小值:
找到最小值就是要找到二叉树的最左边的叶子,具体过程为从根节点出发往左子节点走,直到该节点没有了左子节点那么该节点就是最小值了,java代码:
public Node miniNum(){ Node last , current; last = current = root; while(current != null) { last = current; current = current.leftChild; } return last; }
删除!
// 找到待删除节点的后继节点 private Node getSuccessor(Node delNode){ Node successorParent = delNode; Node successor = delNode; Node current = delNode.rightChild; while (current != null) { successorParent = successor; successor = current; current = current.leftChild; } if (successor != delNode.rightChild) { successorParent.leftChild = successor.rightChild; successor.rightChild = delNode.rightChild; } return successor; } public boolean delete(Node node){ if (node != null) { Node current = root; Node parent = root; boolean isLeftChild = true; // 找到待删除节点 while(current != node){ parent = current; if (node.iData < current.iData) { isLeftChild = true; current = current.leftChild; } else { isLeftChild = false; current = current.rightChild; } if (current == null) return false; } // 如果待删除节点无子节点 if (current.leftChild == null && current.rightChild == null) { if (current == root) root = null; else if (isLeftChild) parent.leftChild = null; else parent.rightChild = null; // 如果待删除节点有左子节点 } else if (current.rightChild == null) { if (current == root) root = root.leftChild; else if (isLeftChild) parent.leftChild = current.leftChild; else parent.rightChild = current.leftChild; // 如果待删除节点有右子节点 } else if (current.leftChild == null) { if (current == root) root = root.rightChild; else if (isLeftChild) parent.leftChild = current.rightChild; else { parent.rightChild = current.rightChild; } // 如果待删除节点有两个节点 } else { Node successor = getSuccessor(current); if (current == root) root = successor; else if (isLeftChild) parent.leftChild = successor; else parent.rightChild = successor; successor.leftChild = current.leftChild; } } return true; }