AA树 - 红黑树的变种

本文深入介绍了AA树——一种红黑树的变种,旨在简化红黑树的实现并减少特殊情况的处理。文章阐述了AA树的基本概念、关键特性及其实现方式,并通过具体的Java代码示例展示了AA树的插入、删除等操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

AA树 - 红黑树的变种

作者:ljs 2011-06-15

AA树是Arne Andersson教授在他的论文"Balanced search trees made simple"中介绍的一个红黑树变种,设计的目的是减少RB树考虑的cases。AA树是一颗红黑树,但是规定红色结点不能作为任何结点的左孩子,也就是说红色结点只能作为右孩子。这样本质上跟2-3树类似(虽然后者属于B树)。另外AA树为实现方便,不再使用红黑两种颜色,而是用level标记结点。level实际上就相当于RB树中的black height,叶子结点的level等于1(反过来,level等于1的不一定是叶子结点,因为等于1的结点可能有一个红色的右孩子),红色结点使用它的父结点的level,黑色结点比它的父结点的level小1。另外,下面两种情况是禁止出现的:

1)连续两个水平方向链(horizontal link),所谓horizontal link是指一个结点跟它的右孩子结点的level相同(左孩子结点永远比它的父结点level小1)。这个规定其实相当于RB树中不能出现两个连续的红色结点。

2)向左的水平方向链(left horizontal link),也就是说一个结点最多只能出现一次向右的水平方向链。这是因为left horizontal link相当于左孩子能为红色结点,这在AA树的定义中是不允许的。

在插入和删除操作中,可能会出现上面两个禁止发生的情况,这时候就需要通过树的旋转操作来纠正。AA树中只有两个基本操作:skew和split。前者用于纠正出现向左的水平方向链,后者用于纠正出现连续两个水平方向链的情况。skew就是一个右旋转,split是一个左旋转,但两者不是互逆的。skew操作之后可能引起1)的发生(当skew之前已经有一个右孩子的level跟当前结点的level相同),这时需要配合使用split操作。split操作的特点是新的子树的根节点level增加1, 从而会在它的父结点中出现1)(当它作为父结点的左孩子)或者在它的父结点中出现2)(当它作为父结点的右孩子而且父结点跟祖父结点的level相同),这时需要通过skew和split操作纠正这两种情况。

 

 


 
由于split引起的新问题发生在parent一级局部结点,而skew引起的新问题只发生在当前局部结点,所以在实现时需要先skew,再split。

在下面的插入操作中使用递归,删除操作没有使用递归。新插入的结点level等于1。

因为AA树也是平衡BST,它的时间复杂度跟RB树一样,即O(logn),但是旋转次数相对多一些(RB树插入操作最多旋转两次,而且旋转完毕即结束rebalancing;删除操作最多旋转三次,也是旋转完毕即结束rebalancing)。

 

 

实现: (性能测试代码和结果在本段代码后面)

 

