首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

算法研究系列-二叉查找树

2012-10-09 
算法研究系列---二叉查找树查找树以便于查找的方式来存放数据,尤其是二叉查找树,二叉查找树的特性使其可以

算法研究系列---二叉查找树

查找树以便于查找的方式来存放数据,尤其是二叉查找树,二叉查找树的特性使其可以使用简单的递归算法进行查找,这种算法在思路上类似于数组的折半查找,且同样高效.

?

?二叉查找树是其节点含有Comparable的对象,并且按如下组织的二叉树:

? ? ? ? ? ? 1:节点的数据大于节点的左子树中的数据。

? ? ? ? ? ? 2:节点的数据小于节点的右子树中的数据。

?

下面着重讨论如何基于java实现二叉查找树 并实现 诸如:插入,查找,删除,遍历等方法

?

?

package tree;public class BinaryTree {// Root node pointer. Will be null for an empty tree.   private Node root;    /*    --Node--    The binary tree is built using this nested node class.    Each node stores one data element, and has left and right    sub-tree pointer which may be null.    The node is a "dumb" nested class -- we just use it for    storage; it does not have any methods.   */   private static class Node {     Node left;     Node right;     int data;    Node(int newData) {       left = null;       right = null;       data = newData;     }   }    public BinaryTree() { root = null;  }    /**    Returns true if the given target is in the binary tree.    Uses a recursive helper.   */   public boolean lookup(int data) {     return(lookup(root, data));   }   /**    Recursive lookup  -- given a node, recur    down searching for the given data.   */   private boolean lookup(Node node, int data) {     if (node==null) {       return(false);     }    if (data==node.data) {       return(true);     }     else if (data<node.data) {       return(lookup(node.left, data));     }     else {       return(lookup(node.right, data));     }   }    /**    Inserts the given data into the binary tree.    Uses a recursive helper.   */   public void insert(int data) {     root = insert(root, data);   }     /**   Remove the given data into the binary tree   Uses a recursive helper   */  public void remove(int data){  remove(root, data);  }    private Node remove(Node node, int data) {  if(node == null) {  return null;  }  if(data < node.data) {  node.left = remove(node.left,data);  } else if(data > node.data) {  node.right = remove(node.right,data);  } else{  if(node.left != null && node.right != null) {    node.data = findMax(node.right).data;    node.right = removeMax(node.right);  } else {  node = ((node.left == null) ? node.right:node.left);   }  }  return node;  }    private Node removeMax(Node node) {  if(node != null) {  if(node.right != null) {  removeMax(node.right);  } else {  node = node.left;  }  }  return node;  }    private Node findMax(Node node) {  if(node != null) {  while(node.right != null) {  node = node.right;  }  }  return node;  }    private Node remove2(Node node, int data) {   if(node == null) {   return node;   }      if(node.data < data) {   node.right = remove2(node.right,data);   } else if(node.data > data) {   node.left = remove2(node.left,data);   } else {   if(node.left != null && node.right != null) {    node.data = findMin(node.left).data;    node.left = removeMin(node.left);  } else {  node = ((node.left == null) ? node.right:node.left);   }   }   return node;  }    private Node removeMin(Node node) {  if(node != null) {  if(node.left != null) {  removeMin(node.left);  } else {  node = node.right;  }  }  return node;  }    private Node findMin(Node node) {  if(node != null) {  while(node.left != null) {  node = node.left;  }  }  return node;  }     private Node insert(Node node, int data) {     if (node==null) {       node = new Node(data);     }     else {       if (data <= node.data) {         node.left = insert(node.left, data);       }       else {         node.right = insert(node.right, data);       }     }    return(node);  }     /**   * 中序历遍   */  public void inOrderTraverse() {  inOrderTraverse(root);  }    /**   * 先序历遍   */  public void preOrderTraverse(){  preOrderTraverse(root);  }    /**   * 后序历遍   * @param node   */  public void lastOrderTraverse(){  lastOrderTraverse(root);  }    private void lastOrderTraverse(Node node){  if(node != null) {  lastOrderTraverse(node.left);    lastOrderTraverse(node.right);  System.out.print(node.data + " ");  }  }    private void preOrderTraverse(Node node){  if(node != null) {  System.out.print(node.data + " ");  preOrderTraverse(node.left);    preOrderTraverse(node.right);  }  }    private void inOrderTraverse(Node node) {  if(node == null) {  return;  }  inOrderTraverse(node.left);    System.out.print(node.data + " ");  inOrderTraverse(node.right);   }}

?

?

package test;

import tree.BinaryTree;public class TestBinaryTree {/** * @param args */public static void main(String[] args) { BinaryTree biTree=new BinaryTree();       int[] data={2,1,3,5,4,55,1245};              for(int i=0; i < data.length; i++) {       biTree.insert(data[i]);       }              biTree.preOrderTraverse();       System.out.println();              biTree.insert(5);              biTree.preOrderTraverse();       System.out.println();              biTree.remove(2);              biTree.inOrderTraverse();       System.out.println();       }}
?

?

上述代码实现了一颗二叉查找树,并提供了插入,删除,遍历,查找节点的操作,下面一一解释各操作:

?

插入: ?往二叉查找树中插入元素是一个基本操作,因为它正是建树时的基本操作。假设已有一颗二叉查找树,如要往其中插入一个新元素,首先必须要确保节点间的相互关系,即需要保证插入元素后的树仍是一颗二叉查找树,并且须保证方法lookup能找到这个元素,同时,每次的插入操作都是给这棵树加上一个新的叶子节点.

?

遍历,查找:这两个操作比较简单,采用递归方式,具体实现如代码.

?

删除: ?删除操作可以说是最复杂的一个了,为了从二叉查找树中删除元素,需要将与之相匹配的元素传递给方法remove,待删除的元素随后从树中删除并返回, 如果不存在这样的元素则返回null

? ? 但是删除元素时,不是简单的删除就可以了,这里需要看待删除的元素的左右孩子的情况:

? ? ? ? ?1:节点没有孩子,为叶子节点

?2: 该节点有一个孩子

? ? ? ? ?3:该节点有两个孩子

?

第一种情况是最简单的,同时第二种情况也不难,只需要将该节点的一个孩子取代这个节点就可以了,这两种情况的处理可以合二为一,具体实现如代码所示

?

下面考虑节点有两个孩子的情况:

?

? ? ? 假设待删除的节点为N,但现在N有两个孩子,如果试图删除它,就会留下两个没有双亲的孩子,尽管节点N可以被其中一个所取代,但总会有一个孩子没有双亲,即总有一个孩子没有被引用,所以删除节点N 的办法是不可行的.

? ? ?实际上,并不是非得删除节点N才能删除其中的元素,这里,不防寻找一个容易删除的节点,我们称为A,这个节点A只有一个孩子或者没有孩子,然后将节点N中的元素用A中的元素替代,随后删除节点A,并使树中仍然还有正确的元素,但是这里的一个问题,如何确定这个节点A,并保证树仍然为二叉查找树呢? 显然,节点A是不可以随便选择的,它必须有可以合法的替代节点N中的元素的条件。

? ? ? 假设e为N中的元素,因为节点N有两个孩子,则e不可能是树中最小的元素,也不可能是最大元素,(为了讨论方便,假设树中没有重复元素), ?并且书中没有重复的元素,若树中元素升序排列,所以有:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ...a<e<b...(a,b为节点N左右孩子的元素)

由于a为节点N的左子树中的元素,b为节点N右子树中的元素,且有上述关系,我们可以想到 a将是N左子树中最大的元素,b是右子树中最小的元素。现假定删除了还有a的节点X,并用a替代e,那么现在N的左子树中所有剩下的元素都小于a,满足所需条件,而且N的右子树中的所有的元素都大于e,从而也大于a,因此该树仍是二叉查找树.

?

? ? 那么如何寻找元素a呢? ? 假设以上论述能够找到适当的俄元素a,所以现在应寻找含有a的节点并且确认他没有两个孩子,为了找到比任一个指定节点中的元素更大的元素,需要查看这个节点的右孩子,因此,a位于这颗子树最右侧的节点R中, 节点R不可能有右孩子,因为如果他有的话,该孩子的元素就会大于a,因此节点R的孩子不可能多余一个,可以很容易的删除它。

?

下面总结上述讨论(由于节点N的右子树情况类似于左子树,不过右子树中我们只要找右子树中最左侧的节点就可以了):

?

? ? ?1: 删除位于有两个孩子的节点N中的元素e

? ? ? ? ? 找到N的左子树中最右侧的节点R

? ? ? ? ? 以节点R中的元素替代节点N的元素

? ? ? ? ? 删除节点R

?

? ? ?2:?删除位于有两个孩子的节点N中的元素e

? ? ? ? ? ?找到N的右子树中最左侧的节点L,

? ? ? ? ? ?以节点L中的元素替代节点N的元素,

? ? ? ? ? ?删除节点L

?

?

?

?

?

?

?

?

?

?

?

热点排行