聊一聊java中的SortedMap,TreeMap,以及SortedSet和TreeSet

news/2024/7/7 20:09:10

SortedMap、TreeMap、SortedSet和TreeSet都是Java集合框架中的重要组成部分,它们各自具有独特的特点和适用场景。

下面将逐一详细介绍这些集合类的特点。

SortedMap

SortedMap是Java中的一个接口,它继承自Map接口,用于存储键值对,并且可以按照键的自然顺序或自定义排序顺序进行排序。在SortedMap中,键是唯一的,而值则可以重复。SortedMap的键值对按照键的排序顺序存储,这使得我们可以方便地根据键来查找和遍历数据。TreeMap就是SortedMap的一个具体实现。

TreeMap

TreeMap是Java中的一种集合类,它实现了SortedMap接口,因此具有按照键的自然顺序或自定义顺序对元素进行排序的特性。TreeMap的底层实现采用了红黑树数据结构,这使得元素在TreeMap中按照键的排序顺序存储,从而可以高效地进行查找、插入和删除操作。同样,TreeMap中的键是唯一的,相同的键只能存储一个元素。

SortedSet

SortedSet 是一个接口,它扩展了 Set 接口并添加了排序的功能。SortedSet 中的元素都是唯一的,并且根据它们的自然顺序(如果元素实现了 Comparable 接口)或根据创建 SortedSet 时提供的 Comparator 进行排序。

SortedSet 接口定义了一些额外的方法,例如 first() 和 last(),分别用于获取集合中的第一个和最后一个元素;headSet(E toElement)tailSet(E fromElement) 和 subSet(E fromElement, E toElement) 方法分别用于获取小于某个元素的集合、大于某个元素的集合以及介于两个元素之间的集合。

TreeSet

TreeSet是Java集合框架中的另一种有序集合,它实现了Set接口,因此具有不允许重复元素的特性。TreeSet使用红黑树数据结构来存储元素,这使得元素在集合中保持有序。TreeSet中的元素按照自然排序(元素的自然顺序)或者指定的排序方式(通过比较器)排列,因此遍历TreeSet得到的元素是按照一定的顺序排列的。同样,TreeSet也保证元素的唯一性,不允许重复元素。

一个TreeSet的简单代码示例:

import java.util.TreeSet;  
  
public class TreeSetExample {  
    public static void main(String[] args) {  
        TreeSet<Integer> set = new TreeSet<>();  
          
        set.add(3);  
        set.add(1);  
        set.add(2);  
          
        // 输出:[1, 2, 3]  
        System.out.println(set);  
          
        // 获取并输出第一个元素  
        System.out.println(set.first()); // 输出:1  
          
        // 获取并输出最后一个元素  
        System.out.println(set.last()); // 输出:3  
          
        // 获取并输出小于3的集合  
        System.out.println(set.headSet(3)); // 输出:[1, 2]  
          
        // 获取并输出大于1的集合  
        System.out.println(set.tailSet(2)); // 输出:[2, 3]  
          
        // 获取并输出介于1和3之间的集合(不包括3)  
        System.out.println(set.subSet(1, 3)); // 输出:[1, 2]  
    }  
}

从以上的简单介绍中可以看出,SortedMap、SortedSet是通过自然序或Comparator来比较排序,TreeMap、TreeSet用到了红黑树。

红黑树:

红黑树(Red Black Tree)是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,其典型的用途是实现关联数组。它是在1972年由Rudolf Bayer发明的,当时被称为平衡二叉B树(symmetric binary B-trees)。后来,在1978年被Leo J. Guibas和Robert Sedgewick修改为如今的“红黑树”。

红黑树本身是一种特殊的二叉树,它的每个节点要么是黑色,要么是红色。它满足以下五个性质:

  1. 根节点是黑色。
  2. 每个叶子节点(Nil或空值)都是黑色。
  3. 每个红色节点的两个子节点都是黑色(但黑色节点的子节点可以是黑色,也可以是红色)。
  4. 从任一节点到其每个叶子节点的所有简单路径都包含相同数量的黑色节点。
  5. 每个简单路径都包含相同数目的黑色节点。

红黑树在进行插入和删除操作时,会通过特定的操作保持二叉查找树的平衡,从而确保在最坏情况下也有良好的运行时间。这使得红黑树在查找、插入和删除操作上的时间复杂度都是O(log n),其中n是树中元素的数目。