[java]  view plain copy
  1. import java.util.ArrayList;  
  2. import java.util.LinkedList;  
  3. import java.util.List;  
  4. import java.util.Stack;  
  5. /** 
  6.  *  
  7.  * @author ljs 
  8.  * 2011-06-15 
  9.  * 版权说明:可以复制,但须标明出处 
  10.  *  
  11.  */  
  12. public class AATree<T extends Comparable<T>> {  
  13.     private AANode<T> nil;  
  14.     private AANode<T> root;  
  15.       
  16.     public static class AANode<E extends Comparable<E>>{  
  17.         E key;  
  18.         AANode<E> left;  
  19.         AANode<E> right;  
  20.         int level;  
  21.           
  22.         public AANode(E key,AANode<E> left,AANode<E> right){  
  23.             this.key = key;  
  24.             this.left = left;  
  25.             this.right = right;  
  26.               
  27.             this.level  = 1;  
  28.         }  
  29.         public AANode(){      
  30.               
  31.         }  
  32.           
  33.         public String toString(){  
  34.             return String.valueOf(key + ":" + level);  
  35.         }  
  36.         public E getKey(){  
  37.             return this.key;  
  38.         }  
  39.         public E getLeftChild(){  
  40.             return this.left.key;  
  41.         }  
  42.         public E getRightChild(){  
  43.             return this.right.key;  
  44.         }  
  45.         public AANode<E> getLeft() {  
  46.             return left;  
  47.         }  
  48.         public AANode<E> getRight() {  
  49.             return right;  
  50.         }         
  51.     }  
  52.     public AATree(){  
  53.         //sentinel node  
  54.         nil = new AANode<T>();  
  55.         nil.left = nil;  
  56.         nil.right = nil;  
  57.         nil.level = 0;  
  58.           
  59.         root = nil;  
  60.     }  
  61.       
  62.     public AANode<T> getRoot(){  
  63.         return root;  
  64.     }  
  65.       
  66.     private AANode<T> rotateLeftChild(AANode<T> t){       
  67.         AANode<T> x = t.left;  
  68.         t.left = x.right;  
  69.         x.right = t;  
  70.           
  71.         return x;  
  72.     }  
  73.       
  74.     private AANode<T> rotateRightChild(AANode<T> t){  
  75.         AANode<T> x = t.right;  
  76.         t.right = x.left;  
  77.         x.left = t;  
  78.           
  79.         return x;  
  80.     }  
  81.       
  82.     private AANode<T> skew(AANode<T> t){  
  83.         if(t != nil && t.left.level == t.level)  
  84.             t=rotateLeftChild(t);  
  85.         return t;  
  86.     }  
  87.       
  88.     private AANode<T> split(AANode<T> t){  
  89.         if(t != nil && t.right.right.level == t.level){  
  90.             t = rotateRightChild(t);  
  91.             t.level++;  
  92.         }  
  93.         return t;  
  94.     }  
  95.       
  96.       
  97.     //single insert  
  98.     public void insert(T x) throws Exception{  
  99.         root = insert(x,root);  
  100.     }  
  101.     //batch insert  
  102.     public void insert(T[] keys) throws Exception{  
  103.         for(T x:keys){  
  104.             insert(x);  
  105.         }  
  106.     }  
  107.       
  108.       
  109.     //x: the AANode to insert  
  110.     //t: the root of the subtree  
  111.     //return: the new root  
  112.     private AANode<T> insert(T x,AANode<T> t) throws Exception{  
  113.         if(t==nil){  
  114.             t = new AANode<T>(x,nil,nil);  
  115.         }else if(x.compareTo(t.key)<0){  
  116.             //search the left subtree  
  117.             AANode<T> left = insert(x,t.left);  
  118.             t.left = left;  
  119.         }else if(x.compareTo(t.key)>0){  
  120.             //search the right subtree  
  121.             AANode<T> right = insert(x,t.right);        
  122.             t.right = right;  
  123.         }else{  
  124.             //duplicate key found!  
  125.             throw new Exception("Duplicate key is found!");  
  126.         }  
  127.         t = skew(t);  
  128.         t = split(t);  
  129.           
  130.         return t;  
  131.     }  
  132.     //single delete  
  133.     public void delete(T x) throws Exception{  
  134.         delete(x,this.root);  
  135.     }  
  136.     //batch delete  
  137.     public void delete(T[] keys) throws Exception{  
  138.         for(T x:keys){  
  139.             delete(x);  
  140.         }  
  141.     }  
  142.     //x: the AANode to delete  
  143.     //t: the root of the subtree  
  144.     //return: the new root  
  145.     private void delete(T x,AANode<T> t) throws Exception{  
  146.         //delete using BST method  
  147.         AANode<T> deleteNode = null;  
  148.           
  149.         Stack<AANode<T>> nodes = new Stack<AANode<T>>();  
  150.         nodes.push(nil); //sentinel  
  151.         while(t != nil){  
  152.             nodes.push(t);        
  153.           
  154.             if(x.compareTo(t.key)==0){  
  155.                 deleteNode = t;  
  156.                 t = t.left; //find predecessor  
  157.             }else if(x.compareTo(t.key)<0){  
  158.                 //search the left subtree  
  159.                 t = t.left;  
  160.             }else {  
  161.                 //search the right subtree  
  162.                 t = t.right;  
  163.             }             
  164.         }  
  165.           
  166.         if(deleteNode == null){  
  167.             throw new Exception("No key is found!");  
  168.         }  
  169.           
  170.         //the top element in the stack is the predecessor of the deleted node or the deleted node itself  
  171.         t = nodes.pop();  
  172.         if(deleteNode != t){  
  173.             //t is the predecessor of the deleteNode  
  174.             deleteNode.key = t.key;  //normal BST operation  
  175.         }//otherwise: t is a single black leaf node (level=1)  
  176.           
  177.         //remove the node  
  178.         if(t.right != nil){       
  179.             //there is a red right child (which has same level with t)  
  180.             AANode<T> parent = nodes.pop();  
  181.             if(parent == nil){  
  182.                 this.root = t.right;  
  183.             }else{  
  184.                 if(parent.left == t)  
  185.                     parent.left = t.right;  
  186.                 else  
  187.                     parent.right = t.right;  
  188.             }     
  189.             //return this.root;  
  190.         }else{  
  191.             AANode<T> parent = nodes.pop();  
  192.             if(parent == nil){  
  193.                 //now return an empty tree  
  194.                 //return nil;  
  195.                 this.root = nil;  
  196.             }else{                                
  197.                 if(parent.left == t){   
  198.                     parent.left = nil;  
  199.                 }else{   
  200.                     parent.right = nil;  
  201.                 }   
  202.                 t=parent;                 
  203.                 AANode<T> rootNode = null;   
  204.                                   
  205.                 //rebalance  
  206.                 boolean deleteFromRight = false;  
  207.                 while(!nodes.isEmpty() && t != nil){                                                          
  208.                     parent = nodes.peek();                                    
  209.                       
  210.                     boolean doSkewOrSplit = false;  
  211.                     int currLevel = t.level;  
  212.                     if(t.left.level < currLevel - 1){  
  213.                         if(parent != nil && parent.right == t) {  
  214.                             deleteFromRight = true;  
  215.                         }         
  216.                           
  217.                         t.level--;  
  218.                         if(t.right.level == currLevel) {  
  219.                             t.right.level--;  
  220.                         }         
  221.                         doSkewOrSplit = true;  
  222.                     }else if(t.right.level<currLevel - 1   
  223.                             || (deleteFromRight && currLevel-1==t.right.level)){  
  224.                         if(parent != nil && parent.right == t) {  
  225.                             deleteFromRight = true;  
  226.                         }         
  227.                           
  228.                         t.level--;  
  229.                           
  230.                         doSkewOrSplit = true;  
  231.                     }  
  232.                     if(doSkewOrSplit){  
  233.                         t = skew(t);      
  234.                         t.right = skew(t.right);                          
  235.                         t.right.right = skew(t.right.right);  
  236.                           
  237.                         t = split(t);  
  238.                         t.right = split(t.right);  
  239.                           
  240.                         //set the parent  
  241.                         if(parent != nil) {  
  242.                             if(deleteFromRight)  
  243.                                 parent.right = t;  
  244.                             else  
  245.                                 parent.left = t;  
  246.                         }                         
  247.                     }else//no rotation   
  248.                         rootNode = this.root;  
  249.                         break;  
  250.                     }  
  251.                     rootNode = t;     
  252.                     t = nodes.pop();  
  253.                 }             
  254.                 //return rootNode;  
  255.                 this.root = rootNode;  
  256.             }  
  257.         }         
  258.     }  
  259.     public static void testCases() throws Exception{  
  260.            
  261.         AATree<Integer> aaT = new AATree<Integer>();  
  262.         try{  
  263.             aaT.delete(0);  //throw exception  
  264.             System.out.println("***Exception Test WRONG");  
  265.         }catch(Exception e){  
  266.             if(e.getMessage().startsWith("No key is found!")){  
  267.                 System.out.println("Exception Test OK");  
  268.             }else{  
  269.                 System.out.println("***Exception Test WRONG");  
  270.             }  
  271.         }  
  272.           
  273.         System.out.println("*************************");  
  274.         aaT = new AATree<Integer>();  
  275.         Integer[] A = new Integer[]{0,1,2,3,4,5,6};  
  276.         aaT.insert(A);  
  277.         System.out.println("After Insert:");  
  278.         AATree.print(aaT);  
  279.               
  280.         System.out.println("*************************");  
  281.         aaT = new AATree<Integer>();  
  282.         A = new Integer[]{6,5,4,3,2};  
  283.         aaT.insert(A);  
  284.         System.out.println("After Insert:");  
  285.         AATree.print(aaT);  
  286.               
  287.         System.out.println("*************************");  
  288.         aaT = new AATree<Integer>();  
  289.         aaT.insert(1);  
  290.         System.out.println("Before Delete:");  
  291.         AATree.print(aaT);  
  292.         aaT.delete(1);  //become an empty tree  
  293.         System.out.println("After Delete 1:");  
  294.         AATree.print(aaT);  
  295.         if(aaT.isEmptyTree()){  
  296.             System.out.println("Empty Tree Test OK");  
  297.         }else{  
  298.             System.out.println("***Empty Tree Test WRONG");  
  299.         }  
  300.           
  301.         System.out.println("*************************");  
  302.         aaT = new AATree<Integer>();  
  303.         aaT.insert(1);  
  304.         aaT.insert(2);  
  305.         System.out.println("Before Delete:");  
  306.         AATree.print(aaT);  
  307.         aaT.delete(2);  //delete right node (red)  
  308.         System.out.println("After Delete 2:");  
  309.         AATree.print(aaT);  
  310.         if(aaT.getRoot().getKey() == 1){  
  311.             System.out.println("Delete Red Leaf OK");  
  312.         }else{  
  313.             System.out.println("***Delete Red Leaf WRONG");  
  314.         }  
  315.           
  316.         System.out.println("*************************");  
  317.         aaT = new AATree<Integer>();  
  318.         aaT.insert(1);  
  319.         aaT.insert(2);  
  320.         System.out.println("Before Delete:");  
  321.         AATree.print(aaT);  
  322.         aaT.delete(1);  //delete 1  
  323.         System.out.println("After Delete 1:");  
  324.         AATree.print(aaT);  
  325.         if(aaT.getRoot().getKey() == 2){  
  326.             System.out.println("Delete Root OK");  
  327.         }else{  
  328.             System.out.println("***Delete Root WRONG");  
  329.         }  
  330.           
  331.         System.out.println("*************************");  
  332.         aaT = new AATree<Integer>();  
  333.         A = new Integer[]{0,1,2,3,4,6,7};  
  334.         aaT.insert(A);  
  335.         aaT.insert(5);  
  336.         System.out.println("Before Delete:");  
  337.         AATree.print(aaT);  
  338.         //tree:  
  339. /* 
  340.             3,3 
  341.         /         / 
  342.      1,2           6,2 
  343.     /   /         /   / 
  344.  0,1     2,1   4,1     7,1 
  345.                  / 
  346.                   5,1 
  347.  */  
  348.         aaT.delete(5);  
  349.         System.out.println("After Delete 5:");  
  350.         AATree.print(aaT);  
  351.         AANode<Integer> node = aaT.findNode(4);  
  352.         if(aaT.isLeaf(node)){  
  353.             System.out.println("Leaf Test OK");  
  354.         }else{  
  355.             System.out.println("***Leaf Test WRONG");  
  356.         }  
  357.           
  358.           
  359.         System.out.println("*************************");  
  360.         aaT = new AATree<Integer>();  
  361.         A = new Integer[]{0,1,2,3,4,6,7};  
  362.         aaT.insert(A);  
  363.         aaT.insert(5);  
  364.         System.out.println("Before Delete:");  
  365.         AATree.print(aaT);  
  366.         //tree:  
  367. /* 
  368.             3,3 
  369.         /         / 
  370.      1,2           6,2 
  371.     /   /         /   / 
  372.  0,1     2,1   4,1     7,1 
  373.                  / 
  374.                   5,1 
  375.  */  
  376.         aaT.delete(3);  
  377.         System.out.println("After Delete 3:");  
  378.         AATree.print(aaT);  
  379.         node = aaT.findNode(0);  
  380.         if(node.getRightChild()==1){  
  381.             System.out.println("Right Child OK");  
  382.         }else{  
  383.             System.out.println("***Right Child WRONG");  
  384.         }  
  385.         if(aaT.getRoot().getKey()==2){  
  386.             System.out.println("Root Key OK");  
  387.         }else{  
  388.             System.out.println("***Root Key WRONG");  
  389.         }  
  390.           
  391.         System.out.println("*************************");  
  392.         aaT = new AATree<Integer>();  
  393.         A = new Integer[]{0,1,2,3,4,6,7};  
  394.         aaT.insert(A);  
  395.         aaT.insert(5);  
  396.         System.out.println("Before Delete:");  
  397.         AATree.print(aaT);  
  398.         //tree:  
  399. /* 
  400.             3,3 
  401.         /         / 
  402.      1,2           6,2 
  403.     /   /         /   / 
  404.  0,1     2,1   4,1     7,1 
  405.                  / 
  406.                   5,1 
  407.  */  
  408.         aaT.delete(4);  
  409.         System.out.println("After Delete 4:");  
  410.         AATree.print(aaT);  
  411.         if(aaT.findNode(5).level==1){  
  412.             System.out.println("Leaf Level OK");  
  413.         }else{  
  414.             System.out.println("***Leaf Level WRONG");  
  415.         }  
  416.         if(aaT.findNode(6).level==2){  
  417.             System.out.println("Subtree's Root Level OK");  
  418.         }else{  
  419.             System.out.println("***Subtree's Root Level WRONG");  
  420.         }  
  421.           
  422.         System.out.println("*************************");  
  423.         aaT = new AATree<Integer>();  
  424.         A = new Integer[]{10,85,15,70,20,60,30,50,65,80,90,40,5,55,35};  
  425.         aaT.insert(A);  
  426.         System.out.println("Before Insert 45:");  
  427.         AATree.print(aaT);  
  428.         aaT.insert(45);  
  429.         System.out.println("After Insert 45:");  
  430.         AATree.print(aaT);  
  431.         if(aaT.getRoot().key==50 && aaT.getRoot().level == 4){  
  432.             System.out.println("Root(50) Level OK");  
  433.         }else{  
  434.             System.out.println("***Root Level WRONG");  
  435.         }  
  436.           
  437.         System.out.println("*************************");  
  438.         aaT = new AATree<Integer>();  
  439.         A = new Integer[]{0,1,2,3,4,5,6};  
  440.         aaT.insert(A);  
  441.         System.out.println("Before Delete:");  
  442.         AATree.print(aaT);  
  443.         /* 
  444.             3,3 
  445.         /         / 
  446.      1,2           5,2 
  447.     /   /         /   / 
  448.  0,1     2,1   4,1     6,1 
  449. */  
  450.         Integer[] DEL = new Integer[]{0,3};  
  451.         aaT.delete(DEL);  //until now nothing special  
  452.         System.out.println("After Delete 0 and 3:");  
  453.         AATree.print(aaT);  
  454.         aaT.delete(1);  
  455.         System.out.println("After Delete 1:");  
  456.         AATree.print(aaT);  
  457.         if(aaT.getRoot().key==4 && aaT.getRoot().level == 2){  
  458.             System.out.println("Root(4) Level OK");  
  459.         }else{  
  460.             System.out.println("***Root Level WRONG");  
  461.         }  
  462.           
  463.         System.out.println("*************************");  
  464.         //make a tree  
  465.         aaT = new AATree<Integer>();  
  466.         buildTestTree1(aaT);      
  467.         System.out.println("Before Delete:");  
  468.         AATree.print(aaT);  
  469.         //test the tree  
  470.         aaT.delete(1);  
  471.         System.out.println("After Delete 1:");  
  472.         AATree.print(aaT);  
  473.         if(aaT.getRoot().key==3 && aaT.getRoot().level == 2){  
  474.             System.out.println("Root(3) Level OK");  
  475.         }else{  
  476.             System.out.println("***Root Level WRONG");  
  477.         }  
  478.           
  479.         System.out.println("*************************");  
  480.         aaT = new AATree<Integer>();  
  481.         buildTestTree1(aaT);      
  482.         System.out.println("Before Delete:");  
  483.         AATree.print(aaT);  
  484.         //test the tree  
  485.         aaT.delete(7);  
  486.         System.out.println("After Delete 7:");  
  487.         AATree.print(aaT);  
  488.         aaT.delete(6);  
  489.         System.out.println("After Delete 6:");  
  490.         AATree.print(aaT);  
  491.         if(aaT.getRoot().key==2 && aaT.getRoot().level == 2){  
  492.             System.out.println("Root(2) Level OK");  
  493.         }else{  
  494.             System.out.println("***Root Level WRONG");  
  495.         }  
  496.           
  497.         System.out.println("*************************");  
  498.         aaT = new AATree<Integer>();  
  499.         buildTestTree2(aaT);      
  500.         System.out.println("Before Delete:");  
  501.         AATree.print(aaT);  
  502.         //test the tree  
  503.         aaT.delete(7);  
  504.         System.out.println("After Delete 7:");  
  505.         AATree.print(aaT);  
  506.           
  507.         System.out.println("*************************");  
  508.         aaT = new AATree<Integer>();  
  509.         buildTestTree3(aaT);      
  510.         System.out.println("Before Delete:");  
  511.         AATree.print(aaT);  
  512.         //test the tree  
  513.         aaT.delete(7);  
  514.         System.out.println("After Delete 7:");  
  515.         AATree.print(aaT);  
  516.     }  
  517.       
  518.     private static void buildTestTree1(AATree<Integer> aaT){  
  519.           
  520.         AANode<Integer> root = aaT.makeNode(2);  
  521.         root.level = 2;  
  522.         AANode<Integer> node1 = aaT.makeNode(1);  
  523.         node1.level = 1;  
  524.         AANode<Integer> node5 = aaT.makeNode(5);  
  525.         node5.level = 2;  
  526.         AATree.attachAsLeftChild(root, node1);  
  527.         AATree.attachAsRightChild(root, node5);  
  528.           
  529.         AANode<Integer> node3 = aaT.makeNode(3);  
  530.         node3.level = 1;  
  531.         AANode<Integer> node6 = aaT.makeNode(6);  
  532.         node6.level = 1;  
  533.         AANode<Integer> node4 = aaT.makeNode(4);  
  534.         node4.level = 1;  
  535.         AANode<Integer> node7 = aaT.makeNode(7);  
  536.         node7.level = 1;  
  537.         AATree.attachAsLeftChild(node5, node3);  
  538.         AATree.attachAsRightChild(node5, node6);  
  539.           
  540.         AATree.attachAsRightChild(node3, node4);  
  541.         AATree.attachAsRightChild(node6, node7);  
  542.         aaT.setRoot(root);  
  543.     }  
  544.       
  545.     private static void buildTestTree2(AATree<Integer> aaT){  
  546.           
  547.         AANode<Integer> root = aaT.makeNode(3);  
  548.         root.level = 2;  
  549.         AANode<Integer> node1 = aaT.makeNode(1);  
  550.         node1.level = 1;  
  551.         AANode<Integer> node6 = aaT.makeNode(6);  
  552.         node6.level = 2;  
  553.         AATree.attachAsLeftChild(root, node1);  
  554.         AATree.attachAsRightChild(root, node6);  
  555.           
  556.         AANode<Integer> node2 = aaT.makeNode(2);  
  557.         node2.level = 1;  
  558.         AANode<Integer> node4 = aaT.makeNode(4);  
  559.         node4.level = 1;  
  560.         AANode<Integer> node7 = aaT.makeNode(7);  
  561.         node7.level = 1;  
  562.         AANode<Integer> node5 = aaT.makeNode(5);  
  563.         node5.level = 1;  
  564.         AATree.attachAsLeftChild(node6, node4);  
  565.         AATree.attachAsRightChild(node6, node7);  
  566.           
  567.         AATree.attachAsRightChild(node4, node5);  
  568.         AATree.attachAsRightChild(node1, node2);  
  569.         aaT.setRoot(root);  
  570.     }  
  571.       
  572.     private static void buildTestTree3(AATree<Integer> aaT){  
  573.       
  574.     AANode<Integer> root = aaT.makeNode(3);  
  575.     root.level = 2;  
  576.     AANode<Integer> node1 = aaT.makeNode(1);  
  577.     node1.level = 1;  
  578.     AANode<Integer> node6 = aaT.makeNode(6);  
  579.     node6.level = 2;  
  580.     AATree.attachAsLeftChild(root, node1);  
  581.     AATree.attachAsRightChild(root, node6);  
  582.       
  583.     AANode<Integer> node2 = aaT.makeNode(2);  
  584.     node2.level = 1;  
  585.     AANode<Integer> node7 = aaT.makeNode(7);  
  586.     node7.level = 1;  
  587.     AANode<Integer> node5 = aaT.makeNode(5);  
  588.     node5.level = 1;  
  589.     AATree.attachAsLeftChild(node6, node5);  
  590.     AATree.attachAsRightChild(node6, node7);  
  591.       
  592.     AATree.attachAsRightChild(node1, node2);  
  593.     aaT.setRoot(root);  
  594. }  
  595.     //utility method for test purpose  
  596.     @SuppressWarnings("rawtypes")  
  597.     public static void print(AATree aaTree){  
  598.         AANode root = aaTree.getRoot();  
  599.         System.out.format("%nin-order BST:%n");   
  600.         NODES=0;  
  601.         AATree.recursiveInOrderTraverse(root);  
  602.           
  603.         System.out.format("%n%n%nThe tree is:");  
  604.         AATree.displayBinaryTree(root,NODES);  
  605.           
  606.     }  
  607.       
  608.     private static int NODES=0;  
  609.     //utility method for test purpose  
  610.     @SuppressWarnings("rawtypes")  
  611.     private static void recursiveInOrderTraverse(AANode root){  
  612.         if(root.key == null)return;  
  613.           
  614.         recursiveInOrderTraverse(root.left);  
  615.         System.out.format(" (%d,%d)", root.key,root.level);  
  616.         NODES++;  
  617.         recursiveInOrderTraverse(root.right);  
  618.     }  
  619.     //utility method for test purpose  
  620.     //n: the nodes number of the tree  
  621.     @SuppressWarnings("rawtypes")  
  622.     private static void displayBinaryTree(AANode root,int n){         
  623.         if(root.key == nullreturn;  
  624.           
  625.         LinkedList<AANode> queue = new LinkedList<AANode>();  
  626.           
  627.         //all AANodes in each level  
  628.         List<List<AANode>> nodesList = new ArrayList<List<AANode>>();  
  629.           
  630.         //the positions in a displayable tree for each level's nodes  
  631.         List<List<Integer>> nextPosList = new ArrayList<List<Integer>>();  
  632.           
  633.         queue.add(root);  
  634.         //int level=0;  
  635.         int levelNodes = 1;       
  636.           
  637.         int nextLevelNodes = 0;       
  638.         List<AANode> levelNodesList = new ArrayList<AANode>();    
  639.         List<Integer> nextLevelNodesPosList = new ArrayList<Integer>();  
  640.           
  641.         int pos = 0;  //the position of the current node  
  642.         List<Integer> levelNodesPosList = new ArrayList<Integer>();  
  643.         levelNodesPosList.add(0); //root position  
  644.         nextPosList.add(levelNodesPosList);  
  645.         int levelNodesTotal = 1;  
  646.         while(!queue.isEmpty()) {  
  647.             AANode node = queue.remove();  
  648.               
  649.             if(levelNodes==0){         
  650.                 nodesList.add(levelNodesList);  
  651.                 nextPosList.add(nextLevelNodesPosList);  
  652.                 levelNodesPosList = nextLevelNodesPosList;  
  653.                   
  654.                 levelNodesList = new ArrayList<AANode>();       
  655.                 nextLevelNodesPosList = new ArrayList<Integer>();  
  656.                   
  657.                 //level++;   
  658.                 levelNodes = nextLevelNodes;  
  659.                 levelNodesTotal = nextLevelNodes;  
  660.                   
  661.                 nextLevelNodes = 0;               
  662.             }         
  663.             levelNodesList.add(node);             
  664.               
  665.             pos = levelNodesPosList.get(levelNodesTotal - levelNodes);            
  666.             if(node.left.key != null){  
  667.                 queue.add(node.left);  
  668.                 nextLevelNodes++;         
  669.                 nextLevelNodesPosList.add(2*pos);  
  670.             }  
  671.                       
  672.             if(node.right.key != null) {  
  673.                 queue.add(node.right);  
  674.                 nextLevelNodes++;         
  675.                   
  676.                 nextLevelNodesPosList.add(2*pos+1);  
  677.             }  
  678.                           
  679.             levelNodes--;             
  680.         }  
  681.         //save the last level's nodes list  
  682.         nodesList.add(levelNodesList);  
  683.           
  684.         int maxLevel = nodesList.size()-1;  //==level  
  685.            
  686.         //use both nodesList and nextPosList to set the positions for each node  
  687.           
  688.         //Note: expected max columns: 2^(level+1) - 1  
  689.         int cols = 1;  
  690.         for(int i=0;i<=maxLevel;i++){  
  691.             cols <<= 1;             
  692.         }  
  693.         cols--;  
  694.         AANode[][] tree = new AANode[maxLevel+1][cols];  
  695.           
  696.         //load the tree into an array for later display   
  697.         for(int currLevel=0;currLevel<=maxLevel;currLevel++){  
  698.             levelNodesList = nodesList.get(currLevel);  
  699.             levelNodesPosList = nextPosList.get(currLevel);  
  700.             //Note: the column for this level's j-th element: 2^(maxLevel-level)*(2*j+1) - 1  
  701.             int tmp = maxLevel-currLevel;  
  702.             int coeff = 1;  
  703.             for(int i=0;i<tmp;i++){  
  704.                 coeff <<= 1;            
  705.             }  
  706.             for(int k=0;k<levelNodesList.size();k++){  
  707.                 int j = levelNodesPosList.get(k);  
  708.                 int col = coeff*(2*j + 1) - 1;                
  709.                 tree[currLevel][col] = levelNodesList.get(k);  
  710.             }  
  711.         }  
  712.           
  713.         //display the binary search tree  
  714.         System.out.format("%n");  
  715.         for(int i=0;i<=maxLevel;i++){  
  716.             for(int j=0;j<cols;j++){  
  717.                 AANode node = tree[i][j];  
  718.                 if(node== null || node.key == null)  
  719.                     System.out.format("  ");  
  720.                 else  
  721.                     System.out.format("%2d,%d",node.key,node.level);  
  722.             }  
  723.             System.out.format("%n");  
  724.         }  
  725.     }  
  726.       
  727.     public void setRoot(AANode<T> root) {  
  728.         this.root = root;  
  729.     }  
  730.     public boolean isEmptyTree(){  
  731.         return this.root == nil;  
  732.     }  
  733.       
  734.     public AANode<T> makeNode(T key){  
  735.         return new AANode<T>(key,nil,nil);  
  736.     }  
  737.       
  738.     public static <T extends Comparable<T>> void attachAsLeftChild(AANode<T> parent,AANode<T> node){  
  739.         parent.left = node;  
  740.     }  
  741.     public static <T extends Comparable<T>> void attachAsRightChild(AANode<T> parent,AANode<T> node){  
  742.         parent.right = node;  
  743.     }  
  744.       
  745.     public boolean isLeaf(AANode<T> node){  
  746.         return node.getLeft()==nil && node.getRight() == nil;  
  747.     }  
  748.       
  749.     public AANode<T> findNode(T key) throws Exception{  
  750.         AANode<T> node = this.root;  
  751.         while(node != nil){  
  752.             if(key.compareTo(node.key)==0){  
  753.                 break;  
  754.             }else if(key.compareTo(node.key)<0){  
  755.                 node = node.left;  
  756.             }else if(key.compareTo(node.key)>0){  
  757.                 node = node.right;  
  758.             }  
  759.         }  
  760.         if(node == nil){  
  761.             throw new Exception("No such key is found!");  
  762.         }  
  763.         return node;  
  764.     }  
  765.       
  766.     public static void main(String[] args) throws Exception {  
  767.         testCases();  
  768.     }  
  769. }  

 

 

