树通常结合了另外两种数据结构的优点:一种是有序数组,另一种是链表。在树中查找数据项的速度和在有序数组中查找一样快,并且插入数据项和删除数据项的速度也和链表一样。
1、二叉搜索树:一个节点的左子节点的关键字值小于这个节点,右子节点的关键字值大于或等于这个父节点。
// to run this program: C>java TreeApp import java.io.*; import java.util.*; class TreeNode { public int data; public TreeNode leftChild; public TreeNode rightChild; public TreeNode parent; public TreeNode(int data,TreeNode leftChild ,TreeNode rightChild,TreeNode parent) { this.data = data; this.leftChild = leftChild; this.rightChild = rightChild; this.parent = parent; } public int getData() { return this.data; } } class BinarySearchTree { private TreeNode root; public BinarySearchTree() { root = null; } public TreeNode getRoot() { return this.root; } //判断二叉查找树是否为空; public boolean isEmpty() { if(root==null) return true; else return false; } //在二叉查找树中查询给定关键字 public TreeNode find(int key) { TreeNode currentNode = root; while(currentNode!=null && currentNode.data!=key) { if(key < currentNode.data) currentNode = currentNode.leftChild; else currentNode = currentNode.rightChild; } return currentNode; } //查找二叉查找树中的最小关键字节点 public TreeNode minNode(TreeNode node) { if(node ==null) return null; TreeNode currentNode = node; while(currentNode.leftChild!=null) currentNode = currentNode.leftChild; return currentNode; } //查找二叉查找树中的最大关键字节点 public TreeNode maxNode(TreeNode node) { if(node ==null) return null; TreeNode currentNode = node; while(currentNode.rightChild!=null) currentNode = currentNode.rightChild; return currentNode; } //前序遍历 public void preOrder(TreeNode node) { if(node != null) { System.out.print(node.data + " "); preOrder(node.leftChild); preOrder(node.rightChild); } } //中序遍历 public void inOrder(TreeNode node) { if(node != null) { inOrder(node.leftChild); System.out.print(node.data + " "); inOrder(node.rightChild); } } //中序遍历,每个节点显示前驱和后继节点 public void testNode(TreeNode node) { if(node != null) { testNode(node.leftChild); TreeNode node1 = getPrecessor(node); TreeNode node2 = getSuccessor(node); System.out.print("本节点:"+node.getData()); if(node1 != null) System.out.print(" 前驱节点:"+node1.getData()); else System.out.print(" 没有前驱节点"); if(node2 != null) System.out.print(" 后继节点:"+node2.getData()); else System.out.print(" 没有后继节点"); System.out.println(""); testNode(node.rightChild); } } //后序遍历 public void postOrder(TreeNode node) { if(node != null) { postOrder(node.leftChild); postOrder(node.rightChild); System.out.print(node.data + " "); } } //插入节点 public void insert(int key) { TreeNode newNode = new TreeNode(key,null,null,null); if(root == null) { root = newNode; return; } TreeNode currentNode = root; TreeNode parentNode = null; while(currentNode != null) { parentNode = currentNode; if(key < currentNode.data) currentNode = currentNode.leftChild; else if(key > currentNode.data) currentNode = currentNode.rightChild; else //树中已存在匹配给定关键字的节点,则什么都不做直接返回 return; } //parentNode就是最后一个非空的节点 if(key < parentNode.data) { parentNode.leftChild = newNode; newNode.parent = parentNode; } else { parentNode.rightChild = newNode; newNode.parent = parentNode; } } //删除节点 public boolean delete(TreeNode node) { TreeNode currentNode = node; if(currentNode == null) return false;
//key节点没有孩子 if(currentNode.leftChild == null && currentNode.rightChild == null) { //key节点是根节点 if(currentNode == root) { root = null; return true; } //key节点是其父节点的左孩子 TreeNode parentNode = currentNode.parent; if(currentNode ==parentNode.leftChild) parentNode.leftChild = null; //key节点是其父节点的右孩子 else parentNode.rightChild = null; return true; } //key节点只有左孩子 if(currentNode.leftChild != null && currentNode.rightChild == null) { //key节点是根节点 if(currentNode == root) { root = currentNode.leftChild; root.parent=null; return true; } //key节点是其父节点的左孩子 TreeNode parentNode = currentNode.parent; if(currentNode == parentNode.leftChild) { parentNode.leftChild = currentNode.leftChild; currentNode.leftChild.parent = parentNode; } //key节点是其父节点的右孩子 else { parentNode.rightChild = currentNode.leftChild; currentNode.leftChild.parent = parentNode; } return true; } //key节点只有右孩子 if(currentNode.leftChild == null && currentNode.rightChild != null) { //key节点是根节点 if(currentNode == root) { root = currentNode.rightChild; root.parent = null; return true; } //key节点是其父节点的左孩子 TreeNode parentNode = currentNode.parent; if(currentNode == currentNode.parent.leftChild) { parentNode.leftChild = currentNode.rightChild; currentNode.rightChild.parent = parentNode; } //key节点是其父节点的右孩子 else { parentNode.rightChild = currentNode.rightChild; currentNode.rightChild.parent = parentNode; } return true; } //key节点左右孩子都有 if(currentNode.leftChild != null && currentNode.rightChild != null) { TreeNode successorNode = getSuccessor(currentNode); delete(successorNode); currentNode.data = successorNode.data; } return true; } //查找给定节点在中序遍历下的后继节点 private TreeNode getSuccessor(TreeNode node) { //子树为空 if(node == null) return null; //若该节点的右子树不为空,则其后继节点就是右子树中的最小关键字节点 if(node.rightChild!=null) return minNode(node.rightChild); //若该节点右子树为空,则向上一直找它的祖先,直到一个祖先是另一个祖先的左孩子 TreeNode parentNode = node.parent; while(parentNode!=null && node==parentNode.rightChild) { node = parentNode; parentNode = parentNode.parent; } return parentNode; } //查找给定节点在中序遍历下的前驱节点 public TreeNode getPrecessor(TreeNode node) { //子树为空 if(node == null) return null; //若该节点的左子树不为空,则其后继节点就是右子树中的最大关键字节点 if(node.leftChild!=null) return maxNode(node.leftChild); //若该节点左子树为空,则向上一直找它的祖先,直到一个祖先是另一个祖先的右孩子 TreeNode parentNode = node.parent; while(parentNode!=null && node == parentNode.leftChild) { node = parentNode; parentNode = parentNode.parent; } return parentNode; } } class BinarySearchTreeApp { public static void main(String[] args) throws IOException { BinarySearchTree bst = new BinarySearchTree(); System.out.print("二叉查找树是否为空?"); if(bst.isEmpty()==true) System.out.println("是"); else System.out.println("否"); int[] keys = new int[] { 15, 6, 18, 3, 7, 13, 20, 2, 9, 4 }; // int[] keys = new int[] { }; for(int key : keys) bst.insert(key); System.out.print("二叉查找树是否为空?"); if(bst.isEmpty()==true) System.out.println("是"); else System.out.println("否"); System.out.print("根节点关键字: " ); if(bst.getRoot()!=null) System.out.println(bst.getRoot().getData());
System.out.print("最小关键字: "); if(bst.getRoot()!=null) System.out.println( bst.minNode(bst.getRoot()).getData()); System.out.print("最大关键字: "); if(bst.getRoot()!=null) System.out.println( + bst.maxNode(bst.getRoot()).getData()); System.out.print("前序遍历: " ); bst.preOrder(bst.getRoot()); System.out.println(""); System.out.print("中序遍历: " ); bst.inOrder(bst.getRoot()); System.out.println(""); System.out.print("后序遍历: " ); bst.postOrder(bst.getRoot()); System.out.println(""); bst.testNode(bst.getRoot()); //删除13这个节点 TreeNode node = bst.find(13); bst.delete(node); node = null; System.out.println(""); System.out.print("中序遍历: " ); bst.inOrder(bst.getRoot()); System.out.println(""); bst.testNode(bst.getRoot()); }
}
二叉查找树是否为空?是
二叉查找树是否为空?否
根节点关键字: 15
最小关键字: 2
最大关键字: 20
前序遍历: 15 6 3 2 4 7 13 9 18 20
中序遍历: 2 3 4 6 7 9 13 15 18 20
后序遍历: 2 4 3 9 13 7 6 20 18 15
本节点:2 没有前驱节点 后继节点:3
本节点:3 前驱节点:2 后继节点:4
本节点:4 前驱节点:3 后继节点:6
本节点:6 前驱节点:4 后继节点:7
本节点:7 前驱节点:6 后继节点:9
本节点:9 前驱节点:7 后继节点:13
本节点:13 前驱节点:9 后继节点:15
本节点:15 前驱节点:13 后继节点:18
本节点:18 前驱节点:15 后继节点:20
本节点:20 前驱节点:18 没有后继节点
中序遍历: 2 3 4 6 7 9 15 18 20
本节点:2 没有前驱节点 后继节点:3
本节点:3 前驱节点:2 后继节点:4
本节点:4 前驱节点:3 后继节点:6
本节点:6 前驱节点:4 后继节点:7
本节点:7 前驱节点:6 后继节点:9
本节点:9 前驱节点:7 后继节点:15
本节点:15 前驱节点:9 后继节点:18
本节点:18 前驱节点:15 后继节点:20
本节点:20 前驱节点:18 没有后继节点