目录
1. 概念
2. 二叉树搜索树的基本操作实现
2.1 查找
2.2 插入
2.3 删除(较为复杂)
2.3.1 图例
2.3.2 代码实现
3. TreeMap常用方法的使用
4. TreeSet常用方法的使用
1. 概念
key-value模型,TreeSet中存储数据为key模型,它们都是基于红黑树实现的便于动态查找的数据结构,如果我们需要在对某个集合进行查找过程中,可能对该集合进行插入或删除的操作,则可以使用它们去实现.
注:TreeMap实现了SortedMap(用于排序,且它实现了Map接口---> 独立接口,没有实现Collection接口)接口,而TreeSet实现了SortedSet(用于排序,且它实现了Set接口---> 实现了Collection接口 )接口.
2. 二叉树搜索树的基本操作实现
二叉搜索树又称二叉排序树,它满足树中每个父节点的值都大于其左子结点值且小于其右子结点值,而其所有操作的最基本思路都是建立游标结点对二叉搜索树中的结点进行遍历,然后根据需求进行插入或删除操作.
2.1 查找
● 具体思路:通过游标结点遍历二叉搜索树的过程中,判断游标结点的val值是否等于给定的val值,如果相等,返回当前游标结点,直到遍历结束,如果还未返回,则返回null(二叉搜索树中没有值为给定val值的结点).
● 实现代码
/**
* 查找值为val的结点
* @param val 给定的val值
* @return 二叉搜索树中值为val的结点
*/
public Node find(int val) {
if(root == null) return null;
Node cur = root;
while (cur != null) {
if(cur.val > val) {
cur = cur.left;
}else if(cur.val < val) {
cur = cur.right;
}else {
return cur;
}
}
return null;
}
2.2 插入
● 具体思路:通过游标结点遍历二叉搜索树的过程中,将给定的val值不断与游标结点的val值进行比较,直到找到适合newNode结点插入的位置(根据给定val值创建的结点)
注:插入newNode结点需要在游标结点进行遍历过程中保存其父节点,不然无法插入该结点.
● 实现代码
Node root = null;
/**
* 插入结点
* @param val 待插入结点的值
*/
public void add(int val) {
Node newNode = new Node(val);
if(root == null) {
root = newNode;
return;
}
Node cur = root;
Node pre = null;
while(cur != null) {
if(cur.val > val) {
pre = cur;
cur = cur.left;
}else if(cur.val < val) {
pre = cur;
cur = cur.right;
}else {
return; //二叉搜索树中出现值相同的结点没有意义
}
}
if(pre.val > val) pre.left = newNode;
else pre.right = newNode;
}
2.3 删除(较为复杂)
★★★★)具体思路:
通过游标结点遍历二叉搜索树得到要删除的结点和其父节点,假设要删除的结点为deleteNode,其父节点为parNode.
1) deleteNode左子树为空
① 要删除的结点为根节点(parNode为空)
② 父节点的左子结点为要删除的结点
③ 父节点的右子结点为要删除的结点
2) deleteNode右子树为空
① 要删除的结点为根节点(parNode为空)
② 父节点的左子结点为要删除的结点
③ 父节点的右子结点为要删除的结点
3) deleteNode左子树和右子树都不为空(替换删除)
主要采用替换删除,有两种方案,一种在其左子树中找到最大结点和其父结点,一种在其右子树中找到最小结点和其父节点.将值与deleteNode结点的值修改为左子树中最大结点的值或者右子树中最小结点的值,之后则问题变成如何将deleteNode结点的左子树最大结点删除或者右子树的最小结点删除.(替换的是那个就删除哪个)
2.3.1 图例
注:特殊情况下,target没有左子树,那么直接targetParent.right = target.right;一般情况下,targetParent.left = target.right.
2.3.2 代码实现
/**
* 删除值为val的结点
* @param val 给定的val值
*/
public void delete(int val) {
if(root == null) return;
Node cur = root;
Node parent = null;
while(cur != null) {
if(cur.val < val) {
parent = cur;
cur = cur.right;
}else if(cur.val > val) {
parent = cur;
cur = cur.left;
}else {
deleteK(cur,parent);
return;
}
}
}
private void deleteK(Node cur, Node parent) {
if(cur.left == null) {
if(cur == root) {
cur = cur.right;
}else if(parent.left == cur) {
parent.left = cur.right;
}else {
parent.right = cur.right;
}
}else if(cur.right == null) {
if(cur == root) {
cur = cur.left;
}else if(parent.left == cur) {
parent.left = cur.left;
}else {
parent.right = cur.left;
}
}else {
//这里以在右子树中找到最小值的结点进行替换删除
Node targetParent = cur;
Node target = cur.right;
while(target.left != null) {
targetParent = target;
target = target.left;
}
cur.val = target.val;
if(target != cur.right) {
targetParent.left = target.right;
}else {
targetParent.right = target.right;
}
}
}
3. TreeMap常用方法的使用
根据jdk文档我们可以查询到有关TreeMap的所有方法的使用(当然也可以在Idea中查看).这里我们将TreeMap的常用方法进行一个练习,加深印象.
● 往某个TreeMap对象中添加键值对使用put()方法.
Map<Integer,Integer> map = new TreeMap<>();
map.put(1,2);
map.put(2,3);
System.out.println(map);
TreeMap的键一定要是可以比较的,且不能为空.
● 删除某个TreeMap对象中的某个键值对 使用remove()方法.
● 根据键得到对应的值 使用get()方法.
● 得到TreeMap对象中所有的键值对 使用entrySet()方法.
Map<Integer,Integer> map = new TreeMap<>();
map.put(1,2);
map.put(99,55);
map.put(3,5);
Set<Map.Entry<Integer,Integer>> set = map.entrySet();
for (Map.Entry<Integer,Integer> s:set) {
System.out.println(s.getKey()+" "+s.getValue());
}
● containsKey()和containsValue()分别判断TreeMap对象是否包含某个键或者值.
Map<Integer,Integer> map = new TreeMap<>();
map.put(1,2);
map.put(99,55);
map.put(3,5);
System.out.println(map.containsKey(1));
System.out.println(map.containsValue(5));
System.out.println(map.containsKey(100));
System.out.println(map.containsValue(66));
除此之外,TreeMap中还有很多方法,大家感兴趣的话可以去了解使用一下.
4. TreeSet常用方法的使用
TreeSet底层还是使用TreeMap进行实现的.它存储的数据必须是可以比较的,且具有去重的作用(key的唯一性).
● 往某个TreeSet对象中添加数据 使用add()方法.
Set<Integer> set = new TreeSet<>();
set.add(11);
set.add(66);
set.add(55);
set.add(55);
System.out.println(set);
● 删除某个TreeSet对象中的数据 使用remove()方法.
Set<Integer> set = new TreeSet<>();
set.add(11);
set.add(66);
set.add(55);
set.remove(55);
System.out.println(set);
● 判断TreeSet对象中是否包含某个数据 使用contains()方法.
Set<Integer> set = new TreeSet<>();
set.add(11);
set.add(66);
set.add(55);
System.out.println(set.contains(55));
System.out.println(set.contains(100));
当然,TreeSet中不仅仅只有这些方法,大家感兴趣可以去了解一下.
分享完毕~