JAVA Map 升序|降序|随机|去重排序

本文介绍了Java中Map的不同类型及其排序方法,包括按键排序、按值排序和随机排序的具体实现,并提供了详细的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、Map简介


在讲解Map排序之前,我们先来稍微了解下map。map是键值对的集合接口,它的实现类主要包括:HashMap,TreeMap,Hashtable以及LinkedHashMap等。其中这四者的区别如下(简单介绍):

1、HashMap:我们最常用的Map,它根据key的HashCode 值来存储数据,根据key可以直接获取它的Value,同时它具有很快的访问速度。HashMap最多只允许一条记录的key值为Null(多条会覆盖);允许多条记录的Value为 Null。非同步的。

2、TreeMap: 能够把它保存的记录根据key排序,默认是按升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。TreeMap不允许key的值为null。非同步的。

3、Hashtable: 与 HashMap类似,不同的是:key和value的值均不允许为null;它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了Hashtale在写入时会比较慢。

4、LinkedHashMap: 保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.在遍历的时候会比HashMap慢。key和value均允许为空,非同步的。


简单总结为:

map:无序
Treemap:默认是升序(以key作为标准)
Linkedhashmap:默认是插入数据时的顺序



二、Comparator接口


(A)、方法

int compare(T o1,T o2)

(B)、说明


比较用来排序的两个参数。根据第一个参数小于、等于或大于第二个参数分别返回负整数、零或正整数。
在前面的描述中,符号 sgn(expression) 表示 signum 数学函数,根据 expression 的值为负数、0 还是正数,该函数分别返回 -1、0 或 1。


简单来说就是,Comparator可以对集合对象或者数组进行排序的比较器接口,实现该接口的public compare(T o1,To2)方法即可实现排序,该方法主要是根据第一个参数o1,小于、等于或者大于o2分别返回负整数、0或者正整数。


(C)、参数:
o1 - 要比较的第一个对象。
o2 - 要比较的第二个对象。


(D)、返回:
根据第一个参数小于、等于或大于第二个参数分别返回负整数、零或正整数。


三、示例


1、按键排序


TreeMap<K,V>既可满足此类需求,向其构造方法 TreeMap(Comparator<? super K> comparator)  传入我们自定义的比较器即可实现按键排序。

    /**
     * 按Key进行排序
     */
    @Test
    public void TestSort1(){
        Map<String, String> resultMap = new TreeMap<>(new Comparator<String>() {
            @Override
            public int compare(String str1, String str2) {
                return str1.compareTo(str2);
            }
        });
        resultMap.put("1", "kfc");
        resultMap.put("2", "wnba");
        resultMap.put("3", "nba");
        resultMap.put("4", "cba");
        for (Map.Entry<String, String> entry : resultMap.entrySet()) {
            System.out.println(entry.getKey() + " " + entry.getValue());
        }
    }



2、按值排序


Map本身按值排序是很有意义的,很多场合下都会遇到类似需求,可以认为其值是定义的某种规则或者权重。

原理:将待排序Map中的所有元素置于一个列表中,接着使用Collections的一个静态方法 sort(List<T> list, Comparator<? super T> c) 
来排序列表,同样是用比较器定义比较规则。排序后的列表中的元素再依次装入Map,为了肯定的保证Map中元素与排序后的List中的元素的顺序一致,使用了LinkedHashMap数据类型。


    /**
     * 按Value进行排序
     */
    @Test
    public void TestSort2(){
        Map<String, String> resultMap = new TreeMap<String, String>();
        resultMap.put("kfc", "1");
        resultMap.put("wnba", "2");
        resultMap.put("nba", "6");
        resultMap.put("cba", "4");
        resultMap.put("eba", "5");
        resultMap.put("ebe", "0");
        Map<String, String> sortedMap = new LinkedHashMap<String, String>();
        List<Map.Entry<String, String>> entryList = new ArrayList<Map.Entry<String, String>>(
                resultMap.entrySet());

        Collections.sort(entryList, new Comparator<Entry<String, String>>() {
            @Override
            public int compare(Entry<String, String> o1, Entry<String, String> o2) {
                return o1.getValue().compareTo(o2.getValue());
            }
        });

        Iterator<Map.Entry<String, String>> iter = entryList.iterator();
        Map.Entry<String, String> tmpEntry = null;
        while (iter.hasNext()) {
            tmpEntry = iter.next();
            sortedMap.put(tmpEntry.getKey(), tmpEntry.getValue());
        }

        for (Map.Entry<String, String> entry : sortedMap.entrySet()) {
            System.out.println(entry.getKey() + " " + entry.getValue());
        }
    }

