Javaベース-バランス二叉検索ツリー(AVLツリー)


三日間をかけて、ノートの木を描きました.やっとできたはずです.
まず一点の木の4種類の回転、シングルスピン、シングルスピン、双方向左回り、両方の右回りは大丈夫です.また、バランスツリーの追加機能は可能です.機能を削除しました.
package com.yc.tree;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;


/**
 * @author wb
 * @param 
 * 
 * 
 *        (height balanced binary search tree) 1962  Adelson-Velskii 
 * Landis  ,     AVL 。AVL    :            ;  T     ,TL TR    
 *            ,         ,  T        :(1)TL TR         ;(2)
 * |hL - hR| <= 1,  hL hR   TL TR   。
 * 
 *             p,    (TL)    (TR)      hL hR, BF(p)  p       
 * (balance factory)。        hL - hR。   AVL  ,           -1 0 1,
 *  |hL - hR| < 2。
 * 
 *               (AVL )。   30            2.
 * 			              50 BF=1
 * 						  ││
 * 		  BF=-2 30────────┘└─────────70 BF=1
 * 				│					  │
 * 				└──40 BF=1	 BF=0 60──┘
 * 					│
 * 		  BF=0 35───┘
 * 				 xx.xx           
 * 
 *
 *   :
 *  AVL                               ,            ,
 *                         。                1.5   log n 
 *    ,    AVL           ,           O(log n)   。      
 *      Balanced BST           e          :  BBST   ,   
 *        e      BBST    ,     1;   e     BBST          ,
 *     ;   e      BBST        ,   BBST         e         ,
 *   e   BBST     ,               (+1) ,            : 
 * BBST          -1(              ,             0,BBST     ;
 * BBST          0( 、        ):             1,BBST    1;  
 *  BBST          1(              ):  BBST             1:
 *              ,         ,                    0,      ; 
 *   e      BBST        ,   BBST         e         ,  e   BBST
 *       ,               (+1) ,          。
 *  
 *    :
 *   AVL                          ,               。       
 *            log n      ,    AVL          ,           O(log n)   。
 *  
 *  (     :      (  privot           )
 *  	             (                 )。         
 *  	 pivot.BF >= 0 
 *  	(privot.left.BF >= 0     LL )
 *  	(privot.left.BF < 0     LR )
 *  
 *  	 pivot.BF < 0 
 *  	(privot.right.BF >= 0     RL )
 *  	(privot.right.BF < 0     RR )
 *  )                       。                 ,         。
 *  
 *  
 *    :
 *   AVL        BST       ,     O(log n)   ,  AVL        。
 *          ,             。(            ,            。)
 */
public class HeightBalanBinSearchTree >{
	private static final int LEFT_HEAVY = -1;
	private static final int BALANCED = 0;
	private static final int RIGHT_HEAVY = 1;
	private static final int RIGHT_RIGHT_HEAVY = 2;
	private static final int LEFT_LEFT_HEAVY = -2;
	
	public class AVLNode {
		//               
		int balanceFactory;
		T data;
		AVLNode left;
		AVLNode right;
		//           
		AVLNode parent;
		
		public AVLNode(int balanceFactory, T data, AVLNode left, AVLNode right, AVLNode parent){
			this.balanceFactory = balanceFactory;
			this.data = data;
			this.left = left;
			this.right = right;
			this.parent = parent;
		}
		public String toString(){
			return "[BF=" + balanceFactory + ",data=" + data + "]";
		}
	}
	//avl     
	private AVLNode root;
	
	public HeightBalanBinSearchTree(){
	}
	public HeightBalanBinSearchTree(T data){
		root = new AVLNode(BALANCED, data, null, null, null);
	}
	
