TreeMap和TreeSet即Java中利用二叉搜索树实现的Map和Set

一:概念
二叉搜索树又称二叉排序树,它或者是一棵空树**,或者是具有以下性质的二叉树:
若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
它的左右子树也分别为二叉搜索树。

二:操作——查找
先和根节点做对比,相等返回,如果不相等,
关键码key>根节点key,在右子树中找(root=root.rightChild)
关键码key<根节点key,在左子树中找(root=root.leftChild)
否则返回false

三:操作——插入
根据二叉排序树的性质,左孩子比根节点的值小,右孩子比根节点的值大。关键码key先于根节点key作比较,然后再判断与根节点的左或者右作比较,满足二叉排序树性质时,即为合理位置,然后插入。

四: 操作-删除(难点)
设待删除结点为 cur, 待删除结点的双亲结点为 parent
1. cur.left == null

  1. cur 是 root,则 root = cur.right
  2. cur 不是 root,cur 是 parent.left,则 parent.left = cur.right
  3. cur 不是 root,cur 是 parent.right,则 parent.right = cur.right
    2. cur.right == null
  4. cur 是 root,则 root = cur.left
  5. cur 不是 root,cur 是 parent.left,则 parent.left = cur.left
  6. cur 不是 root,cur 是 parent.right,则 parent.right = cur.left
    3. cur.left != null && cur.right != null
  7. 需要使用替换法进行删除,即在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中,再来处理该结点的删除问题

五:实现