性能测试:从磁盘读入一百万条数据到内存,然后依次查找、插入和删除各50万次。

 

先是性能测试代码:

其中prepareTestData(dataFilename,N)语句只需执行一次,用于写入一百万个不重复的整数到磁盘文件中:

[java]  view plain copy
  1. public static void main(String[] args) throws Exception {     
  2.     String dataFilename = "C://tmp//aatree.txt";  
  3.     int N = 1000000;  //the number of keys   
  4.       
  5.     //******Prepare Data(only execute once for multiple tests)******  
  6.     prepareTestData(dataFilename,N);  
  7.       
  8.     //******Begin Test******  
  9.     AATree<Integer> aaT = new AATree<Integer>();  
  10.     DataInputStream in= new DataInputStream(new FileInputStream(dataFilename));  
  11.     //long startTime = System.currentTimeMillis();        
  12.     int key = -1;  
  13.     int keyCount = 0;  
  14.     while(true){  
  15.         try{  
  16.             key = in.readInt();  
  17.             aaT.insert(key);  
  18.             keyCount++;  
  19.         }catch(EOFException e){  
  20.             break;  
  21.         }  
  22.     }         
  23.     in.close();  
  24.     //long endTime = System.currentTimeMillis();  
  25.     //System.out.format("file io and insert time spent: %d(ms)%n",(endTime-startTime));  
  26.     System.out.format("Total number of keys to begin with: %d%n",keyCount);  
  27.       
  28.     long t1=0,t2=0;  
  29.       
  30.     //do some operations in memory  
  31.     long startTime = System.currentTimeMillis();      
  32.     t1 = startTime;  
  33.     int totalSuccess = 0;  
  34.     int totalFailed = 0;      
  35.       
  36.     System.out.format("%n***Search Operations***%n");  
  37.     //try to find a number of keys  
  38.     int rangeStart = 1100000;  
  39.     int rangeEnd = 1600000;  
  40.     for(int i=rangeStart;i<rangeEnd;i++){  
  41.         try{              
  42.             AANode<Integer> node = aaT.findNode(i);  
  43.             //System.out.println("found key: " + node.key);  
  44.             totalSuccess++;  
  45.         }catch(Exception e){  
  46.             totalFailed++;  
  47.             //not found  
  48.             //System.out.println(e.getMessage());             
  49.         }  
  50.     }  
  51.     t2 = System.currentTimeMillis();  
  52.     System.out.format("Time spent: %d(ms)%n",(t2-t1));  
  53.     System.out.format("The number of keys we try to find: %d%n",rangeEnd-rangeStart);  
  54.     System.out.format("The number of keys found: %d%n",totalSuccess);  
  55.     System.out.format("The number of keys not found: %d%n",totalFailed);  
  56.       
  57.     //insert a number of new keys  
  58.     System.out.format("%n***Insertion Operations***%n");  
  59.     t1 = System.currentTimeMillis();      
  60.     totalSuccess = 0;  
  61.     totalFailed = 0;  
  62.     rangeStart = 1400000;  
  63.     rangeEnd = 1900000;  
  64.     for(int i=rangeStart;i<rangeEnd;i++){  
  65.         try{              
  66.             aaT.insert(i);  
  67.             //System.out.println("inserted key: " + i);  
  68.             totalSuccess++;  
  69.         }catch(Exception e){  
  70.             totalFailed++;  
  71.             //duplicate insert  
  72.             //System.out.println(e.getMessage());             
  73.         }  
  74.     }         
  75.     t2 = System.currentTimeMillis();      
  76.     System.out.format("Time spent: %d(ms)%n",(t2-t1));  
  77.     System.out.format("The number of keys we try to insert: %d%n",rangeEnd - rangeStart);  
  78.     System.out.format("The number of keys inserted: %d%n",totalSuccess);  
  79.     System.out.format("The number of keys with insertion failed due to duplicate: %d%n",totalFailed);  
  80.       
  81.     //delete a number of new keys  
  82.     System.out.format("%n***Deletion Operations***%n");  
  83.     t1 = System.currentTimeMillis();      
  84.     totalSuccess = 0;  
  85.     totalFailed = 0;  
  86.     rangeStart = 400000;  
  87.     rangeEnd = 900000;  
  88.     for(int i=rangeStart;i<rangeEnd;i++){  
  89.         try{              
  90.             aaT.delete(i);  
  91.             //System.out.println("deleted key: " + i);  
  92.             totalSuccess++;  
  93.         }catch(Exception e){  
  94.             totalFailed++;  
  95.             //not found  
  96.             //System.out.println(e.getMessage());             
  97.         }  
  98.     }  
  99.     t2 = System.currentTimeMillis();  
  100.     System.out.format("Time spent: %d(ms)%n",(t2-t1));  
  101.     System.out.format("The number of keys we try to delete: %d%n",rangeEnd-rangeStart);  
  102.     System.out.format("The number of keys deleted: %d%n",totalSuccess);  
  103.     System.out.format("The number of keys with deletion failed due to non-existence: %d%n",totalFailed);  
  104.       
  105.       
  106.     long endTime = t2;  
  107.     System.out.format("%nThe above operations(search,insert,delete) total spent: %d(ms)%n",(endTime-startTime));  
  108.       
  109. }  
  110.   
  111. //write non-duplicate keys into external file for later test  
  112. private static void prepareTestData(String dataFilename,int totalKeys) throws IOException{  
  113.     AATree<Integer> aaT = new AATree<Integer>();  
  114.       
  115.     //multiply by a larger factor(here it is 10) to eliminate the duplicate insert  
  116.     int KEYRANGE = totalKeys*10;  
  117.     int i=0;  
  118.     while(i<totalKeys){  
  119.         int rand = (int)(Math.random()*KEYRANGE);  
  120.         try{  
  121.             aaT.insert(rand);  
  122.             i++;  
  123.             //System.out.format("insert: %d%n",rand);  
  124.         }catch(Exception e){  
  125.             //for duplicate insert: retry  
  126.             //System.out.println(e.getMessage());  
  127.         }  
  128.     }     
  129.     DataOutputStream out= new DataOutputStream(new FileOutputStream(dataFilename));  
  130.     persistKeys(aaT.getRoot(),out);  
  131.     out.close();  
  132. }  
  133.   
  134. private static void persistKeys(AANode<Integer> root,DataOutputStream out) throws IOException{  
  135.     if(root.key == null)return;  
  136.       
  137.     persistKeys(root.left,out);  
  138.     out.writeInt(root.key);  
  139.     persistKeys(root.right,out);  
  140. }  

 

性能测试报告(Intel Core2 T5500 1.66GHz, 2GB RAM):

Total number of keys to begin with: 1000000

***Search Operations***
Time spent: 2172(ms)
The number of keys we try to find: 500000
The number of keys found: 49955
The number of keys not found: 450045

***Insertion Operations***
Time spent: 1984(ms)
The number of keys we try to insert: 500000
The number of keys inserted: 450090
The number of keys with insertion failed due to duplicate: 49910

***Deletion Operations***
Time spent: 3172(ms)
The number of keys we try to delete: 500000
The number of keys deleted: 7
The number of keys with deletion failed due to non-existence: 499993

The above operations(search,insert,delete) total spent: 7328(ms)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值