博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
二叉搜索树的实现
阅读量:3968 次
发布时间:2019-05-24

本文共 6917 字,大约阅读时间需要 23 分钟。

二叉搜索树

定义
  • 若任意节点的左子树不空,则左子树上的所有节点的值均小于它的根节点的值;

  • 若任意节点的右子树不空,则右子树上的所有节点的值均大于它的根节点的值;

  • 任意节点的左子树,右子树也分别为二叉查找树

  • 节点的值不能相同

  1. 如果节点的值存的是key,则key是不允许重复的
  2. 如果节点的值存的是key-value键值对,则key是不允许重复的,value是允许重复的。
  • 二叉搜索树的中序遍历是有许的
常见API实现(节点存的是key为例)
insert()

二叉搜索树的插入本质来说是插入到叶子节点上

  1. 如果是空树,让树的根节点指向要插入的新节点
  2. 查找合适的位置,插入元素(模拟查找过程),一个引用current标记查找节点,一个引用parentCurrent标记查找节点的父节点
  3. 用待插入的值和根节点进行比较
  4. 待插入的值和根节点相等,就插入失败(因为二叉搜索树不允许节点的值重复)
  5. 待插入的值比根节点的值小,就去根节点左子树找
  6. 待插入的值比根节点的值大,就去根节点右子树找
  7. 依次再比较待查找元素和左子树/右子树根节点的值,再去递归找左子树和右子树
  8. 循环结束current就指向null,当前元素要插入到parentCurrent的子树位置
  9. 在比较是插入到左子树还是右子树
  10. 待插入值小于parentCurrent的值,就插入到左子树
  11. 待插入值大于parentCurrent的值,就插入到右子树

**时间复杂度:**O(n)当整棵树退化为链表

search()

根据二叉搜索树的特性查找,避免了遍历整个树

  1. 用待查找的值和根节点值进行比较
  2. 待查找的值和根节点的值相等,说明找到返回true
  3. 待查找的值小于根节点的值,则去根的左子树去查找
  4. 待查找的值大于根节点的值,则去根节点的右子树去查找
  5. 依次再比较待查找元素和左子树/右子树根节点的值,再去递归找左子树和右子树
  6. 遍历到叶子节点,如果没有找到就返回false

**时间复杂度:**O(n) 当整棵树退化为链表

remove()
  1. 先查找待删除的值是否存在,存在再删除,不存在就删除失败
  2. 查找过程
  3. 用待删除的值和根节点进行比较
  4. 待删除的值和根节点的值比较
  5. 待删除的值和根节点的值相等,然后进行删除操作
  6. 待删除的值小于根节点的值,则去根节点的左子树查找
  7. 待删除的值大于根节点的值,则去根节点的右子树查找
  8. 依次在比较待删除值和左子树/右子树根节点的值,迭代下去
  9. 待删除的值存在,进行删除操作
  10. 分情况:
  11. 删除的是叶子节点
    1. 只有一个节点的树,直接让让根节点指向null
    2. 删的是父节点的左孩子
    3. 删的父节点的右孩子
  12. 删除的只有左或右子树的节点
    1. 删的是只有左子树的节点
      1. 删除的跟节点
      2. 删除的是父节点的左孩子
      3. 删除的父节点的右孩子
    2. 删的是只有右子树的节点
      1. 删除的根节点
      2. 删除的是父节点的左孩子
      3. 删除的是父节点的右孩子
  13. 删除的是有左和右子树的节点(替换法删除)
    • 方法1-替换最大值
      1. 找待删除节点左子树的最大值(替罪羊)-左子树的最右端
      2. 替换-待删除节点值替换为左子树的最大值(替罪羊)
      3. 删除左子树的最大值(替罪羊)-类似删除只有左子树的节点情况
    • 方法2-替换最小值
      1. 找待删除节点右子树的最小值(替罪羊)-右子树的最左端
      2. 替换-待删除节点值替换为右子树的最小值(替罪羊)
      3. 删除右子树的最小值(替罪羊)-类似删除只有右子树的情况

**时间复杂度:**O(n) 当整棵树退化为链表

实现

