参考原文(原文作者:Timothy J. Rolfe
):http://penguin.ewu.edu/~trolfe/DSWpaper/
DSW算法用于平衡BST(二叉查找树),而且平衡后的二叉树是一颗完全二叉树(complete binary tree-即叶子节点顶多位于最后两层,而且从左到右排列)。该算法的优点是:无须开辟额外的空间用于存储节点,时间复杂度线性O(n)。该算法分两个阶段进行:首先将任意一颗二叉树通过一序列右旋转(right rotations)转换成一个单链结构(称作vine,即每个非叶子节点只有右孩子,没有左孩子);然后在第二阶段中对单链结构通过几个批次左旋转(left rotations)生成一颗完全二叉树。为了生成完全二叉树,在第二阶段的左旋转中,首先只将一部分节点左旋转(这算是第一个批次左旋转),然后依次对剩下的单链节点做多批次左旋转(每个批次的左旋转所针对的节点位于剩下的vine上依次相隔的一个节点),直到某个批次的左旋转次数不大于1。
实现代码:
//phase one: right rotate the input tree into a vine
//return the root of the elongated tree; and compute the nodes count
private Node createVine(Node root){
Node pseudoRoot = new Node(Integer.MIN_VALUE);
Node grandpar = pseudoRoot;
Node tmp = root;
int nodeCnt = 0;
while(tmp != null){
if(tmp.left != null){
//right rotation for node tmp.left
Node child = tmp.left;
//postpone grandpar.right update until tmp.left is null
//grandpar.right = child;
tmp.left = child.right;
child.right = tmp;
tmp = child;
}else{
grandpar.right = tmp;
//move down
grandpar = tmp;
tmp = tmp.right;
nodeCnt++;
}
}
root = pseudoRoot.right;
n = nodeCnt;
return root;
}
//phase two: balance the vine into a complete BST
//return the new root
private Node createCompleteBST(Node root,int n){
//caculate m = 2^log(n+1) - 1;
int tmp = n + 1;
int m = 1;
tmp>>=1;
while(tmp != 0){
m<<=1;
tmp>>=1;
}
m--;
int leftRotates = n - m;
root = leftRotate(root,leftRotates);
while(m>1){
m>>=1; //m = m/2
root = leftRotate(root,m);
}
return root;
}
//return the new root after a number of left rotations
private Node leftRotate(Node root,int leftRotates){
Node pseudoRoot = new Node(Integer.MIN_VALUE);
Node grandpar = pseudoRoot;
Node tmp = root;
int rotations = 1;
while(tmp != null && tmp.right != null && rotations<=leftRotates){
//left rotate for node tmp.right
Node child = tmp.right;
grandpar.right = child;
tmp.right = child.left;
child.left = tmp;
tmp = child.right;
grandpar = child;
rotations++;
}
return pseudoRoot.right;
}
//return the new root
public Node dswBalance(Node root){
root = createVine(root);
n = this.getNumberOfNodes();
root = createCompleteBST(root,n);
return root;
}
public int getNumberOfNodes() {
return n;
}
//utility method for test purpose
public static void recursiveInOrderTraverse(Node root){
if(root == null)return;
recursiveInOrderTraverse(root.left);
System.out.format(" %d", root.val);
recursiveInOrderTraverse(root.right);
}
//utility method for test purpose
public static void levelTraverseCompleteBST(Node root,int n){
LinkedList<Node> queue = new LinkedList<Node>();
List<List<Node>> nodesList = new ArrayList<List<Node>>();
queue.add(root);
int level=0;
int levelNodes = 1;
int nextLevelNodes = 0;
//System.out.format("%nLevel %d:",level);
List<Node> levelNodesList = new ArrayList<Node>();
while(!queue.isEmpty()) {
Node node = queue.remove();
if(levelNodes==0){
//save the prev. level's nodes list
nodesList.add(levelNodesList);
levelNodesList = new ArrayList<Node>();
level++;
//System.out.format("%nLevel %d:",level);
levelNodes = nextLevelNodes;
nextLevelNodes = 0;
}
levelNodesList.add(node);
//System.out.format(" %d", node.val);
if(node.left != null){
queue.add(node.left);
nextLevelNodes++;
}
if(node.right != null) {
queue.add(node.right);
nextLevelNodes++;
}
levelNodes--;
}
//save the last level's nodes list
nodesList.add(levelNodesList);
int maxLevel = nodesList.size()-1; //==level
//expected max level for a complete binary tree = ceiling(log(n+1) - 1)
int expectedMaxLevel = (int)Math.ceil(Math.log1p(n) / Math.log(2)) - 1;
System.out.format("%n[expected max level: %d; real max level: %d]%n", expectedMaxLevel,maxLevel);
//Note: expected max columns: 2^(level+1) - 1
int cols = 1;
for(int i=0;i<=maxLevel;i++){
cols <<= 1;
}
cols--;
Node[][] tree = new Node[maxLevel+1][cols];
//load the tree into an array for later display
for(int currLevel=0;currLevel<=maxLevel;currLevel++){
levelNodesList = nodesList.get(currLevel);
//Note: the column for this level's j-th element: 2^(maxLevel-level)*(2*j+1) - 1
int tmp = maxLevel-currLevel;
int coeff = 1;
for(int i=0;i<tmp;i++){
coeff <<= 1;
}
for(int j=0;j<levelNodesList.size();j++){
int col = coeff*(2*j + 1) - 1;
tree[currLevel][col] = levelNodesList.get(j);
}
}
//display the binary search tree
for(int i=0;i<=maxLevel;i++){
for(int j=0;j<cols;j++){
Node node = tree[i][j];
if(node == null)
System.out.format(" ");
else
System.out.format("%2d",node.val);
}
System.out.format("%n");
}
}
public static void main(String[] args) {
/*
13
10 25
2 12 20 35
29
30
31
32
33
*/
System.out.format("Test case 1:%n");
Node n13 = new Node(13);
Node n10 = new Node(10);
Node n25 = new Node(25);
Node n2 = new Node(2);
Node n12 = new Node(12);
Node n20 = new Node(20);
Node n35 = new Node(35);
Node n29 = new Node(29);
Node n30 = new Node(30);
Node n31 = new Node(31);
Node n32 = new Node(32);
Node n33 = new Node(33);
n13.left = n10;
n13.right = n25;
n10.left = n2;
n10.right = n12;
n25.left = n20;
n25.right = n35;
n35.left = n29;
n29.right = n30;
n30.right = n31;
n31.right = n32;
n32.right = n33;
Node root = n13;
System.out.format("%nBefore being balanced, in-order BST:%n");
DSW_BST.recursiveInOrderTraverse(root);
DSW_BST dsw = new DSW_BST();
root = dsw.dswBalance(root);
System.out.format("%nAfter being balanced, in-order BST:%n");
DSW_BST.recursiveInOrderTraverse(root);
System.out.format("%n%n%nAfter being balanced, it is now a complete BST:");
DSW_BST.levelTraverseCompleteBST(root,dsw.getNumberOfNodes());
System.out.format("************************************");
System.out.format("%nTest case 2:%n");
Node nn5 = new Node(5);
Node nn10 = new Node(10);
Node nn20 = new Node(20);
Node nn15 = new Node(15);
Node nn30 = new Node(30);
Node nn25 = new Node(25);
Node nn40 = new Node(40);
Node nn23 = new Node(23);
Node nn28 = new Node(28);
nn5.right = nn10;
nn10.right = nn20;
nn20.left = nn15;
nn20.right = nn30;
nn30.left = nn25;
nn30.right = nn40;
nn25.left = nn23;
nn25.right = nn28;
root = nn5;
System.out.format("%nBefore being balanced, in-order BST:%n");
DSW_BST.recursiveInOrderTraverse(root);
dsw = new DSW_BST();
root = dsw.dswBalance(root);
System.out.format("%nAfter being balanced, in-order BST:%n");
DSW_BST.recursiveInOrderTraverse(root);
System.out.format("%n%n%nAfter being balanced, it is now a complete BST:");
DSW_BST.levelTraverseCompleteBST(root,dsw.getNumberOfNodes());
}
}
测试
Test case 1:
Before being balanced, in-order BST:
2 10 12 13 20 25 29 30 31 32 33 35
After being balanced, in-order BST:
2 10 12 13 20 25 29 30 31 32 33 35
After being balanced, it is now a complete BST:
[expected max level: 3; real max level: 3]
30
13 33
10 25 32 35
2 12 20 29 31
************************************
Test case 2:
Before being balanced, in-order BST:
5 10 15 20 23 25 28 30 40
After being balanced, in-order BST:
5 10 15 20 23 25 28 30 40
After being balanced, it is now a complete BST:
[expected max level: 3; real max level: 3]
25
20 30
10 23 28 40
5 15