红黑树的这些特性使得它在计算机科学领域得到了广泛的应用,尤其是在需要高效处理大量有序数据的场景中。

红黑树的java实现:

Java中实际上内置了对红黑树的实现,最典型的是在java.util.TreeMapjava.util.TreeSet中。这些类内部使用了红黑树来存储元素,并提供了高效的查找、插入和删除操作。

不过,要完全从头开始用Java编写一个红黑树的实现是相当复杂的。

这里提供一个简化版的红黑树节点定义和插入操作的示例代码:

public class RedBlackTree {  
  
    // 定义红黑树节点的颜色  
    enum Color {  
        RED, BLACK  
    }  
  
    // 定义红黑树节点  
    static class Node {  
        int key;  
        Color color;  
        Node left;  
        Node right;  
        Node parent;  
  
        Node(int key, Color color) {  
            this.key = key;  
            this.color = color;  
            this.left = null;  
            this.right = null;  
            this.parent = null;  
        }  
    }  
  
    // 根节点  
    private Node root;  
  
    // 向红黑树中插入新节点  
    public void insert(int key) {  
        Node newNode = new Node(key, Color.RED); // 新节点默认为红色  
        if (root == null) {  
            root = newNode;  
            root.color = Color.BLACK; // 根节点必须为黑色  
            return;  
        }  
  
        Node current = root;  
        Node parent = null;  
  
        // 找到新节点的插入位置  
        while (current != null) {  
            parent = current;  
            if (newNode.key < current.key) {  
                current = current.left;  
            } else {  
                current = current.right;  
            }  
        }  
  
        newNode.parent = parent;  
        if (newNode.key < parent.key) {  
            parent.left = newNode;  
        } else {  
            parent.right = newNode;  
        }  
  
        // 修复红黑树  
        fixInsert(newNode);  
    }  
  
    // 修复插入新节点后的红黑树  
    private void fixInsert(Node k) {  
        // 插入修复算法:向上修复颜色及进行旋转  
        while (k != root && k.parent.color == Color.RED) {  
            if (parentOf(k) == leftOf(parentOf(parentOf(k)))) {  
                Node uncle = rightOf(parentOf(parentOf(k)));  
                if (uncle != null && uncle.color == Color.RED) {  
                    // 情况1: 叔叔节点也是红色  
                    parentOf(k).color = Color.BLACK;  
                    uncle.color = Color.BLACK;  
                    parentOf(parentOf(k)).color = Color.RED;  
                    k = parentOf(parentOf(k));  
                } else {  
                    // 情况2: 叔叔节点是黑色且k是右孩子  
                    if (k == rightOf(parentOf(k))) {  
                        k = parentOf(k);  
                        leftRotate(k);  
                    }  
                    // 情况3: 叔叔节点是黑色且k是左孩子  
                    parentOf(k).color = Color.BLACK;  
                    parentOf(parentOf(k)).color = Color.RED;  
                    rightRotate(parentOf(parentOf(k)));  
                }  
            } else {  
                // 镜像情况  
                Node uncle = leftOf(parentOf(parentOf(k)));  
                if (uncle != null && uncle.color == Color.RED) {  
                    parentOf(k).color = Color.BLACK;  
                    uncle.color = Color.BLACK;  
                    parentOf(parentOf(k)).color = Color.RED;  
                    k = parentOf(parentOf(k));  
                } else {  
                    if (k == leftOf(parentOf(k))) {  
                        k = parentOf(k);  
                        rightRotate(k);  
                    }  
                    parentOf(k).color = Color.BLACK;  
                    parentOf(parentOf(k)).color = Color.RED;  
                    leftRotate(parentOf(parentOf(k)));  
                }  
            }  
        }  
        root.color = Color.BLACK;  
    } 
    // 左旋转  
    private void leftRotate(Node x) {  
        Node y = x.right;  
        x.right = y.left;  
  
        if (y.left != null) {  
            y.left.parent = x;  
        }  
  
        y.parent = x.parent;  
  
        if (x.parent == null) {  
            root = y;  
        } else if (x == x.parent.left) {  
            x.parent.left = y;  
        } else {  
            x.parent.right = y;  
        }  
  
        y.left = x;  
        x.parent = y;  
    }  
  
    // 右旋转  
    private void rightRotate(Node y) {  
        Node x = y.left;  
        y.left = x.right;  
  
        if (x.right != null) {  
            x.right.parent = y;  
        }  
  
        x.parent = y.parent;  
  
        if (y.parent == null) {  
            root = x;  
        } else if (y == y.parent.right) {  
            y.parent.right = x;  
        } else {  
            y.parent.left = x;  
        }  
  
        x.right = y;  
        y.parent = x;  
    }  
  
