用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