public class BinarySearchTree<K extends Comparable<K>, V>
{
public static class Node<K extends Comparable<K>, V>
{
K key;
V value;
Node<K, V> left;
Node<K, V> right;

public String toString()
{
return String.format("{%s, %s}", key, value);
}
}
private Node<K, V> root = null;
public V get(K key)
{
Node<K, V> parent = null;
Node<K, V> cur = root;
while (cur != null)
{
parent = cur;
int r = key.compareTo(cur.key);
if (r == 0)
{
return cur.value;
}
else if (r < 0) {
cur = cur.left;
}
else
{
cur = cur.right;
}
}
return null;
}
public V put(K key, V value)

{
if (root == null)
{ root = new Node<>();
root.key = key;
root.v
display(root);
return null;
}
Node<K, V> parent = null;
Node<K, V> cur = root;
while (cur != null)
{
parent = cur;
int r = key.compareTo(cur.key);
if (r == 0)
{
V oldValue = cur.value;
cur.value = value;
display(root);
return oldValue;
}
else if (r < 0)
{
cur = cur.left;
}
else
{
cur = cur.right;
}
}
Node<K, V> node = new Node<>();
node.key = key;
node.value = value;
int r = key.compareTo(parent.key);
if (r < 0)
{ parent.left = node;
}
else { parent.right = node;
}
display(root);
return null;
}
public V remove(K key)
{ 
Node<K, V> parent = null;
Node<K, V> cur = root;
while (cur != null)
{
int r = key.compareTo(cur.key);
if (r == 0)
{
V oldValue = cur.value;
deleteNode(parent, cur);
display(root);
return oldValue; }
else if (r < 0)
{ parent = cur; cur = cur.left; }
else { parent = cur; cur = cur.right;
}
}
display(root);
return null;
}
private void deleteNode(Node<K,V> parent, Node<K,V> cur)
{
if (cur.left == null)
{
if (cur == root)
{
root = cur.right;
}
else if (cur == parent.left)
{ parent.left = cur.right; }
else { parent.right = cur.right; }
} else if (cur.right == null)
{
if (cur == root)
{ root = cur.left; }
else if (cur == parent.left)
{ parent.left = cur.left; }
else { parent.right = cur.left; }
} else {
// 去 cur 的右子树中寻找最小的 key 所在的结点 scapegoat
// 即 scapegoat.left == null 的结点
Node<K,V> goatParent = cur;
Node<K,V> scapegoat = cur.right;
while (scapegoat.left != null)
{ goatParent = scapegoat; scapegoat = cur.left; }
cur.key = scapegoat.key;
cur.value = scapegoat.value;
if (scapegoat == goatParent.left)
{
goatParent.left = scapegoat.right;
}
else { goatParent.right = scapegoat.right; }
}
}
private static <K extends Comparable<K>,V> void display(Node<K,V> node)
{
System.out.print("前序: ");
preOrder(node);
System.out.println();
System.out.print("中序: ")
inOrder(node);
System.out.println(); }
private static <K extends Comparable<K>,V> void preOrder(Node<K,V> node)
{ if (node == null)
{ return; }
System.out.print(node + " ");
preOrder(node.left);
preOrder(node.right); }
private static <K extends Comparable<K>,V> void inOrder(Node<K,V> node)
{ if (node == null)
{ return; }
inOrder(node.left);
System.out.print(node + " ");
inOrder(node.right); }
public static void main(String[] args)
{
BinarySearchTree<Integer, String> tree = new BinarySearchTree<>();
int[] keys = { 5, 3, 7, 4, 2, 6, 1, 9, 8 };
for (int key : keys)
{
tree.put(key, String.valueOf(key)); }
System.out.println("=================================="); tree.put(3, "修改过的 3"); System.out.println("=================================="); tree.remove(9);
tree.remove(1); t
ree.remove(3);
``` }
}

**六:性能分析**
插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。
对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。
但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树。
**七: 和 java 类集的关系**
TreeMap 和 TreeSet 即 java 中利用搜索树实现的 Map 和 Set;

原文地址:https://blog.51cto.com/14232658/2474571

时间: 2024-11-14 03:35:29

TreeMap和TreeSet即Java中利用二叉搜索树实现的Map和Set的相关文章

Java数据结构之二叉搜索树

Java数据结构之二叉搜索树 1.二叉搜索树组成 二叉搜索树又称为二叉排序树,它或者是一颗空树,或者是一颗具有如下特性的非空二叉树,需要满足一下三个条件: (1)若它的左子树非空,则左子树上所有结点的关键字均小于根结点的关键字: (2)若它的右子树非空,则右子树上所有结点的关键字均大于(可以等于)根结点的关键字. (3)左子树右子树本身又各是一颗二叉搜索树 在算法描述中,均以结点值的比较来代表其关键字的比较,因为若结点的值为类类型时,该类必须实现系统提供的java.lang.comparable

二叉搜索树的Java实现

为了更加深入了解二叉搜索树,博主自己用Java写了个二叉搜索树,有兴趣的同学可以一起探讨探讨. 首先,二叉搜索树是啥?它有什么用呢? 二叉搜索树, 也称二叉排序树,它的每个节点的数据结构为1个父节点指针,1个左孩子指针,1个有孩子指针,还有就是自己的数据部分了,因为只有左右两孩子,所以才叫二叉树,在此基础上,该二叉树还满足另外一个条件:每个结点的左孩子都不大于该结点&&每个结点的右孩子都大于该结点.这样,我们队这棵树进行中序遍历,就能把key从小到大排序了…… 那么问题来了,我都有线性表有

剑指Offer面试题27(Java版):二叉搜索树与双向链表

题目:输入一颗二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建新的结点.仅仅能调整树中结点指针的指向. 比方例如以下图中的二叉搜索树.则输出转换之后的排序双向链表为: 在二叉树中,每一个结点都有两个指向子节点的指针.在双向链表中.每一个结点也有两个指针.他们分别指向前一个结点和后一个结点.因为这两种结点的结构相似,同一时候二叉搜索树也是一种排序的数据结构.因此在理论上有可能实现二叉搜索树和排序的双向链表的转换. 在搜索二叉树中,左子结点的值总是小于父节点的值,右子节点的值总是大于

二叉搜索树 思想 JAVA实现

二叉搜索树:一棵二叉搜索树是以一棵二叉树来组织的,这样一棵树可以使用链表的数据结构来表示(也可以采用数组来实现).除了key和可能带有的其他数据外,每个节点还包含Left,Right,Parent,它们分别指节点的左孩子,右孩子,和父节点. 一个二叉搜索树总是满足 :node.left.key<node.key<=node.right.key. 以下是一个用java实现的二叉搜索树,包含了查找最大值,最小值,查找某一节点,插入和删除操作. 接下来通过代码来分析二叉搜索树中的思想:在代码实现二叉

二叉搜索树(搜索、添加、遍历)——Java

栈.队列.链表都有他们各自的好处,同样的也有弊端的存在. 如果我想要一个有序的数组和链表这个当然很好实现.现在我要在这几个数据结构中查找一个值.先说数组,因为是有序的通过二分查找很快的就可以找到.查找的效率还是很高的,但如果要是插入呢,为了保证有序,我要先找到插入位置,然后再将比插入数字大的数字依次向后移动:这时的第一反应就是链表!他打插入速度很快,只要改变指针的指向就可以了.但是链表大查找要从头开始找啊.只有知道了前一个元素的地址才能知道下一个地址.所以链表查找起来又费劲了.这时候就有人引进了

数据结构-二叉搜索树(BST binary search tree)

本文由@呆代待殆原创,转载请注明出处:http://www.cnblogs.com/coffeeSS/ 二叉搜索树简介 顾名思义,二叉搜索树是以一棵二叉树来组织的,这样的一棵树可以用一个链表数据结构来表示,每个节点除了key和卫星数据(除了二叉树节点的基本数据以外人为添加的数据,这些数据和树的基本结构无关),还有left.right.parent,分别指向节点的左孩子.右孩子和父节点,如果对应的节点不存在则指向NIL节点(因为最简单的二叉搜索树中的NIL节点里并没有有用的信息,所以在实现的时候简

二叉搜索树的顺序性

------------------siwuxie095 二叉搜索树的顺序性 二叉搜索树具有一定的顺序性,即 使用二叉搜索树可以回答很多 元素之间的和顺序相关的问题,如下: (1)minimum 和 maximum 通过二叉搜索树可以非常容易地找到一组数据中最小的元素 minimum 和最大的元素 maximum (2)predecessor 和 successor 通过二叉搜索树可以非常容易地找到一个元素的前驱 predecessor 和后继 successor (3)floor 和 ceil

漫谈二叉搜索树的基本算法(三种思路实现查询操作)

  前面我们说了二叉树前序中序后序遍历的递归非递归算法的实现,下面我们再来说说二叉搜索树~   二叉排序树分为静态查找(find)和动态查找(insert.delete) 二叉搜索树:一棵二叉树,可以为空:如果不为空,满足下列性质: 1.非空左子树的所有键值小于其根结点的键值. 2.非空右子树的所有键值大于其根结点的键值 3.左右子树都是二叉搜索树!! 2.以上是二叉搜索树(也叫二叉排序树)的一些基本操作,此处我们先说一下二叉树的结点定义·· 代码中判断当前结点位置情况的辅助方法以及简单的 ge

[LeetCode]501. Find Mode in Binary Search Tree二叉搜索树寻找众数

这次是二叉搜索树的遍历 感觉只要和二叉搜索树的题目,都要用到一个重要性质: 中序遍历二叉搜索树的结果是一个递增序列: 而且要注意,在递归遍历树的时候,有些参数如果是要随递归不断更新(也就是如果递归返回上层,参数也需要最新的),就要用全局变量,而不是传参,其实这就是全局变量的定义. 不过如果是保存每层递归内的信息,就需要传参数. 本题显然是需要全局参数 /** * Definition for a binary tree node. * public class TreeNode { * int