	/**
	 *  AVL         data   
	 * @param data
	 */
	public void add(T data){
		if(root == null){
			root = new AVLNode(BALANCED, data, null, null, null);
		}else{
			AVLNode current = root;
			AVLNode parent = null;
			int imp = 0;
			do{
				parent = current;
				imp = data.compareTo(current.data);
				if(imp > 0){
					current = current.right;
				}else{
					current = current.left;
				}
				
			}while(current != null);
			
			AVLNode newNode = new AVLNode(BALANCED, data, null, null, parent);
			
			if(imp > 0){
				parent.right = newNode;
			}else{
				parent.left = newNode;
			}
			//                        
			reBalacedForAdd(newNode);
		}
		
	}
	/**
	 *          
	 * @param data
	 */
	public void remove(T data){
		AVLNode delNode = getAVLNode(data);
		reBalacedForRemove(delNode);
	}
	//                   
	private void reBalacedForRemove(AVLNode target){

		if(target == null){//     
			return;
		}
		
		if(target.left == null && target.right == null){//         、     (    )
			if(target == root){
				root = null;
			}else{
				reBalacedForRemoveHelp(target);
				
				if(target == target.parent.left){
					target.parent.left = null;
				}else{
					target.parent.right = null;
				}
				//       
				target.parent = null;  
			}
		}else if(target.left != null && target.right == null){ //             (       ,         )
			//            
			if(root == target){
				root = target.left;
				target.left.parent = null; //       
			}
			else{
				//                 
				if(target == target.parent.left){
					target.parent.left = target.left;
				}else{
					target.parent.right = target.left;
				}
				target.left.parent = target.parent; //   (                ,          ,         )
				
				reBalacedForRemoveHelp(target.left);
			
				target.parent = target.left = target.right = null;
			}
		}else if(target.right != null && target.left == null){ //             
			if(root == target){
				root = target.right;
				target.right.parent = null; //       
			}
			else{
				if(target == target.parent.left){
					target.parent.left = target.right;
				}else{
					target.parent.right = target.right;
				}
				target.right.parent = target.parent;
				
				reBalacedForRemoveHelp(target.right);
				
				target.parent = target.left = target.right = null;
			}
		}else if(target.left != null && target.right != null){ //               ,     
			if(root == target){
				AVLNode leftMaxNode = target.left;
				
				while(leftMaxNode.right != null){
					leftMaxNode = leftMaxNode.right;
				}
				
				root = leftMaxNode;
				if(target.left.data.equals(leftMaxNode.data)){
					leftMaxNode.right = target.right;
					target.right.parent = leftMaxNode;//jia
					
					leftMaxNode.parent = null;
					target.right = target.parent = target.left = null;
					
					
					leftMaxNode.balanceFactory = target.balanceFactory - 1;
					reBalacedForRemoveHelpAndHelp(leftMaxNode);
					
					
				}else{
					AVLNode tmpNode = new AVLNode(0,null,leftMaxNode.left,null,leftMaxNode.parent);
					leftMaxNode.parent.right = tmpNode;
					
					leftMaxNode.left = target.left;
					leftMaxNode.right = target.right;
					//leftMaxNode.balanceFactory = target.balanceFactory;
					
					target.left.parent = leftMaxNode;
					target.right.parent = leftMaxNode;
					
					target.right = target.parent = target.left = null;
					leftMaxNode.parent = null;
					
					reBalacedForRemoveHelp(tmpNode);
					
					tmpNode.parent.right = tmpNode.left;
					if(tmpNode.left != null){
						tmpNode.left.parent = leftMaxNode.parent;
					}
					tmpNode = null;
					
				}
				
			}else{
				
				AVLNode leftMaxNode = target.left;
				
				while(leftMaxNode.right != null){
					leftMaxNode = leftMaxNode.right;
				}
				
				if(target.left.data.equals(leftMaxNode.data)){
					leftMaxNode.right = target.right;
					leftMaxNode.parent = target.parent;
					
					if(target == target.parent.left){
						target.parent.left = leftMaxNode;
					}else{
						target.parent.right = leftMaxNode;
					}
					
					target.right = target.parent = target.left = null;
					
					leftMaxNode.balanceFactory = target.balanceFactory - 1;
					reBalacedForRemoveHelpAndHelp(leftMaxNode);
					
				}else{
					AVLNode tmpNode = new AVLNode(0,null,leftMaxNode.left,null,leftMaxNode.parent);
					leftMaxNode.parent.right = tmpNode;
					
					
					if(target == target.parent.left){
						target.parent.left = leftMaxNode;
					}else{
						target.parent.right = leftMaxNode;
					}
					
					leftMaxNode.parent = target.parent;
					leftMaxNode.left = target.left;
					leftMaxNode.right = target.right;
					
					target.left.parent = leftMaxNode;
					target.right.parent = leftMaxNode;
					
					target.right = target.parent = target.left = null;
					
					reBalacedForRemoveHelp(tmpNode);
					
					tmpNode.parent.right = tmpNode.left;
					if(tmpNode.left != null){
						tmpNode.left.parent = leftMaxNode.parent;
					}
					tmpNode = null;
				}
			}
		}
	
	}
	//        (  ) 
	private void reBalacedForRemoveHelp(AVLNode node){
		if(node.parent != null){
			if(node.parent.left != null && node.parent.right != null && node.left == null && node.right == null){
				if(node == node.parent.left){
					node.parent.balanceFactory -= 1;
					reBalacedForRemoveHelpAndHelp(node.parent);
				}else if(node == node.parent.right){
					node.parent.balanceFactory += 1;
					reBalacedForRemoveHelpAndHelp(node.parent);
				}
			}else{
				if(node == node.parent.left){
					node.parent.balanceFactory -= 1;
				}else if(node == node.parent.right){
					node.parent.balanceFactory += 1;
				}
				AVLNode current = node.parent;
				while(current.parent != null){
					if(current.balanceFactory == BALANCED){
						if(current == current.parent.left){
							current.parent.balanceFactory -= 1;
							if(current.parent.balanceFactory == LEFT_LEFT_HEAVY){//  -2,    
								if(typeOfRemove(current.parent, LEFT_LEFT_HEAVY).equals("RR")){
									type_rR(current.parent);
									break;
								}else if(typeOfRemove(current.parent, LEFT_LEFT_HEAVY).equals("RL")){
									type_rL(current.parent, true);
									break;
								}else{
									//what are U nongshalie.
								}
							}
						}else if(current == current.parent.right){
							current.parent.balanceFactory += 1;
							if(current.parent.balanceFactory == RIGHT_RIGHT_HEAVY){//  2,    
								if(typeOfRemove(current.parent, RIGHT_RIGHT_HEAVY).equals("LL")){
									type_lL(current.parent);
									break;
								}else if(typeOfRemove(current.parent, RIGHT_RIGHT_HEAVY).equals("LR")){
									type_lR(current.parent, true);
									break;
								}else{
									//what are U nongshalie.
								}
							}
						}
					}else{
						break;
					}
					
					current = current.parent;
				}
			}
		}
	}
	private void reBalacedForRemoveHelpAndHelp(AVLNode current){
		if(current.balanceFactory == RIGHT_RIGHT_HEAVY){//  2,    
			if(typeOfRemove(current, RIGHT_RIGHT_HEAVY).equals("LL")){
				type_lL(current);
				reBalacedForRemoveHelp(current.parent);
			}else if(typeOfRemove(current, RIGHT_RIGHT_HEAVY).equals("LR")){
				type_lR(current, true);
				reBalacedForRemoveHelp(current.parent);
			}else{
				//what are U nongshalie.
			}
		}else if(current.balanceFactory == LEFT_LEFT_HEAVY){
			if(typeOfRemove(current, LEFT_LEFT_HEAVY).equals("RR")){
				type_rR(current);
				reBalacedForRemoveHelp(current.parent);
			}else if(typeOfRemove(current, LEFT_LEFT_HEAVY).equals("RL")){
				type_rL(current, true);
				reBalacedForRemoveHelp(current.parent);
			}else{
				//what are U nongshalie.
			}
		}
		
	}
	//                  
	private void reBalacedForAdd(AVLNode node){
		if(node.parent.left != null && node.parent.right != null){
			if(node == node.parent.left){
				node.parent.balanceFactory += 1;
				return;
			}else if(node == node.parent.right){
				node.parent.balanceFactory -= 1;
				return;
			}
		}else{
			if(node == node.parent.left){
				node.parent.balanceFactory += 1;
			}else if(node == node.parent.right){
				node.parent.balanceFactory -= 1;
			}
			
			AVLNode current = node.parent;
			while(current.parent != null){
				if(current.balanceFactory != BALANCED){
					if(current == current.parent.left){
						current.parent.balanceFactory += 1;
						if(current.parent.balanceFactory == RIGHT_RIGHT_HEAVY){//  2,    
							if(typeOfAdd(node, current.parent).equals("LL")){
								type_lL(current.parent);
								break;
							}else if(typeOfAdd(node, current.parent).equals("LR")){
								type_lR(current.parent, false);
								break;
							}
						}
					}else if(current == current.parent.right){
						current.parent.balanceFactory -= 1;
						if(current.parent.balanceFactory == LEFT_LEFT_HEAVY){//  -2,    
							if(typeOfAdd(node, current.parent).equals("RL")){
								type_rL(current.parent, false);
								break;
							}else if(typeOfAdd(node, current.parent).equals("RR")){
								type_rR(current.parent);
								break;
							}
						}
					}
					current = current.parent;
				}else{
					break;
				}
			}
		}
	}
	//        LL  RR  LR  RL
	private String typeOfAdd(AVLNode node, AVLNode bFIs2Node){
		AVLNode current = node;
		while(true){//        
			if(bFIs2Node.left != null){
				if(current == bFIs2Node.left.left){
					return "LL";
				}
				if(current == bFIs2Node.left.right){
					return "LR";
				}
				
			}else if(bFIs2Node.right != null){
				if(current == bFIs2Node.right.right){
					return "RR";
				}
				if(current == bFIs2Node.right.left){
					return "RL";
				}
			}
			current = current.parent;
		}
		
	}
	
