首页 > 代码库 > 数据结构—二叉查找树

数据结构—二叉查找树

  查找树是一种数据结构,二叉查找树是按二叉树结构来组织的。可以用链表结构表示,其中每一个结点就是一个对象。结点中包括:key、数据、left、right、p。其中left、right和p分别指向左儿子,右儿子和父结点。

  二叉查找树中的关键字总是满足二叉查找树的性质:y是x左子树上的结点,则key[y]≤key[x],如果y是x右子树上的结点,则key[y]≥key[x]。

  遍历:

  根据二叉查找树的性质,可以用一个递归算法按排列顺序输出树中的所有关键字。这种是中序遍历算法:因为一子树根的关键字在输出时介于左子树和右子树的关键字之间。那么,根据根所在的不同位置,还有前序遍历和后序遍历。

 1 //中序递归遍历二叉树 2     public void Inorder_Tree_Walk(TreeNode root) 3     { 4         if(root!=null) 5         { 6             Inorder_Tree_Walk(root.leftChild); 7             nodeList.add(root); 8             Inorder_Tree_Walk(root.rightChild); 9         }10         11         12     }

  查询:

  在树中查找给定的关键字。下面代码从树的根节点开始进行查找,并沿着树下降。碰到节点x就比较节点x的key与给定k值比较。如果相同,则查找结束。如果k小于key[x],则继续查找x的左子树,根据二叉查找树的性质可知,k不可能在x的右子树中。对称地,如果k大于key[x],则继续查找x 的右子树。运行时间是O(lgn)。

 1 //查找给定关键字k 2         public TreeNode Tree_Seach(int key) 3         { 4             TreeNode pNode = root; 5             while(pNode!=null && pNode.key != key) 6             { 7                 if (key<pNode.key) 8                     pNode = pNode.leftChild; 9                 else10                     pNode = pNode.rightChild;11             }12             return pNode;  13         }

  最大最小关键字:

  要查找二叉树中的最小关键字元素,只要从根节点开始,沿着各结点的left指针查找下去,直到遇到null为止,而要找到最大关键字元素,就沿着各节点right指针查找。 

  public TreeNode Tree_Minimum(TreeNode node) throws Exception        {            if(node == null)            {                throw new Exception("树为空");            }            TreeNode pNode  = node;            while(pNode.leftChild != null)            {                pNode = pNode.leftChild;            }            return pNode;        }        public  TreeNode Tree_Maximum(TreeNode node)throws Exception        {            if(node == null)            {                throw new Exception("树为空");            }            TreeNode pNode = node;            while(pNode.rightChild != null)            {                pNode = pNode.rightChild;            }            return pNode;        }      

  前趋和后继

    给定一个二叉查找树中的结点,要求找出中序遍历下它的后继。就是:某结点x的后继,具有大于key[x]中的关键字中最小者的结点。根据二叉查找树的结构,不用进行比较就可以找到结点的后继。

    后继:一、如果x的右子树不空,后继就是右子树中最小值。二、如果x的右子树为空,则x的后继是x的最低祖先结点,且后继的左儿子是x的祖先。如下代码:

public TreeNode Tree_Successor(TreeNode node) throws Exception      {          if(node == null)          {              return null;          }          TreeNode pNode = node;          //若右子树不空,则为右子树中最小的关键字          if(pNode.rightChild != null)          {              return Tree_Minimum(pNode.rightChild);          }          TreeNode parentNode = node.parent;          //若右子树为空,且x有一个后继y.则y是x的最低祖先结点,且y的左儿子也是x的祖先          while(parentNode != null && pNode == parentNode.rightChild)          {              pNode = parentNode;              parentNode = pNode.parent;           }          return parentNode;           }

  前驱:前驱和后继是对称的。一、如果x的左子树不空,前驱就是左子树中最大值。二、如果x的左子树为空,则x的前驱是x的最低祖先结点,且前驱的左儿子是x的祖先。

public TreeNode precessor(TreeNode node) throws Exception      {          TreeNode pNode = node;          TreeNode parentNode = pNode.parent;          if(pNode == null)          {              return null;          }          if(pNode.leftChild != null)          {              return Tree_Maximum(pNode.leftChild);          }          while(parentNode != null && pNode == parentNode.leftChild)          {              pNode = parentNode;              parentNode = parentNode.parent;          }          return parentNode;      }

 插入:将新的元素v插入树中,可以调用Tree_Insert过程。该过程的输入参数是一个结点z,且key[z] = v,z.leftChild = null,z.rightChild = null。该过程修改树T和z的域,并把z插入到树中适当的位置。运行时间为O(lgn)

  

public void insert(int key)      {          TreeNode parentNode = null;          TreeNode newNode = new TreeNode(key, "v", null, null, null);          TreeNode pNode = root;          if(root == null)          {              root = newNode;              return ;          }          while(pNode != null)          {              parentNode = pNode;              if(key < pNode.key)              {                  pNode = pNode.leftChild;              }              else if(key > pNode.key)              {                  pNode = pNode.rightChild;                                }              else              {                  return;//书中已存在与新结点的关键字相同的结点              }          }          newNode.parent = parentNode;          if(newNode.key < parentNode.key)          {              parentNode.leftChild = newNode;             }          else          {                parentNode.rightChild = newNode;          }                     }

删除:将给定结点z从二叉查找树中删除的过程:一、如果z没有子女,则修改其父节点z.parent,使其子女为空;二、如果z只有一个子女,则可以通过在其子结点和父节点之间建立一条链来删除z。三、如果z有两个子女,先删除z的后继y(y没有子女),再用y的内容代替z的内容。运行时间为O(lgn)。

  

  public  void Delete(int key) throws  Exception      {        TreeNode pNode = Tree_Seach(key);        if(pNode == null)        {            throw new Exception("树中不存在要删除的关键字!");        }        Tree_Delete(pNode);                }      private  void Tree_Delete(TreeNode pNode) throws Exception      {          if(pNode == null)          {              return ;          }          TreeNode parentNode = pNode.parent;          if(pNode.leftChild == null && pNode.rightChild == null)          {              if(parentNode.leftChild == pNode)              {                  parentNode.leftChild = null;               }              else              {                  parentNode.rightChild = null;              }              return;                       }          if(pNode.leftChild == null && pNode.rightChild != null)          {              if(pNode == parentNode.leftChild)              {                  parentNode.leftChild = pNode.rightChild;                  pNode.rightChild.parent = parentNode;              }              else              {                  parentNode.rightChild = pNode.rightChild;                  pNode.rightChild.parent = parentNode;              }              return;          }          if(pNode.leftChild != null && pNode.rightChild == null)          {              if(pNode == parentNode.leftChild)              {                  parentNode.leftChild = pNode.leftChild;                  pNode.leftChild.parent = parentNode;              }              else              {                  parentNode.rightChild = pNode.leftChild;                  pNode.leftChild.parent = parentNode;              }              return;          }                  //左右儿子都不为空,就删除后继,让后继的内容,代替当前内容          TreeNode successorNode = Tree_Successor(pNode);          pNode.key = successorNode.key;          pNode.data = successorNode.data;          Tree_Delete(successorNode);      }

 程序实现:

  

  1 package agrith;  2   3 import java.util.List;  4 import java.util.ArrayList;  5   6 public class BiSeachTree {      7      class TreeNode{  8         private int key;  9         private String data; 10         private TreeNode leftChild; 11         private TreeNode rightChild; 12         private TreeNode parent; 13          14         public TreeNode(int key,String data,TreeNode leftChild,TreeNode rightChild,TreeNode parent) 15         { 16              17             this.key = key; 18                         this.data =http://www.mamicode.com/data; 19             this.leftChild = leftChild; 20             this.rightChild = rightChild; 21             this.parent = parent; 22         } 23         public int getKey() 24         { 25             return key; 26         } 27         public String toString() 28         { 29             String leftKey = (leftChild == null?" ":String.valueOf(leftChild.key)); 30             String rightKey = (rightChild == null?" ":String.valueOf(rightChild.key)); 31             return "("+leftKey+","+key+","+rightKey+")"; 32         }     33     } 34      35     private TreeNode root = null; 36     private List<TreeNode> nodeList = new ArrayList<TreeNode>(); 37      38     //获取中序二叉树列表 39     public List<TreeNode> Inorder_Tree_WalkList() 40     { 41          42         if(nodeList != null ) 43         { 44             nodeList.clear(); 45         } 46         Inorder_Tree_Walk(root); 47         return nodeList; 48          49     } 50     //中序递归遍历二叉树 51     public void Inorder_Tree_Walk(TreeNode root) 52     { 53         if(root!=null) 54         { 55             Inorder_Tree_Walk(root.leftChild); 56             nodeList.add(root); 57             Inorder_Tree_Walk(root.rightChild); 58         }         59     } 60         //查找给定关键字k 非递归版本运行的快 61         public TreeNode Tree_Seach(int key) 62         { 63             TreeNode pNode = root; 64             while(pNode!=null && pNode.key != key) 65             { 66                 if (key<pNode.key) 67                     pNode = pNode.leftChild; 68                 else 69                     pNode = pNode.rightChild; 70             } 71             return pNode;   72         } 73          public TreeNode Tree_Minimum(TreeNode node) throws Exception 74         { 75             if(node == null) 76             { 77                 throw new Exception("树为空"); 78             } 79             TreeNode pNode  = node; 80             while(pNode.leftChild != null) 81             { 82                 pNode = pNode.leftChild; 83             } 84             return pNode; 85         } 86         public  TreeNode Tree_Maximum(TreeNode node)throws Exception 87         { 88             if(node == null) 89             { 90                 throw new Exception("树为空"); 91             } 92             TreeNode pNode = node; 93             while(pNode.rightChild != null) 94             { 95                 pNode = pNode.rightChild; 96             } 97             return pNode; 98         }      99       public TreeNode Tree_Successor(TreeNode node) throws Exception100       {101           if(node == null)102           {103               return null;104           }105           TreeNode pNode = node;106           //若右子树不空,则为右子树中最小的关键字107           if(pNode.rightChild != null)108           {109               return Tree_Minimum(pNode.rightChild);110           }111           TreeNode parentNode = node.parent;112           //若右子树为空,且x有一个后继y.则y是x的最低祖先结点,且y的左儿子也是x的祖先113           while(parentNode != null && pNode == parentNode.rightChild)114           {115               pNode = parentNode;116               parentNode = pNode.parent;117            }118           return parentNode;  119       }120       public TreeNode Tree_precessor(TreeNode node) throws Exception121       {122           TreeNode pNode = node;123           TreeNode parentNode = pNode.parent;124           if(pNode == null)125           {126               return null;127           }128           if(pNode.leftChild != null)129           {130               return Tree_Maximum(pNode.leftChild);131           }132           while(parentNode != null && pNode == parentNode.leftChild)133           {134               pNode = parentNode;135               parentNode = parentNode.parent;136           }137           return parentNode;138       }139       public void Tree_Insert(int key)140       {141           TreeNode parentNode = null;142           TreeNode newNode = new TreeNode(key, "v", null, null, null);143           TreeNode pNode = root;144           if(root == null)145           {146               root = newNode;147               return ;148           }149           while(pNode != null)150           {151               parentNode = pNode;152               if(key < pNode.key)153               {154                   pNode = pNode.leftChild;155               }156               else if(key > pNode.key)157               {158                   pNode = pNode.rightChild;                  159               }160               else161               {162                   return;//书中已存在与新结点的关键字相同的结点163               }164           }165           newNode.parent = parentNode;166           if(newNode.key < parentNode.key)167           {168               parentNode.leftChild = newNode;   169           }170           else171           {172                 parentNode.rightChild = newNode;173           }              174        }175     public boolean  IsEmpty()176     {177         if(root == null)178         {179             return true;180         }181         else182         {183             return false;184         }185     }186     public void  TreeEmpty() throws Exception187     {188         if(IsEmpty())189         {190             throw new Exception("树空异常!");191         }192     }193     //返回二叉查找树的关键字的有序链表194     public String toStringofOrderList(){195         StringBuilder sbBuilder = new  StringBuilder("[");196         for(TreeNode p :Inorder_Tree_WalkList())197         {198             sbBuilder.append(p.key);199             sbBuilder.append(" ");200         }201         sbBuilder.append("]");202         return sbBuilder.toString();203     }204     //返回二叉查找树的字符串表示205     public  String toString()206     {207         StringBuilder sbBuilder = new StringBuilder("[");208         for(TreeNode p:Inorder_Tree_WalkList())209         {210             sbBuilder.append(p);211             sbBuilder.append(" ");212         }213         sbBuilder.append("]");214         return sbBuilder.toString();215     }216     public TreeNode getRoot()217     {218         return root;219     }220 }221 222 223 /*224  * To change this template, choose Tools | Templates225  * and open the template in the editor.226  */227 package agrith;228 229 import javax.swing.tree.TreeNode;230 231 /**232  *233  * @author ning234  */235 public class TreeMain {236     public static  void main(String [] args) throws Exception237     {238         try{239         BiSeachTree biTree = new BiSeachTree();240         System.out.println("二叉树是否为空?" + (biTree.IsEmpty()?"是":"否"));241         int [] keys = new int[]{ 15, 6, 18, 3, 7, 13, 20, 2, 9, 4 };242         for(int key:keys)243         {244             biTree.Tree_Insert(key);245         }246         System.out.println("二叉树是否为空?" + (biTree.IsEmpty()?"是":"否"));247         BiSeachTree.TreeNode minTreeNode = biTree.Tree_Minimum(biTree.getRoot());248         System.out.println("最小关键字:"+minTreeNode.getKey());249         BiSeachTree.TreeNode maxTreeNode = biTree.Tree_Maximum(biTree.getRoot()); 250         System.out.println("最大关键字:"+maxTreeNode.getKey());251         test(biTree, maxTreeNode);252         System.out.println("根结点的关键字:"+biTree.getRoot().getKey());253         TestTraverse(biTree);254         }catch(Exception e)255         {256             System.out.println(e.getMessage());257             e.printStackTrace();258         }259     }260     public static void TestTraverse(BiSeachTree biTree)261     {262         System.out.println("遍历二叉树:" + biTree );263         System.out.println("二叉树转化为有序链表:"+ biTree.toStringofOrderList());264     }265     public static  void test(BiSeachTree BiTree,BiSeachTree.TreeNode pNode) throws Exception266     {267         System.out.println("本结点: " + pNode);  268         System.out.println("前趋结点: " + BiTree.Tree_precessor(pNode));  269         System.out.println("后继结点: " + BiTree.Tree_Successor(pNode));  270     }271     272 }