TreeNode类
public class TreeNode {
Integer key; TreeNode left; TreeNode right; public TreeNode(Integer key){
this.key=key; }}
BinarySearchTree类
public class BinarySearchTree {
TreeNode root; public BinarySearchTree(){
this.root=null; } //中序遍历作为打印验证 public void inOrder(TreeNode root){
if (root==null){
return; } inOrder(root.left); System.out.print(root.key+" "); inOrder(root.right); } public void insert(Integer key){
if(this.root==null){
this.root=new TreeNode(key); return; } //标识current的父节点 TreeNode parentCurrent=null; //current寻找插入位置 TreeNode current=this.root; int cmp=0; while (current!=null){
cmp=key.compareTo(current.key); if (cmp==0){
throw new RuntimeException("二叉搜索树不允许相同的key值"); }else if (cmp<0){
//往左插 parentCurrent=current; current=current.left; }else{
parentCurrent=current; current=current.right; } } TreeNode node=new TreeNode(key); if (cmp<0){
parentCurrent.left=node; }else{
parentCurrent.right=node; } } public boolean search(Integer key){
if (this.root==null){
return false; } TreeNode current=this.root; while (current!=null){
int cmp=key.compareTo(current.key); if (cmp==0){
return true; }else if(cmp<0){
current=current.left; }else{
current=current.right; } } return false; } /* * 1.删除的是叶子节点 * 2.删除的是有一个孩子的节点 * 3.删除的是有两个孩子的节点(替换删除) * 选择作左子树中最大的或者右子树中最小的 * * */ public boolean remove(Integer key) {
if(this.root==null){
return false; } //查找 TreeNode parent=null; TreeNode current=this.root; while (current!=null){
int cmp=key.compareTo(current.key); if (cmp==0){
//删除 removeInternal(current,parent); return true; }else if(cmp<0){
parent=current; current=current.left; }else{
parent=current; current=current.right; } } return false; } private void removeInternal(TreeNode node, TreeNode parent) {
//删除的是叶子节点 if(node.left==null&&node.right==null){
if(this.root==node){
//说明只有一个节点的树 this.root=null; }else if (parent.left==node){
//删左孩子则去除 parent.left=null; }else{
//删有孩子则去除 parent.right=null; } }else if(node.left!=null&&node.right==null){
//删除只有左子树的节点 if(this.root==node){
this.root=node.left; }else if (node==parent.left){
parent.left=node.left; }else{
parent.right=node.left; } }else if(node.left==null&&node.right!=null){
//删除只有右子树的节点 if(root==node){
root=node.right; }else if(node==parent.left){
parent.left=node.right; }else{
parent.right=node.right; } }else if(node.left!=null&&node.right!=null){
//方法1-替换最大值 //找待删除节点左子树中的最大值(替罪羊)-左子树的最右端 /* * 为什么找左子树的最大值? * 左子树的最大值和待删除节点一替换,仍然满足二叉搜索树的性质 * 左孩子小于根节点,右孩子大于根节点 * */ //从左孩子开始一直向右走到尽头 TreeNode maxParent=node; TreeNode max=node.left; while (max.right!=null){
maxParent=max; max=max.right; } //替换-把替罪羊的值赋给待删除的节点 node.key=max.key; //删除替罪羊节点max(替罪羊节点一定没有右子树) //类似删除的只有左孩子的情况 if (maxParent.left==max){
maxParent.left=max.left; }else{
maxParent.right=max.left; } //方法2-替换最小值(和替换最大值同理) //找右子树的最小值(替罪羊)-右子树的最左端// TreeNode minParent=node;// TreeNode min=node.right;//// while (min.left!=null){
// minParent=min;// min=min.left;// }//// //替换// node.key=min.key;// //删除替罪羊(替罪羊节点没有左子树)// //类似于删除只右子树的节点////// if (minParent.right==min){
// minParent.right=min.right;// }else {
// minParent.left=min.right;// } } }}
测试类Test
public class Test {
public static void main(String[] args) {
BinarySearchTree bst=new BinarySearchTree(); bst.insert(1); bst.insert(3); bst.insert(5); bst.insert(7); bst.insert(9); bst.insert(10); bst.insert(2); bst.insert(4); //中序遍历 bst.inOrder(bst.root); System.out.println(); System.out.println(bst.search(7)); System.out.println(bst.search(6)); System.out.println(bst.remove(1)); bst.inOrder(bst.root); System.out.println(); System.out.println(bst.remove(9)); bst.inOrder(bst.root); System.out.println(); }}
结果

在这里插入图片描述

转载地址:http://gyfki.baihongyu.com/

你可能感兴趣的文章
pthread_create使用类中函数指针的…
查看>>
实用技巧:Gdbserver远程调试的具…
查看>>
实用技巧:Gdbserver远程调试的具…
查看>>
静态成员函数调用非静态成员变量-p…
查看>>
静态成员函数调用非静态成员变量-p…
查看>>
基于ARM与DSP的智能仪器系统设计
查看>>
基于ARM与DSP的智能仪器系统设计
查看>>
微处理器中各种总线简介(转载)
查看>>
linux库知识,静态库和动态库
查看>>
linux库知识,静态库和动态库
查看>>
U-boot在开发板上移植过程详解(1)-…
查看>>
Nand&nbsp;Flash存储结构及控制方法(K9F…
查看>>
S3C2440与SDRAM连接浅析
查看>>
S3C2440与SDRAM连接浅析
查看>>
关于udelay();&nbsp;mdelay();&nbsp;ndelay()…
查看>>
关于udelay();&nbsp;mdelay();&nbsp;ndelay()…
查看>>
pthread_create&nbsp;内存泄漏&nbsp;valgrind
查看>>
pthread_create&nbsp;内存泄漏&nbsp;valgrind
查看>>
JPEG文件编/解码详解
查看>>
JPEG文件编/解码详解
查看>>