    // 获取节点的父节点  
    private Node parentOf(Node node) {  
        return node != null ? node.parent : null;  
    }  
  
    // 获取节点的左孩子  
    private Node leftOf(Node node) {  
        return node != null ? node.left : null;  
    }  
  
    // 获取节点的右孩子  
    private Node rightOf(Node node) {  
        return node != null ? node.right : null;  
    }  
  
    // ...(其他需要的方法和功能)  
  
    public static void main(String[] args) {  
        RedBlackTree tree = new RedBlackTree();  
        // 示例:插入节点  
        tree.insert(5);  
        tree.insert(3);  
        tree.insert(8);  
        tree.insert(10);  
        tree.insert(1);  
        // ...(其他操作)  
    }  
}

请注意,这只是一个非常简化的示例,它不包括完整的红黑树功能(如删除操作)以及完整的错误检查和边界情况处理。在实际应用中,您可能需要使用现有的数据结构库(如Java的TreeMapTreeSet),或者查阅更完整的红黑树实现,以确保正确性和性能。

更详细的信息,请阅读java.util.TreeMap或java.util.TreeSet中的代码实现。


http://lihuaxi.xjx100.cn/news/2159730.html

相关文章

2024.4.3力扣每日一题——找出克隆二叉树中的相同节点

2024.4.3 题目来源我的题解方法一 深度优先搜索方法二 广度优先遍历 题目来源 力扣每日一题&#xff1b;题序&#xff1a;1379 我的题解 方法一 深度优先搜索 同时对二叉树 original 与 cloned 进行深度优先搜索&#xff0c;如果 original当前搜索的节点的引用等于 target 节…

python 怎样卸载pip

首先&#xff0c;同时按下键盘&#xff0c;winR 调出运行窗口&#xff0c;输入‘cmd’命令。 想在cmd界面进行解析&#xff0c;必须将python环境变量安装好&#xff0c;可以通过输入‘python’来确定是否调整好变量。 首先将python的工作路径调整值&#xff0c;所需安装工具包位…

茴香豆 RAG 智能助理 搭建

一. 环境准备 1. 构建Conda环境 studio-conda -o internlm-base -t InternLM2_Huixiangdou 2. 进入创建的conda环境 conda activate InternLM2_Huixiangdou 二. 准备基础文件 1. 创建文件夹 cd /root && mkdir models 2. 构建软链接 # 复制BCE模型 ln -s /root…

蓝桥杯 基础练习 特殊的数字

资源限制 内存限制&#xff1a;512.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 问题描述 153是一个非常特殊的数&#xff0c;它等于它的每位数字的立方和&#xff0c;即1531*1*15*5*53*3*3。编程求所有满足这种条件…

字符函数strlen、strcpy、strcat、strcmp、strstr、strtok、 strerror和perror函数

目录 1、strlen函数 strlen函数的模拟实现 2、strcpy函数 strcpy函数的模拟实现 strncpy函数 strncpy函数的模拟实现 3、srtcat函数 strcat函数的模拟实现 strncat函数 strncat函数的模拟实现 4、strcmp函数 strcmp函数的模拟实现 strncmp函数 5、strstr函数 st…

【2023注册测绘师考试综合能力考试攻略】综合练习题

学习目标: 学完航空摄影测量等章节,试着做做题吧。 学习内容: 【单项选择题】 (1)某航摄分区的航摄比例尺为 1:6000,所用航摄仪主距为100mm,则分区内地形高差最大 应不超过( )m。 A.50 B.100 C.150 D.200 【答案】B (2)根据现行规范规定,行政区域界线测量中,界桩…

【刷题篇】回溯算法(三)

文章目录 1、全排列2、子集3、找出所有子集的异或总和再求和4、全排列 II5、电话号码的字母组合6、括号生成 1、全排列 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 class Solution { public:vector<vector<i…

三:synchronized 关键字

目录 1、共享带来的问题2、synchronized 用法3、类加载器对 Class 锁的影响4、synchronized 实现原理4.1、同步方法、同步代码块4.2、对象内存布局4.3、Monitor 对象定义 5、synchronized 与原子性6、synchronized 与可见性7、synchronized 与有序性8、synchronized 锁升级8.1、…