数据结构—二叉查找树

  查找树是一种数据结构,二叉查找树是按二叉树结构来组织的。可以用链表结构表示,其中每一个结点就是一个对象。结点中包括: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 }
原文地址:https://www.cnblogs.com/Jiaoxia/p/3879418.html