	private String typeOfRemove(AVLNode bFIs2Node, int bf){
		if(bFIs2Node != null){
			if(bf == RIGHT_RIGHT_HEAVY){ //   
				if(bFIs2Node.left != null){
					if(bFIs2Node.left.balanceFactory >= BALANCED){
						return bFIs2Node.left.left != null ? "LL" : "";
					}else{
						return bFIs2Node.left.right != null ? "LR" : "";
					}
				}
			}else if(bf == LEFT_LEFT_HEAVY){ //   
				if(bFIs2Node.right != null){
					if(bFIs2Node.right.balanceFactory >= BALANCED){
						return bFIs2Node.right.left != null ? "RL" : "";
					}else{
						return bFIs2Node.right.right != null ? "RR" : "";
					}
				}
			}
		}
		return "";
	}
	/***
	 * LL (   )
	 * 			p				l
	 * 			│			   ││
	 * 		l───┘	->	  ll───┘└───p
	 * 		│
	 * ll───┘
	 * 
	 */
	private void type_lL(AVLNode p){
		if(p != null){
			AVLNode l = p.left;
			//AVLNode ll = l.left;
			
			if(p.parent == null){ //p  
				root = l;
				l.parent = null;
				p.left = l.right;
				l.right = p;
				p.parent = l;
				
				if(l.balanceFactory == RIGHT_HEAVY){ //1
					//l.balanceFactory = BALANCED;
					//p.balanceFactory = BALANCED;
					l.balanceFactory -= RIGHT_HEAVY;
					p.balanceFactory -= RIGHT_RIGHT_HEAVY;
				}else if(l.balanceFactory == BALANCED){//0 
					//l.balanceFactory = LEFT_HEAVY;
					//p.balanceFactory = BALANCED;
					l.balanceFactory -= RIGHT_HEAVY;
					p.balanceFactory -= RIGHT_HEAVY;
				}else{
					/*l.balanceFactory -= RIGHT_HEAVY;
					p.balanceFactory -= RIGHT_HEAVY;*/
				}
			}else{
				if(p == p.parent.left){
					p.parent.left = l;
				}else if(p == p.parent.right){
					p.parent.right = l;
				}
				l.parent = p.parent;
				p.left = l.right;
				l.right = p;
				p.parent = l;
				
				if(l.balanceFactory == RIGHT_HEAVY){ //1
					//l.balanceFactory = BALANCED;
					//p.balanceFactory = BALANCED;
					l.balanceFactory -= RIGHT_HEAVY;
					p.balanceFactory -= RIGHT_RIGHT_HEAVY;
				}else if(l.balanceFactory == BALANCED){//0 
					//l.balanceFactory = LEFT_HEAVY;
					//p.balanceFactory = BALANCED;
					l.balanceFactory -= RIGHT_HEAVY;
					p.balanceFactory -= RIGHT_HEAVY;
				}else {
					/*l.balanceFactory -= RIGHT_HEAVY;
					p.balanceFactory -= RIGHT_HEAVY;*/
				}
			}
			
		}
	}
	
