用DSW算法一次性平衡二叉查找树

参考原文(原文作者:Timothy J. Rolfe ):http://penguin.ewu.edu/~trolfe/DSWpaper/

DSW算法用于平衡BST(二叉查找树),而且平衡后的二叉树是一颗完全二叉树(complete binary tree-即叶子节点顶多位于最后两层,而且从左到右排列)。该算法的优点是:无须开辟额外的空间用于存储节点,时间复杂度线性O(n)。该算法分两个阶 段进行:首先将任意一颗二叉树通过一序列右旋转(right rotations)转换成一个单链结构(称作vine,即每个非叶子节点只有右孩子,没有左孩子);然后在第二阶段中对单链结构通过几个批次左旋转 (left rotations)生成一颗完全二叉树。为了生成完全二叉树,在第二阶段的左旋转中,首先只将一部分节点左旋转(这算是第一个批次左旋转),然后依次对 剩下的单链节点做多批次左旋转(每个批次的左旋转所针对的节点位于剩下的vine上依次相隔的一个节点),直到某个批次的左旋转次数不大于1。

实现代码:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
 * DSW(Day-Stout-Warren) algorithm to balance a binary search tree
 * 
 * @author ljs
 * see also: http://penguin.ewu.edu/~trolfe/DSWpaper/
 */
public class DSW_BST {
	static class Node{
		int val;
		Node left;
		Node right;
		public Node(int val){
			this.val = val;
		}
		public String toString(){
			return String.valueOf(val);
		}
	}
	//the number of nodes in this tree
	private int n;
	
	//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

posted @ 2011-06-05 22:29  ljsspace  阅读(498)  评论(0编辑  收藏  举报