3.随机排序


   /**
     * 三种排序
     * 1.升序排列
     * 2.降序排序
     * 3.随机排序
     */
    @Test
    public void TestSort3() {
        //默认的TreeMap升序排列
        TreeMap<Integer, Integer> map1 = new TreeMap<Integer, Integer>();
        
        //降序排序
        TreeMap<Integer, Integer> map2 = new TreeMap<Integer, Integer>(new Comparator<Integer>() {
            /*
            * int compare(Object o1, Object o2) 返回一个基本类型的整型,
            * 返回负数表示:o1 小于o2,
            * 返回0 表示:o1和o2相等,
            * 返回正数表示:o1大于o2。
            */
            public int compare(Integer o1, Integer o2) {
                return  o2 - o1;
            }
        });

        //随机排序
        TreeMap<Integer, Integer> map3 = new TreeMap<Integer, Integer>(new Comparator<Integer>() {
            /*
            * int compare(Object o1, Object o2) 返回一个基本类型的整型,
            * 返回负数表示:o1 小于o2,
            * 返回0 表示:o1和o2相等,
            * 返回正数表示:o1大于o2。
            */
            public int compare(Integer a, Integer b) {
                int randomOne = (int) (Math.random() * 10);
                int randomTwo = (int) (Math.random() * 10);
                return randomOne - randomTwo;
            }
        });

        map2.put(1, 2);
        map2.put(2, 4);
        map2.put(2, 4);
        map2.put(7, 1);
        map2.put(5, 2);
        System.out.println("Map2降序排列=" + map2);

        map1.put(1, 2);
        map1.put(2, 4);
        map1.put(7, 1);
        map1.put(5, 2);
        map1.put(5, 2);
        System.out.println("map1升序排序=" + map1);

        map3.put(1, 2);
        map3.put(2, 4);
        map3.put(7, 1);
        map3.put(5, 2);
        map3.put(9, 2);
        map3.put(11, 2);
        map3.put(11, 2);
        System.out.println("map3随机排序=" + map3);
    }

4.Map转成List使用Collections.shuffle()随机排序

    /**
     * Map转List 随机排序
     * @throws IOException
     */
    @Test
    public void TestSort4() throws IOException {
        Map<String, Object> unsortMap = new HashMap<>();
        unsortMap.put("z", 10);
        unsortMap.put("b", 5);
        unsortMap.put("a", 6);
        unsortMap.put("c", 20);
        unsortMap.put("d", 1);
        unsortMap.put("e", 7);
        unsortMap.put("y", 8);
        unsortMap.put("n", 99);
        unsortMap.put("g", 50);
        unsortMap.put("m", 2);
        unsortMap.put("f", 9);
        List<String> list = new LinkedList(unsortMap.keySet());
        //随机排序
        Collections.shuffle(list);
        Map<String,Object> result = new HashMap<String,Object>();
        for (int i = 0; i < list.size(); i++) {
            String jsonString = list.get(i);
            result.put(jsonString, unsortMap.get(jsonString));
        }
        for (Map.Entry<String, Object> entry : result.entrySet()) {
            System.out.println(entry.getKey() + " " + entry.getValue());
        }
    }


