链表能够很方便的存储数据,但是,数据的组织只能是线性的,不能有层次的组织数据,且查找元素需要线性查找,复杂度O(n)。
它的特点是:
(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
即:对于任何一个子树,左子树所有结点值小于根结点,右子树所有结点值小于根结点。
查找、插入删除的最优复杂度为log(n)
在极端情况下,如果按照排序好的顺序给二叉查找树数据,那么树会退化成一个链表,复杂的同链表一样。
那么:
测试代码:
BST tree = new BST();
Random rand = new Random();
double totalTime = 0;
for (int i=0;i<=3000000; i++)
tree.Insert(rand.nextInt(10000000));
//tree.tranformIntoPerfectTree();
for (int i=0;i<100;i++) {
long time = System.currentTimeMillis();
tree.Contains(new BSTNode(rand.nextInt(10000000)));
totalTime += System.currentTimeMillis()-time;
}
System.out.println("在1000万数据中查找1000次 平均耗时: "+totalTime/100);
测试结果:
随机生成300万个数据(太多内存受不了),加入二叉查找树,测试100次,平均时长为:67.63ms
即整个树只有最下面两层不满,其他层均满。
当存入一定数据之后,按照一定规则将二叉查找树拉伸成链表,然后重新组织数据,使数据接近完全二叉树。以下代码使用这种方法重建二叉搜索树。因为这种方法是所有数据一起重建一棵树,所以又叫“全局重建”
存入一个数据之后,该数据并非影响整棵树的平衡,因为数据总是插在最下方。所以可以只进行局部调整。
这种方法又叫“局部重建”(这个方法将在下一篇博文实现)
来看看:
测试代码及测试条件同上,加入了平衡函数tranformIntoPerfectTree()
改变不大,这是因为我们随机生成数据,如果数据有一定规律,那么效率会提高很多。
对于二叉查找树,有如下:
root:树的根,作为树的入口
size:数的大小,不必要,可以使用时遍历求得
Insert:插入
remove:删除,并返回被删除的数据
isEmpty:判断树是否为空
Contains:是否包含某数据
rotateRight/rotateLeft:将树进行旋转,这是DSW方法中使用的子方法
transformIntoBackbone:DSW方法的第一步,把树转化成链表
tranformIntoPerfectTree:使用DSW方法全局重构二叉树
dfs:深度优先搜索,返回搜索路径,二叉搜索树的中序遍历是数据的排序,使用递归,消耗资源
bfs:广度优先遍历,使用内存较大
下面是二叉查找树的代码:
package BST;
import java.util.ArrayList;
import java.util.Random;
public class BST {
int size;
BSTNode root;
public BST() {
root = null;
size = 0;
}
public boolean isEmpty() {
return root == null;
}
public void Insert(int value) {
Insert(new BSTNode(value));
}
public boolean Contains(BSTNode node) {
return Contains(node, root);
}
public boolean Remove(BSTNode node) {
BSTNode[] fatherNode = new BSTNode[1];
BSTNode toDelete = Search(node, fatherNode);
if (toDelete == null)
return false;
if (toDelete.left == null && toDelete.right == null)
return false;
if (toDelete.left == null && toDelete.right != null) {
fatherNode[0].right = toDelete.right;
}
else if (toDelete.left != null && toDelete.right == null) {
fatherNode[0].left = toDelete.left;
}
else if (toDelete.left != null && toDelete.right != null) {
if(toDelete.right.right != null) {
toDelete.right.right.left = toDelete.right.left;
toDelete.right.left = toDelete.left;
}
else {
if(toDelete.right.left != null)
Insert(toDelete.right.left);
toDelete.right.left = toDelete.left;
}
if(root != fatherNode[0])
if (BSTNode.equals(fatherNode[0].right, toDelete))
fatherNode[0].right = toDelete.right;
else
fatherNode[0].left = toDelete.right;
else {
root = toDelete.right;
}
}
size--;
return true;
}
public void tranformIntoPerfectTree() {
if (isEmpty() || size == 1) return ;
transformIntoBackbone(); //转化为骨架结构(向右)
//System.out.println("________________________________________");
//printSelf();
int n = this.size;
int m = (int) Math.pow(2, Math.floor(Math.log10(n+1)/Math.log10(2))) - 1;
int cnt = n-m;
if(cnt>0) {
rotateLeft(null, root);
cnt--;
}
//System.out.println("m:"+m+" cnt: "+cnt);
//printSelf();
//System.exit(0);
BSTNode grand = root;
BSTNode now = root.right;
if(cnt>0)
while(true) {
//System.out.println("___________In While_____________________________");
//printSelf();
rotateLeft(grand, now);
//System.out.println("___________In While_____________________________");
//printSelf();
cnt--;
if(cnt==0) break;
grand = grand.right;
now = grand.right;
}
while(m>1) {
m=m/2;
int tmp = m;
if (tmp>=1) {
rotateLeft(null, root);
tmp--;
}
grand = root;
now = root.right;
//System.out.println("Pre Rotating: " + root.value + " " + root.right.value);
while(tmp>0) {
rotateLeft(grand, now);
tmp--;
if(tmp==0) break;
grand = grand.right;
now = grand.right;
}
}
}
public void transformIntoBackbone() {
BSTNode grand = null;
BSTNode now = root;
while(now != null) {
//System.out.println((grand==null?"null":grand.value) + " " + now.value);
if (now.left != null) {
rotateRight(grand, now);
if(grand!=null)
now = grand.right;
else
now = root;
//System.out.println("exce 1");
//System.out.println("___________In While_____________________________");
//printSelf();
}
else {
grand = now;
now = now.right;
//System.out.println("exce 2");
}
}
}
public void transformIntoBackboneLeft() {
BSTNode grand = null;
BSTNode now = root;
while(now != null) {
if (now.right != null) {
rotateLeft(grand, now);
if(grand!=null)
now = grand.left;
else
now = root;
}
else {
grand = now;
now = now.left;
}
}
}
private void rotateRight(BSTNode grand, BSTNode node) {
if (node.left == null) return ;
BSTNode nodeLeft = node.left,
nodeRight = node.right,
child = node.left,
childLeft = node.left.left,
chileRight = node.left.right;
node.left = chileRight;
child.right = node;
if(grand == null) {
root = child;
}
else {
grand.right = child;
}
}
private void rotateLeft(BSTNode grand, BSTNode node) {
if (node == null || node.right == null) return ;
BSTNode nodeLeft = node.left,
nodeRight = node.right,
child = node.right,
childLeft = node.right.left,
chileRight = node.right.right;
node.right = childLeft;
child.left = node;
if(grand == null) {
root = child;
}
else {
grand.right = child;
}
}
private BSTNode Search(BSTNode node, BSTNode[] fatherNode) {
if(isEmpty())
return null;
fatherNode[0] = root;
BSTNode search = root;
while(true) {
if(search == null) return null;
if (BSTNode.equals(search, node)) {return search;}
fatherNode[0] = search;
if (node.value < search.value)
search = search.left;
else
search = search.right;
}
}
private void Insert(BSTNode node) {
//System.out.print("Value: " + node.value + " ");
if (isEmpty()) {
root = node;
size = 1;
return ;
}
BSTNode search = root;
while(true) {
//System.out.print("node value: "+ search.value + " ");
if (node.value < search.value)
if (search.left == null) {
search.left = node;
//System.out.println("add to left ");
break;
}
else {
search = search.left;
//System.out.println("add to left ");
}
else
if (search.right == null) {
search.right = node;
//System.out.println("add to right ");
break;
}
else {
search = search.right;
//System.out.println("add to right ");
}
}
size++;
}
private boolean Contains(BSTNode targetNode, BSTNode nowNode) {
if (isEmpty())
return false;
if (nowNode == null)
return false;
if (BSTNode.equals(targetNode, nowNode))
return true;
return Contains(targetNode, nowNode.left) || Contains(targetNode, nowNode.right);
}
public void dfs(int[] result, int[] cnt, BSTNode node) {
if (isEmpty())
return ;
//System.out.println("To Node:" + node.value);
if (node.left != null) {
//System.out.print("L"+node.value+" ");
dfs(result, cnt, node.left);
}
result[cnt[0]++] = node.value;
if (node.right != null) {
//System.out.print("R"+node.value+" ");
dfs(result, cnt, node.right);
}
return ;
}
public void bfs(int[] result, int[] cnt) {
if (isEmpty())
return ;
ArrayList list = new ArrayList();
list.add(root);
while(!list.isEmpty()) {
BSTNode now = list.remove(0);
if (now.left != null)
list.add(now.left);
if (now.right != null)
list.add(now.right);
result[cnt[0]++] = now.value;
}
}
public void printSelf() {
int[] result = new int[this.size];
int[] cnt = new int[1];
this.dfs(result, cnt, this.root);
System.out.println("\nDFS: ");
for(int i=0; i