• 数据结构—二叉查找树


      查找树是一种数据结构,二叉查找树是按二叉树结构来组织的。可以用链表结构表示,其中每一个结点就是一个对象。结点中包括: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                 else
    10                     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 =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 Exception
    100       {
    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 Exception
    121       {
    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               else
    161               {
    162                   return;//书中已存在与新结点的关键字相同的结点
    163               }
    164           }
    165           newNode.parent = parentNode;
    166           if(newNode.key < parentNode.key)
    167           {
    168               parentNode.leftChild = newNode;   
    169           }
    170           else
    171           {
    172                 parentNode.rightChild = newNode;
    173           }              
    174        }
    175     public boolean  IsEmpty()
    176     {
    177         if(root == null)
    178         {
    179             return true;
    180         }
    181         else
    182         {
    183             return false;
    184         }
    185     }
    186     public void  TreeEmpty() throws Exception
    187     {
    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 | Templates
    225  * and open the template in the editor.
    226  */
    227 package agrith;
    228 
    229 import javax.swing.tree.TreeNode;
    230 
    231 /**
    232  *
    233  * @author ning
    234  */
    235 public class TreeMain {
    236     public static  void main(String [] args) throws Exception
    237     {
    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 Exception
    266     {
    267         System.out.println("本结点: " + pNode);  
    268         System.out.println("前趋结点: " + BiTree.Tree_precessor(pNode));  
    269         System.out.println("后继结点: " + BiTree.Tree_Successor(pNode));  
    270     }
    271     
    272 }
  • 相关阅读:
    【转】DOS命令大全(远程命令)
    system CPU占用率过高与91助手的关系
    要像管理咨询一样去做软件需求调研
    近两个月工作日志
    ECSHOP:首页实现显示子分类商品,并实现点击Tab页切换分类商品
    奋战5个小时解决诡异的PHP“图像XX因其本身有错无法显示”的问题
    SVN强制添加日志出现E205000错误解决方法
    pdf文件之itextpdf操作实例
    验证码实例
    Struts2拦截器记录系统操作日志
  • 原文地址:https://www.cnblogs.com/Jiaoxia/p/3879418.html
Copyright © 2020-2023  润新知