<think>好的,用户现在问的是C++中map的默认排序升序还是降序。之前他问过关于map的find方法返回值的问题,现在转向了排序规则。我需要先确定用户对map的了解程度,可能他刚开始接触STL容器,特别是关联容器。 首先,我得回忆C++标准中map的默认行为。map通常是用红黑树实现的,键值对会根据键来排序。默认情况下,使用std::less作为比较函数,所以是升序排列。这点需要明确,用户可能没有意识到模板参数中的比较函数可以改变排序方式。 用户可能遇到的问题是什么?他可能在测试代码时发现元素按升序输出,或者看到文档里的例子是升序,但不确定是否默认如此。也有可能他想实现降序排列,但不知道如何修改。这时候需要给出默认是升序,并简单说明如何更改为降序。 另外,用户之前的问题是关于find的返回值,现在转到排序,可能他在实际使用中遇到了排序相关的问题,比如插入元素后的遍历顺序不符合预期。这时候需要强调默认排序规则,并举例说明如何验证和修改排序方式。 需要确保回答清晰,结构分明。先直接回答问题,默认是升序。然后解释底层原因,比如比较函数std::less的作用。接着给出例子,比如int和string作为键时的默认排序。再说明如何更改为降序,使用greater或者自定义比较函数。最后可能提到其他类似容器的情况,比如set和multimap,同样适用默认的排序规则。 还要注意避免术语过多,用简单的中文解释,必要时用代码示例帮助理解。可能用户需要实际操作的例子,所以提供代码片段会更好。比如展示一个默认排序map和修改为降序后的map,输出结果对比。 总结回答结构:先结论,再详细说明,包括比较函数的作用,示例代码,如何修改排序,以及相关容器的信息。确保用户不仅知道默认是什么,还能知道如何调整和验证。</think>在 C++ STL 中,`std::map` 的 **默认排序升序**(从小到大)。具体规则如下: --- ### 核心机制 1. **底层实现**:红黑树(自平衡二叉搜索树) 2. **排序依据**:键(`Key`)的比较结果 3. **默认比较器**:`std::less<Key>`,即使用 `<` 运算符比较键值 --- ### 排序验证示例 #### 示例 1:整型键 ```cpp #include <map> #include <iostream> int main() { std::map<int, std::string> m = { {3, "three"}, {1, "one"}, {4, "four"}, {2, "two"} }; // 遍历输出(默认升序) for (const auto& pair : m) { std::cout << pair.first << " "; // 输出: 1 2 3 4 } } ``` #### 示例 2:字符串键 ```cpp std::map<std::string, int> words = { {"zebra", 1}, {"apple", 2}, {"banana", 3} }; for (const auto& w : words) { std::cout << w.first << " "; // 输出: apple banana zebra (按字典序升序) } ``` --- ### 修改排序规则(改为降序) 通过模板参数 **显式指定比较器**: ```cpp #include <functional> // 需要包含头文件 std::map<int, std::string, std::greater<int>> m_desc = { {3, "three"}, {1, "one"}, {4, "four"}, {2, "two"} }; for (const auto& pair : m_desc) { std::cout << pair.first << " "; // 输出: 4 3 2 1 } ``` --- ### 关键特性对比 | 特性 | 升序 (`std::less`) | 降序 (`std::greater`) | |---------------------|----------------------------------------|------------------------------------| | 默认行为 | ✅ 所有`map`默认使用 | 需显式声明 | | 时间复杂度 | 插入/查找 $O(\log n)$ | 同左 | | 自定义类型支持 | 需重载 `<` 运算符 | 需重载 `>` 运算符 或自定义比较器 | --- ### 扩展知识 1. **底层原理**:排序在插入时自动维护,迭代器遍历时会按排序顺序输出 2. **相关容器**: - `std::set`:同 `map` 的排序规则(默认升序) - `std::multimap`:允许重复键,排序规则相同 3. **自定义排序**:可通过函数对象或 Lambda 实现复杂比较逻辑 若需要其他排序方式,可通过自定义比较器灵活控制元素的存储顺序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值