数据结构—二叉查找树

  查找树是一种数据结构,二叉查找树是按二叉树结构来组织的。可以用链表结构表示,其中每一个结点就是一个对象。结点中包括: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 }

数据结构—二叉查找树

时间: 2024-10-09 19:53:54

数据结构—二叉查找树的相关文章

数据结构——二叉查找树

使二叉树成为二叉查找树的性质是,对于树中的每个节点X,它的左子树中所有关键字值小于X的关键字值,而它的右子树中所有关键字值大于X的关键字值.这意味着,该树所有的元素以某种统一的方式排序. 二叉查找树的声明 二叉查找树是一棵特殊的二叉树,二叉查找树中节点的结构与二叉树种节点的结构相同,关键在于可以在二叉查找树上可以执行的操作以及对其进行操作的算法.二叉查找树的声明如下: #ifndef  _Tree_H struct TreeNode; typedef struct TreeNode *Posit

数据结构-二叉查找树

前序遍历: 后序遍历: 二叉查找树按照二叉树进行组织.二叉查找树关键字的存储方式总是瞒住二叉查找树性质: 设x为二查查找树种一个节点.如果y是x的左子树中的一个节点,那么key[x] >= key[y].如果y是x的右子树的一个节点,那么key[x] <= key[y]. 这样对二叉查找树进行中序遍历就可得到书中所有元素的一个非降序排列. 查找某一个存在节点的前驱和后继.某一个节点x的后继就是大于key[x]的关键字中最小的那个节点,前驱就是小于key[x]的关键字中最大的那个节点.查找二叉前

JAVA数据结构--二叉查找树

二叉查找树定义 二叉查找树(英语:Binary Search Tree),也称二叉搜索树.有序二叉树(英语:ordered binary tree),排序二叉树(英语:sorted binary tree),是指一棵空树或者具有下列性质的二叉树: 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值: 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值: 任意节点的左.右子树也分别为二叉查找树: 没有键值相等的节点. 二叉查找树相比于其他数据结构的优势在于查找.插入

Java数据结构-二叉查找树续以及平衡二叉查找树

??前面一篇文章讲到了二叉查找树的实现,其中的插入操作是使用非递归方法实现的,这里再增加一种递归实现插入的操作,Java代码如下,建议增加到前一篇文章对应的FOBinarySearchTree.java中: /** * @TODO 二叉排序树插入元素(递归方法) * @param e 需要插入的元素 * @return true or false */ public boolean insert(E e){ insert(root,e); return true; } /** * @TODO 二

数据结构--二叉查找树的java实现

上代码: package com.itany.erchachazhaoshu; public class BinarySearchTree<T extends Comparable<? super T>> { //定义二叉查找树的根节点 每一个查找二叉树都有一个自己的root 节点 root外界看不到 private BinaryNode<T> root; public BinarySearchTree() { root=null; } //节点类 private st

C++数据结构====二叉查找树

C++二叉查找树:Binary Search tree 二叉查找树默认左子树的值都比根节点小,右子树都比根节点大,这个定义排除了树中存在值相同节点的可能性.这便是二叉查找树称为一个用关键值KEY快速查找的工具. 二叉树类: class bst { struct Node { T data; Node* L; Node* R; Node(const T& d):data(d),L(),R(){} Node(const T& d,Node* L,Node* R):data(d),L(L),R(

数据结构|-二叉查找树(二叉搜索树)的链式存储结构的实现

二叉排序树,又称为二叉查找树. 它或者是一棵空树,或者是具有下列性质的二叉树. 若它的左子树不为空,则左子树上所有的结点的值均小于根结构的值: 若它的右子树不为空,则右字数上所有结点的值均大于它的根结点的值: 它的左右子树也分别为二叉排序树. 优点: 1,排序方便 2,方便查找 3,方便插入和删除 二叉排序树的插入数据: 因为二叉排序树中所有的数都符合排序树的特点,所以任意插入一个数时,都能在遍历树的过程中找到其应该放置的正确位置 二叉排序树的删除数据: 三种情况: 1,叶子结点:直接删除该叶子

详解二叉查找树(BST)

详解二叉查找树(BST) 本篇随笔简单讲解一下数据结构--二叉查找树(\(Binary\,\,Sort\,\,Tree,BST\)),(后文的"二叉查找树"一词均用\(BST\)代替). BST的概念 首先,\(BST\)是一棵二叉树. 它的定义是,根节点左子树全部严格小于根节点,右子树大于等于根节点,并且,左右子树都是\(BST\). 很好理解,很明朗很简单的定义. 可以看出,这是一个通过递归方式定义的数据结构,所以,它的诸多操作自然要用到递归. BST的功能 我们可以看出来,这个二

查找与二叉树

查找与二叉树 我家园子有几棵树系列 查找与二叉树 我家园子有几棵树系列 Preface 查找 二叉查找树的实现 定义数据结构 中序遍历 查找操作 插入 删除 删除最小值 复制(拷贝)删除 步骤 Rank 2-3查找树 总结 Preface 前面我们学习了基于线性表的数据结构,如数组,链表,队列,栈等.现在我们要开始学习一种非线性的数据结构--树(tree),是不是很兴奋呢!让我们开始新的系列吧! 查找 先让我们回忆一下线性表的查找,首先最暴力的方法就是做一个线性扫描,一一对比是不是要找的值.这么