	/**
	 * RR (    )
	 * 		p						r
	 * 		│			-> 			││
	 * 		└───r			    p───┘└───rr
	 * 			│
	 * 			└──rr
	 */
	private void type_rR(AVLNode p){
		AVLNode r = p.right;
		//AVLNode rr = r.right;
		
		if(p.parent == null){ //p  
			root = r;
			r.parent = null;
			p.right = r.left;
			r.left = p;
			p.parent = r;
			
			if(r.balanceFactory == LEFT_HEAVY){ //-1
				//r.balanceFactory = BALANCED;
				r.balanceFactory += RIGHT_HEAVY;
				p.balanceFactory += RIGHT_RIGHT_HEAVY;
			}else if(r.balanceFactory == BALANCED){//0
				//r.balanceFactory = RIGHT_HEAVY;
				//p.balanceFactory = BALANCED;
				r.balanceFactory += RIGHT_HEAVY;
				p.balanceFactory += RIGHT_HEAVY;
			}else {
				/*r.balanceFactory += RIGHT_HEAVY;
				p.balanceFactory += RIGHT_HEAVY;*/
			}
		}else{
			if(p == p.parent.left){
				p.parent.left = r;
			}else if(p == p.parent.right){
				p.parent.right = r;
			}
			r.parent = p.parent;
			p.right = r.left;
			r.left = p;
			p.parent = r;
			
			if(r.balanceFactory == LEFT_HEAVY){ //-1
				//r.balanceFactory = BALANCED;
				r.balanceFactory += RIGHT_HEAVY;
				p.balanceFactory += RIGHT_RIGHT_HEAVY;
			}else if(r.balanceFactory == BALANCED){//0
				//r.balanceFactory = RIGHT_HEAVY;
				//p.balanceFactory = BALANCED;
				r.balanceFactory += RIGHT_HEAVY;
				p.balanceFactory += RIGHT_HEAVY;
			}else {
				/*r.balanceFactory += RIGHT_HEAVY;
				p.balanceFactory += RIGHT_HEAVY;*/
			}
		}
	}
	/**
	 * LR (    (      ))
	 * 			p
	 * 			│			lr
	 * 		l───┘	-》 		││
	 * 		│			 l──┘└───p
	 * 		└───lr
	 * 
	 * @param p
	 */
	private void type_lR(AVLNode p, boolean isRemove){
		/*AVLNode l = p.left;
		AVLNode lr = l.right;
		
		type_rR(l);
		type_lL(p);
		if(isRemove){
			lr.balanceFactory += RIGHT_HEAVY;
		}*/
		
		AVLNode l = p.left;
		AVLNode lr = l.right;
		
		if(p.parent == null){ //  
			root = lr;
			
			l.right = lr.left;
			if(lr.left != null){
				lr.left.parent = l;
			}
			p.left = lr.right;
			if(lr.right != null){
				lr.right.parent = p;
			}
			
			lr.left = l;
			lr.right = p;
			
			l.parent = lr;
			p.parent = lr;
			
			lr.parent = null;
			
			if(lr.balanceFactory == RIGHT_HEAVY){ //1
				p.balanceFactory -= 3;
				l.balanceFactory += 1;
				lr.balanceFactory -= 1;
			}else if(lr.balanceFactory == BALANCED){//0
				p.balanceFactory -= 2;
				l.balanceFactory += 1;
			}else if(lr.balanceFactory == LEFT_HEAVY){//-1
				p.balanceFactory -= 2;
				l.balanceFactory += 2;
				lr.balanceFactory += 1;
			}
		}else{
			l.right = lr.left;
			if(lr.left != null){
				lr.left.parent = l;
			}
			p.left = lr.right;
			if(lr.right != null){
				lr.right.parent = p;
			}
			
			lr.left = l;
			lr.right = p;
			lr.parent = p.parent;
			if(p == p.parent.left){
				p.parent.left = lr;
			}
			if(p == p.parent.right){
				p.parent.left = lr;
			}
			
			l.parent = lr;
			p.parent = lr;
			
			
			if(lr.balanceFactory == RIGHT_HEAVY){ //1
				p.balanceFactory -= 3;
				l.balanceFactory += 1;
				lr.balanceFactory -= 1;
			}else if(lr.balanceFactory == BALANCED){ //0
				p.balanceFactory -= 2;
				l.balanceFactory += 1;
			}else if(lr.balanceFactory == LEFT_HEAVY){ //-1
				p.balanceFactory -= 2;
				l.balanceFactory += 2;
				lr.balanceFactory += 1;
			}
		}
		
	}
	/**
	 * RL (     (      ))
	 * 			p
	 * 			│			  	rl
	 * 			└──r	-》 		││
	 * 			   │		 p──┘└───r
	 * 	      rl───┘
	 * 
	 * @param p
	 */
	private void type_rL(AVLNode p, boolean isRemove){
		/*AVLNode r = p.right;
		AVLNode rl = r.left;
		
		type_lL(r);
		type_rR(p);
		if(isRemove){
			rl.balanceFactory -= RIGHT_HEAVY;
		}*/
		
		AVLNode r = p.right;
		AVLNode rl = r.left;
		if(p.parent == null){ //    
			root = rl;
			
			r.left = rl.right;
			if(rl.right != null){
				rl.right.parent = r;
			}
			p.right = rl.left;
			if(rl.left != null){
				rl.left.parent = p;
			}
			
			rl.left = p;
			rl.right = r;
			rl.parent = p.parent;
			
			p.parent = rl;
			r.parent = rl;
			
			
			if(rl.balanceFactory == RIGHT_HEAVY){ //1
				p.balanceFactory += 2;
				r.balanceFactory -= 2;
				rl.balanceFactory -= 1;
			}else if(rl.balanceFactory == BALANCED){
				p.balanceFactory += 2;
				r.balanceFactory -= 1;
			}else if(rl.balanceFactory == LEFT_HEAVY){
				p.balanceFactory += 3;
				r.balanceFactory -= 1;
				rl.balanceFactory += 1;
			}
		}else{
			r.left = rl.right;
			if(rl.right != null){
				rl.right.parent = r;
			}
			p.right = rl.left;
			if(rl.left != null){
				rl.left.parent = p;
			}
			
			rl.left = p;
			rl.right = r;
			rl.parent = p.parent;
			if(p == p.parent.left){
				p.parent.left = rl;
			}
			if(p == p.parent.right){
				p.parent.left = rl;
			}
			
			p.parent = rl;
			r.parent = rl;
			
			
			if(rl.balanceFactory == RIGHT_HEAVY){ //1
				p.balanceFactory += 2;
				r.balanceFactory -= 2;
				rl.balanceFactory -= 1;
			}else if(rl.balanceFactory == BALANCED){
				p.balanceFactory += 2;
				r.balanceFactory -= 1;
			}else if(rl.balanceFactory == LEFT_HEAVY){
				p.balanceFactory += 3;
				r.balanceFactory -= 1;
				rl.balanceFactory += 1;
			}
		}
		
	}
	
