数据结构与算法
Binary Search Tree
概念
二叉搜索树
由于其左子树总是小于当前节点key值又小于右子树,所以这种数据结构在搜索中经常用到。
但值得注意的是,这种树如果分布地很均衡的话搜索的时间复杂度为O(log2n),但如果输入的数据流恰好为顺序表的话,这棵树的搜索时间复杂度和链表一样O(n)。
代码实现:
package ElevenWeek;
import java.util.*;
public class BSTNode {//Binary Search Node class
private class Node{//子类
public Node left;
public Node right;
public int key;
public Node(int x){this.key=x;}
}
public Node root;
public int size;
public BSTNode(){
this.root=null;
this.size=0;
}
public boolean isEmpty(){ return size==0;}
public void add(int x){ root=add(root, x);}
private Node add(Node node, int x){
if(node==null){
size++;
return new Node(x);
}
if(node.key > x) node.left=add(node.left, x);
else if(node.key < x) node.right=add(node.right, x);
return node;
}
public boolean contains(int x){ return contains(root, x);}
private boolean contains(Node node, int x){
if(node==null) return false;
if(node.key==x) return true;
else if(node.key>x) return contains(node.left, x);
else return contains(node.right, x);
}
private void visit(Node node){System.out.print(node.key+", ");}
/**
* 以下为先序遍历,中序遍历,后序遍历,层序遍历的非递归实现
*
* 其中Stack类我在前期中有写过
*/
public void preTravel() throws Exception{ preTravel(root);}
private void preTravel(Node node) throws Exception{
if(node==null) return;
Stack s=new Stack(20);
s.push(node);
Node temp;
while(!s.isEmpty()){
temp=(Node) s.pop();
visit(temp);
if(temp.right!=null) s.push(temp.right);
if(temp.left!=null) s.push(temp.left);
}
System.out.println();
}
public void midTravel() throws Exception{ midTravel(root);}
private void midTravel(Node node) throws Exception{
if(node==null) return;
Stack s=new Stack(20);
while(true){
while(node!=null){
s.push(node);
node=node.left;
}
if(s.isEmpty()) break;
node=(Node) s.pop();
visit(node);
node=node.right;
}
System.out.println();
}
public void bacTravel() throws Exception{ bacTravel(root);}
private void bacTravel(Node node) throws Exception {
if(node==null) return;
Node curnode=node;
Node prenode=null;
Stack s=new Stack(20);
while(curnode!=null){
s.push(curnode);
curnode=curnode.left;
}
while(!s.isEmpty()){
curnode=(Node) s.pop();
if(curnode.right==null||curnode.right==prenode){
visit(curnode);
prenode=curnode;
continue;
}
s.push(curnode);
curnode=curnode.right;
while(curnode!=null){
s.push(curnode);
curnode=curnode.left;
}
}
System.out.println();
}
public void levTravel(){ levTravel(root);}
private void levTravel(Node node){
if(node==null) return;
Queue<Node> q=new LinkedList<Node>();
q.offer(node);
while(!q.isEmpty()){
node=q.poll();
visit(node);
if(node.left!=null) q.offer(node.left);
if(node.right!=null) q.offer(node.right);
}
System.out.println();
}
public int getMin() throws Exception{
if(size==0) throw new Exception("BST is empty.");
return getMin(root).key;
}
private Node getMin(Node node){
while(node.left!=null){
node=node.left;
}
return node;
}
public int getMax() throws Exception{
if(size==0) throw new Exception("BST is empty.");
return getMax(root).key;
}
private Node getMax(Node node){
while(node.right!=null) node=node.right;
return node;
}
public int delMin() throws Exception{
int min=getMin();
root=delMin(root);
return min;
}
private Node delMin(Node node){
if(node.left==null) return null;
while(node.left.left!=null) node=node.left;
node.left=null;
return node;
}
public int delMax() throws Exception{
int max=getMax();
root=delMax(root);
return max;
}
private Node delMax(Node node){
if(node.right==null) return null;
while(node.right.right!=null) node=node.right;
node.right=null;
return node;
}
public void remove(int x){ root=remove(root, x);}
private Node remove(Node node, int x){
if(node==null) return null;
if(node.key>x){
node.left=remove(node.left, x);
return node;
}
else if(node.key<x){
node.right=remove(node.right, x);
return node;
}
else{
if(node.left==null){
Node temp=node.right;
node.right=null;
size--;
return temp;
}
if(node.right==null){
Node temp=node.left;
node.left=null;
size--;
return temp;
}
// 待删除节点左右子树均不为空的情况
// 查找待删除节点的后继节点
// 用后继节点替换当前待删除节点
Node prenode=getMin(node.right);
prenode.right=delMin(node.right);
prenode.left=node.left;
node.left=null;
node.right=null;
return prenode;
}
}
public String toString(){
String res="";
generateString(root, 0, res);
return res;
}
private void generateString(Node node, int depth, String res){
if(node==null){
res+=generate_nbsp(depth)+"null\n";
return;
}
res+=generate_nbsp(depth)+node.key+"\n";
generateString(node.left, depth+1, res);
generateString(node.right, depth+1, res);
}
private String generate_nbsp(int depth){
String res="";
for(int i=0;i<depth;i++)
res+="--";
return res;
}
}
Test:
package ElevenWeek;
public class BSTree_Test {
public static void main(String args[]) throws Exception{
int[] nums={5,3,6,4,8,2};
BSTNode bs=new BSTNode();
for(int i=0;i<nums.length;i++)
bs.add(nums[i]);
System.out.println("pre in the first time: ");
bs.preTravel();
System.out.println("mid");
bs.midTravel();
System.out.println("bac");
bs.bacTravel();
System.out.println();
bs.remove(bs.getMax());
System.out.println("pre");
bs.preTravel();
System.out.println("mid");
bs.midTravel();
System.out.println("bac");
bs.bacTravel();
System.out.println();
bs.add(8);
bs.remove(3);
System.out.println("pre");
bs.preTravel();
System.out.println("mid");
bs.midTravel();
System.out.println("bac");
bs.bacTravel();
System.out.println();
}
}
结果:
pre in the first time:
5, 3, 2, 4, 6, 8,
mid
2, 3, 4, 5, 6, 8,
bac
2, 4, 3, 8, 6, 5,pre
5, 3, 2, 4, 6,
mid
2, 3, 4, 5, 6,
bac
2, 4, 3, 6, 5,pre
5, 4, 2, 6, 8,
mid
2, 4, 5, 6, 8,
bac
2, 4, 8, 6, 5,
AVT Tree
概念:
平衡二叉树
考虑到Binary Search Tree对于输入数据顺序的高度依赖,AVL Tree用于自动平衡二叉树,以确保每次搜索的时间复杂度总为O(log2n)。
代码实现:
package ElevenWeek;
import java.util.*;
public class AVLNode {
private class Node{
public int key;
public Node left;
public Node right;
public int height;
public Node(int x, Node left, Node right){
this.key=x;
this.left=left;
this.right=right;
}
public Node(int x){
this.key=x;
this.left=null;
this.right=null;
}
}
private static final int allow_balance=1;
private Node root=null;
public AVLNode(){root=null;}
public boolean isEmpty(){return root==null;}
public void insert(int x){root=insert(root, x);}
private Node insert(Node node, int x) {
// TODO Auto-generated method stub
if(node==null) return new Node(x);
if(x > node.key) node.right=insert(node.right, x);
else if(x < node.key) node.left=insert(node.left, x);
return balance(node);
}
private Node balance(Node node){
if(node==null) return node;
if(height(node.left) - height(node.right) > allow_balance){
if(height(node.left.left) >= height(node.left.right)) node = rotate_with_left(node);
else node = double_with_left(node);
}
else if(height(node.right) - height(node.left) > allow_balance){
if(height(node.right.right) >= height(node.right.left)) node=rotate_with_right(node);
else node=double_with_right(node);
}
node.height=Math.max(height(node.left), height(node.right))+1;
return node;
}
private int height(Node node){return (node==null) ? 0 : Math.max(height(node.left), height(node.right))+1;}
private Node rotate_with_left(Node node) {
Node tempnode=node.left;
node.left=tempnode.right;
tempnode.right=node;
node.height=Math.max(height(node.left), height(node.right))+1;
tempnode.height=Math.max(height(tempnode.left), height(tempnode.right))+1;
return tempnode;
}
private Node rotate_with_right(Node node){
Node tempnode=node.right;
node.right=tempnode.left;
tempnode.left=node;
node.height=Math.max(height(node.left), height(node.right))+1;
tempnode.height=Math.max(height(tempnode.left), height(tempnode.right))+1;
return tempnode;
}
private Node double_with_left(Node node){
node.left=rotate_with_right(node.left);
return rotate_with_left(node);
}
private Node double_with_right(Node node){
node.right=rotate_with_left(node.right);
return rotate_with_right(node);
}
public void remove(int x){root=remove(root, x);}
private Node remove(Node node, int x){
if(node==null) return node;
if(x < node.key) node.left=remove(node.left, x);
else if(x > node.key) node.right=remove(node.right, x);
else if(node.left!=null&&node.right!=null){
node.key=findmin(node.right).key;
node.right=remove(node.right, node.key);
}
else node = (node.left==null) ? node.right : node.left;
return balance(node);
}
public Node findmin(Node node){
if(node==null) return null;
if(node.left==null) return node;
return findmin(node.left);
}
public void levTravel(){
Queue<Node> q=new LinkedList<Node>();
q.offer(root);
Node temp;
while(!q.isEmpty()){
temp=q.poll();
visit(temp);
if(temp.left!=null) q.offer(temp.left);
if(temp.right!=null) q.offer(temp.right);
}
System.out.println();
}
public void preTravel() throws Exception{ preTravel(root);}
private void preTravel(Node node) throws Exception{
if(node==null) return;
Stack s=new Stack(20);
s.push(node);
while(!s.isEmpty()){
node=(Node) s.pop();
visit(node);
if(node.right!=null) s.push(node.right);
if(node.left!=null) s.push(node.left);
}
System.out.println();
}
public void midTravel() throws Exception{ midTravel(root);}
private void midTravel(Node node) throws Exception{
if(node==null) return;
Stack s=new Stack(20);
while(true){
while(node!=null){
s.push(node);
node=node.left;
}
if(s.isEmpty()) break;
node=(Node) s.pop();
visit(node);
node=node.right;
}
System.out.println();
}
public void bacTravel() throws Exception{ bacTravel(root);}
private void bacTravel(Node node) throws Exception {
if(node==null) return;
Stack s=new Stack(20);
Node curnode=node;
Node prenode=null;
while(curnode!=null){
s.push(curnode);
curnode=curnode.left;
}
while(!s.isEmpty()){
curnode=(Node) s.pop();
if(curnode.right==null||curnode.right==prenode){
visit(curnode);
prenode=curnode;
continue;
}
s.push(curnode);
curnode=curnode.right;
while(curnode!=null){
s.push(curnode);
curnode=curnode.left;
}
}
System.out.println();
}
private void visit(Node temp) {
// TODO Auto-generated method stub
System.out.print(temp.key+", ");
}
}
Test
package ElevenWeek;
public class AVLNode_Test {
public static void main(String args[]) throws Exception{
AVLNode as=new AVLNode();
as.insert(1);
as.insert(2);
as.insert(3);
as.insert(4);
as.insert(5);
as.insert(6);
as.insert(7);
as.insert(8);
as.insert(9);
System.out.println("pre in the first time: ");
as.preTravel();
System.out.println("mid");
as.midTravel();
System.out.println("bac");
as.bacTravel();
System.out.println();
}
}
结果如下:
pre in the first time:
4, 2, 1, 3, 6, 5, 8, 7, 9,
mid
1, 2, 3, 4, 5, 6, 7, 8, 9,
bac
1, 3, 2, 5, 7, 9, 8, 6, 4,