java实现二分搜索树

来源:互联网 发布:嘉兴菜鸟网络怎么样 编辑:程序博客网 时间:2024/05/22 16:15

二分搜索树的优势

查找元素、插入元素、删除元素的时间复杂度都是O(logn)。还可以方便的回答很多数据之间关系的问题:min,max,floor,ceil,rank,select

例如rank,求key=45在所有节点中排名第几?
答:可以通过给Node增加一个属性,记录以当前节点为根节点的二叉树的所有节点数(包括根节点),通过它可以方便得知排名

结构

二分搜索树是一棵二叉树,每个节点的键值小于右孩子大于左孩子,以左右孩子为根的子树仍为二分搜索树。

节点类

public class Node {private int key;private String value;private Node LeftChild;private Node RightChild;public Node(int key, String value) {this.key = key;this.value = value;LeftChild = null;RightChild = null;}public Node(Node node) {this.key = node.getKey();this.value = node.getValue();LeftChild = node.getLeftChild();RightChild = node.getRightChild();}public int getKey() {return key;}public void setKey(int key) {this.key = key;}public String getValue() {return value;}public void setValue(String value) {this.value = value;}public Node getLeftChild() {return LeftChild;}public void setLeftChild(Node leftChild) {LeftChild = leftChild;}public Node getRightChild() {return RightChild;}public void setRightChild(Node rightChild) {RightChild = rightChild;}}

二分搜索树类

public class Two_SearchTree {private Node RootNode;       //根节点private int count;          //节点数public Two_SearchTree() {RootNode = null;this.count = 0;}public int size(){return count;}public boolean isEmpty(){return count==0;}public boolean contain(int key){return contain(RootNode,key);}public void insert(int key,String value){RootNode=insert(RootNode,key,value);}public String search(int key){return search(RootNode,key);}public void preOrder(){preOrder(RootNode);}public void inOrder(){inOrder(RootNode);}public void postOrder(){postOrder(RootNode);}//层序遍历public void levelOrder(){Queue<Node> queue=new LinkedList<Node>();    //通过LinkedList来实现队列queue.offer(RootNode);     //头元素入队while(!queue.isEmpty()){Node node=queue.peek();     queue.poll();      //头元素出队列System.out.println(node.getKey());if(node.getLeftChild()!=null){   //左孩子不为空,则左孩子入队queue.offer(node.getLeftChild());}if(node.getRightChild()!=null){  //右孩子不为空,则右孩子入队queue.offer(node.getRightChild());}}}//寻找最小的键值public int minimum(){assert(count!=0);Node minNode=minimum(RootNode);return minNode.getKey();}//返回最大的键值public int maximum(){assert(count!=0);Node maxNode=maximum(RootNode);return maxNode.getKey();}//删除最小键值的节点public void removeMin(){if(RootNode!=null){RootNode=removeMin(RootNode);}}//删除最大键值的节点public void removeMax(){if(RootNode!=null){RootNode=removeMax(RootNode);}}//删除键值为key的节点public void remove(int key){RootNode=remove(RootNode,key);}//向以RootNode为根的二叉搜索树中插入节点(key,value)//返回插入新节点后的二叉搜索树的根private Node insert(Node RootNode,int key,String value){if(RootNode==null){         //这是没有左孩子或右孩子的情况count++;return new Node(key,value);}if(key==RootNode.getKey()){RootNode.setValue(value);}else if(key<RootNode.getKey()){RootNode.setLeftChild(insert(RootNode.getLeftChild(),key,value));}else{     //key>RootNode.getKey()RootNode.setRightChild(insert(RootNode.getRightChild(),key,value));}return RootNode;}//查看以RootNode为根的二叉搜索树中是否包含键为key的节点private boolean contain(Node RootNode,int key){if(RootNode==null){      return false;}if(key==RootNode.getKey()){return true;}else if(key<RootNode.getKey()){return contain(RootNode.getLeftChild(),key);}else{return contain(RootNode.getRightChild(),key);}}//查找以RootNode为根的二叉搜索树中以key为键的valueprivate String search(Node RootNode,int key){if(RootNode==null)return null;if(key==RootNode.getKey()){return RootNode.getValue();}else if(key<RootNode.getKey()){return search(RootNode.getLeftChild(),key);}else{return search(RootNode.getRightChild(),key);}}//前序遍历private void preOrder(Node RootOrder){if(RootOrder!=null){System.out.println(RootOrder.getKey());preOrder(RootOrder.getLeftChild());preOrder(RootOrder.getRightChild());}}//中序遍历private void inOrder(Node RootNode){if(RootNode!=null){inOrder(RootNode.getLeftChild());System.out.println(RootNode.getKey());inOrder(RootNode.getRightChild());}}//后序遍历private void postOrder(Node RootNode){if(RootNode!=null){postOrder(RootNode.getLeftChild());postOrder(RootNode.getRightChild());System.out.println(RootNode.getKey());}}//返回最小键值的节点private Node minimum(Node RootNode){if(RootNode.getLeftChild()==null){return RootNode;}return minimum(RootNode.getLeftChild());}//返回最大键值的节点private Node maximum(Node RootNode){if(RootNode.getRightChild()==null){return RootNode;}return maximum(RootNode.getRightChild());}//删除以RootNode为根的二分搜索树的最小节点//返回删除节点后的新的二分搜索树的根private Node removeMin(Node node){if(node.getLeftChild()==null){Node rightNode=node.getRightChild();count--;return rightNode;}return removeMin(node.getLeftChild());}//删除以RootNode为根的二分搜索树的最大节点//返回删除节点后的新的二分搜索树的根private Node removeMax(Node node){if(node.getRightChild()==null){Node leftNode=node.getLeftChild();count--;return leftNode;}return removeMax(node.getRightChild());}//返回删除节点后新的二分搜索树的根private Node remove(Node node,int key){if(node==null)return null;if(key==node.getKey()){if(node.getLeftChild()==null){   //删除只有右孩子的节点或左右孩子都没有的节点count--;return node.getRightChild();}if(node.getRightChild()==null){  //删除只有左孩子的节点count--;return node.getLeftChild();}//node->left!=null&&node->right!=null         删除左右都有孩子的节点Node successor=new Node(minimum(node.getRightChild())); //代替被删除节点的节点count++;successor.setRightChild(removeMin(node.getRightChild()));successor.setLeftChild(node.getLeftChild());count--;return successor;}else if(key<node.getKey()){node.setLeftChild(remove(node.getLeftChild(),key));return node;}else{node.setRightChild(remove(node.getRightChild(),key));return node;}}}

二分搜索树的局限性

当将一组数据以近乎有序的顺序插入空二分搜索树中时,几乎每一个节点都是父节点的右孩子,二分搜索树近乎退化成了一个链表,相关算法时间复杂度都退化成了O(N)。因此有了平衡二叉树,不会退化成链表,如:红黑树等。
其他平衡二叉树还有:2-3树,AVL树,Splay树
还有平衡二叉树和堆的结合:Treap
还有个trie数据结构也很有意思

原创粉丝点击