	//           
	private AVLNode getAVLNode(T data){
		if(root == null){
			return null;
		}
		AVLNode node = root;
		int compInt = 0;
		while(node != null){
			compInt = data.compareTo(node.data);
			if(compInt > 0){
				node = node.right;
			}else if(compInt < 0){
				node = node.left;
			}else{
				return node;
			}
		}
		return null;
	}
	//      
	public List breadthFirstSearch(){
		return cBreadthFirstSearch(root);
	}
	private List cBreadthFirstSearch(AVLNode node) {
		List nodes = new ArrayList();
		Deque deque = new ArrayDeque();
		if(node != null){
			deque.offer(node);
		}
		while(!deque.isEmpty()){
			AVLNode tmp = deque.poll();
			nodes.add(tmp);
			if(tmp.left != null){
				deque.offer(tmp.left);
			}
			if(tmp.right != null){
				deque.offer(tmp.right);
			}
		}
		return nodes;
	}
	public static void main(String[] args) {
		HeightBalanBinSearchTree tree = new HeightBalanBinSearchTree();
		tree.add(20);
		tree.add(23);
		tree.add(17);
		tree.add(19);
		tree.add(21);
		tree.add(26);
		tree.add(14);
		tree.add(18);
		tree.add(11);
		tree.add(16);
		tree.add(22);
		tree.add(24);
		tree.add(27);
		//tree.add(15);
		System.out.println( tree.breadthFirstSearch());
		
		tree.remove(17);
		System.out.println( tree.breadthFirstSearch());

	}
	
}
テスト結果:
[[BF=1,data=20], [BF=1,data=17], [BF=0,data=23], [BF=-1,data=14], [BF=1,data=19], [BF=-1,data=21], [BF=0,data=26], [BF=0,data=11], [BF=1,data=16], [BF=0,data=18], [BF=0,data=22], [BF=0,data=24], [BF=0,data=27], [BF=0,data=15]]
[[BF=0,data=20], [BF=0,data=16], [BF=0,data=23], [BF=0,data=14], [BF=1,data=19], [BF=-1,data=21], [BF=0,data=26], [BF=0,data=11], [BF=0,data=15], [BF=0,data=18], [BF=0,data=22], [BF=0,data=24], [BF=0,data=27]]