Java-01-源码篇-04集合-05-SortedMap NavigableMap TreeMap

目录

一,SortedMap 

二,NavigableMap

三,TreeMap

3.1 TreeMap 继承结构

3.2 TreeMap 属性

3.3 TreeMap 构造器

3.4 TreeMap 内部类

3.4.1 Values

3.4.2 KeySet

3.4.3 EntrySet

3.4.5 相关集合迭代器

3.4.5.1 PrivateEntryIterator 迭代器

   

3.4.5.2 ValueIterator 迭代器

3.4.5.3 KeyIterator 迭代器

          

3.4.5.4 EntryIterator 迭代器

3.4.5.5 DescendingKeyIterator 倒排 key 迭代器

3.4.6  相关子集Map

3.4.7 相关分割器

3.4.8 Entry 映射实体类 (红黑树节点)

3.5 TreeMap 新增业务

3.5.1 put(key, value)

3.5.2 putIfAbsent(key, value)

 3.5.3 put(key, value, replaceOld)

3.5.4 addEntryToEmptyMap(key, value)

3.5.5 addEntry(key, value, parent, addToLeft)

3.6 TreeMap 删除业务

3.6.1 remove(key)

3.6.2 deleteEntry(e)

3.7 TreeMap 查询业务

3.8 TreeMap的 NavigableMap 的 lowerEntry(key)

2.9 TreeMap 与 HashMap 区别


一,SortedMap 

        SortedMap 是 Java 中 Map 接口的一个子接口,它提供一些额外的方法来处理有序的简直对映射。SortedMap 保证键以自然顺序或指定的比较器顺序排序。其接口方法源码如下:

package java.util;

/**
 * @since 1.2
 */
public interface SortedMap<K,V> extends Map<K,V> {
    /** 用于对键进行排序的比较器。如果使用键的自然顺序进行排序,则返回 null */
    Comparator<? super K> comparator();

    /** 
     * 获取一个子映射[fromKey, toKey),用于处理特定范围的键值对 
     * @param fromKey    
     * @param toKey     
     */
    SortedMap<K,V> subMap(K fromKey, K toKey);

    /**
     * 获取所有键小于 toKey 值的子映射
     */
    SortedMap<K,V> headMap(K toKey);

    /**
     * 获取所有键大于等于 fromKey值 的子映射
     */
    SortedMap<K,V> tailMap(K fromKey);
    
    /** 返回当前映射中第一个(最小的)键。 */
    K firstKey();

    /** 返回当前映射中最后一个(最大的)键 */
    K lastKey();

    /** 返回一个包含此映射中所有键的 Set 视图。集合中的键按照升序排列 */
    Set<K> keySet();

    /** 返回一个包含此映射中所有值的 Collection 视图。集合中的值按照对应键的升序排列。*/
    Collection<V> values();

    /** 返回一个包含此映射中所有键值对的 Set 视图。集合中的条目按照键的升序排列 */
    Set<Map.Entry<K, V>> entrySet();
}

        SortedMap 提供了一些用于处理有序键值对映射的额外方法,这些方法允许你获取子映射、获取特定范围的映射,以及按顺序访问键、值和键值对。

二,NavigableMap

        NavigableMap 是 Java 集合框架中的一个接口,扩展了 SortedMap 接口,提供了导航方法来检索按顺序映射的键及其关联的值。它允许更灵活地处理键和值,并提供了查找最接近的匹配项的方法。

        NavigableMap 主要用于处理有序键值对,并提供了额外的导航方法,例如获取最接近的键,逆向视图等。与 SortedMap 不同, NavigableMap 提供了更丰富的方法集,使得更加灵活的操作有序映射。其接口源码如下:

package java.util;

/**
 * @author Doug Lea
 * @author Josh Bloch
 * @param <K> the type of keys maintained by this map
 * @param <V> the type of mapped values
 * @since 1.6
 */
public interface NavigableMap<K,V> extends SortedMap<K,V> {
    /************************** 基本导航方法 **************************/
    /**
     * 查找 小于 指定键的最大键值的键值对映射,如果没有返回 null
     * @param key the key
     * @return 
     * @throws ClassCastException
     * @throws NullPointerException
     */
    Map.Entry<K,V> lowerEntry(K key);

    /**
     * 查找 小于 指定键的最大键值,如果没有返回 null
     *
     * @param key the key
     * @throws ClassCastException
     * @throws NullPointerException
     */
    K lowerKey(K key);

    /**
     * 查找 小于或等于 指定键的最大键值对,如果没有返回 null
     *
     * @param key the key
     * @throws ClassCastException 
     * @throws NullPointerException
     */
    Map.Entry<K,V> floorEntry(K key);

    /**
     * 查找 小于或等于 指定键的最大键
     *
     * @param key the key
     * @throws ClassCastException 
     * @throws NullPointerException
     */
    K floorKey(K key);

    /**
     * 查找 大于或等于 指定键的最小键值对,如果没有返回null
     *
     * @param key the key
     * @throws ClassCastException 
     * @throws NullPointerException
     */
    Map.Entry<K,V> ceilingEntry(K key);

    /**
     * 查找 大于或等于 指定键的最小键。
     *
     * @param key the key
     * @throws ClassCastException 
     * @throws NullPointerException
     */
    K ceilingKey(K key);

    /**
     * 查找 大于 指定键的最小键值对。
     *
     * @param key the key
     * @throws ClassCastException
     * @throws NullPointerException 
     */
    Map.Entry<K,V> higherEntry(K key);

    /**
     * 查找 大于 指定键的最小键
     *
     * @param key the key
     * @throws ClassCastException 
     * @throws NullPointerException 
     */
    K higherKey(K key);

    /************************** 最小和最大方法 **************************/
    /**
     * 获取映射中的第一个键值对
     * @return 返回映射中的第一个(键的最小)键值映射,或返回 null 如果映射为空
     */
    Map.Entry<K,V> firstEntry();

    /**
     * 返回映射中的最后一个(键的最大)键值映射,或返回 null 如果映射为空。
     * @return 获取映射中的最后一个键值对
     */
    Map.Entry<K,V> lastEntry();

    /**
     * 移除并返回映射中的第一个(键的最小)键值映射,或返回 null 如果映射为空
     * 简单理解:删除并返回映射中的第一个键值对。
     */
    Map.Entry<K,V> pollFirstEntry();

    /**
     * 移除并返回映射中的最后一个(键的最大)键值映射,或返回 null 如果映射为空。
     * 简单理解:删除并返回映射中的最后一个键值对
     */
    Map.Entry<K,V> pollLastEntry();

    /************************** 视图操作 **************************/
    /** 获取映射的键按逆序排列的视图。 */
    NavigableMap<K,V> descendingMap();

    /** 获取所有键的 NavigableSet 视图 */
    NavigableSet<K> navigableKeySet();

    /** 获取所有键的逆序 NavigableSet 视图 */
    NavigableSet<K> descendingKeySet();

    /************************** 子映射操作 **************************/
    /**
     * 返回键在 fromKey 到 toKey 范围内的子映射,是否包含边界由 fromInclusive 和 toInclusive 决定。
     * @param fromKey 子映射集合的起点
     * @param fromInclusive 子映射是否包含起点 true - 包含 | false - 不包含
     * @param toKey high 子映射集合的终点
     * @param toInclusive 子映射是否包含终点 true - 包含 | false - 不包含
     * @throws ClassCastException 
     * @throws NullPointerException 
     * @throws IllegalArgumentException 
     */
    NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
                             K toKey,   boolean toInclusive);

    /**
     * 返回键小于(或等于,如果 inclusive 为 true)toKey 的子映射
     * @param toKey 子映射集合的终点
     * @param inclusive 子映射是否包含终点 true - 包含 | false - 不包含
     * @throws ClassCastException
     * @throws NullPointerException
     * @throws IllegalArgumentException
     */
    NavigableMap<K,V> headMap(K toKey, boolean inclusive);

    /**
     * 返回键大于(或等于,如果 inclusive 为 true)fromKey 的子映射
     * @param fromKey 子映射集合的起点
     * @param inclusive 子映射是否包含起点 true - 包含 | false - 不包含
     * @throws ClassCastException 
     * @throws NullPointerException 
     * @throws IllegalArgumentException
     */
    NavigableMap<K,V> tailMap(K fromKey, boolean inclusive);

    /************************** SortedMap 兼容方法 **************************/
    /**
     * 等价于 subMap(fromKey, true, toKey, false)
     * @throws ClassCastException       {@inheritDoc}
     * @throws NullPointerException     {@inheritDoc}
     * @throws IllegalArgumentException {@inheritDoc}
     */
    SortedMap<K,V> subMap(K fromKey, K toKey);

    /**
     * 等价于 headMap(toKey, false)
     * @throws ClassCastException       {@inheritDoc}
     * @throws NullPointerException     {@inheritDoc}
     * @throws IllegalArgumentException {@inheritDoc}
     */
    SortedMap<K,V> headMap(K toKey);

    /**
     * 等价于 tailMap(fromKey, true)
     * @throws ClassCastException       {@inheritDoc}
     * @throws NullPointerException     {@inheritDoc}
     * @throws IllegalArgumentException {@inheritDoc}
     */
    SortedMap<K,V> tailMap(K fromKey);
}

        NavigableMap 的这些方法使得对有序映射的操作更加灵活和方便,可以轻松实现查找、子集和导航等操作。Java 中的 TreeMapNavigableMap 接口的一个常见实现

三,TreeMap

        TreeMap 是 NavigableMap 的子类,并且是一颗通过红黑树实现 NavigableMap。

 

3.1 TreeMap 继承结构

package java.util;
public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{/** 忽略代码 */}

 

3.2 TreeMap 属性

public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{

    /** 比较器,用于 key 排序 */
    @SuppressWarnings("serial")
    private final Comparator<? super K> comparator;

    /** TreeMap 的根节点,毕竟是一颗红黑树 */
    private transient Entry<K,V> root;

    /** 当前 TreeMap 的元素数量大小 */
    private transient int size = 0;

    /** 当前集合修改次数 */
    private transient int modCount = 0;

    /** 忽略其他代码 */
}

3.3 TreeMap 构造器

【无参构造】默认指定比较器,默认使用key的自然排序

    public TreeMap() {
        comparator = null;
    }

【单参构造】指定比较器进行创建

    public TreeMap(Comparator<? super K> comparator) {
        this.comparator = comparator;
    }

【单参构造】指定元素映射集进行创建

    public TreeMap(Map<? extends K, ? extends V> m) {
        comparator = null;
        putAll(m);
    }

 【单参构造】指定SortedMap 元素集进行构造,并且直接使用 SortedMap的比较器

    public TreeMap(SortedMap<K, ? extends V> m) {
        comparator = m.comparator();
        try {
            buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
        } catch (java.io.IOException | ClassNotFoundException cannotHappen) {
        }
    }

3.4 TreeMap 内部类

3.4.1 Values

        Values 是 TreeMap 中所有 value 的视图集合。

3.4.2 KeySet

        KeySet 是 TreeMap 中所有 key 的视图集合,类型为 Set 集合,原因是 key 是不允许有重复的;该类还实现NavigableSet 意味着同样丰富的导航视图方法

3.4.3 EntrySet

        key 有对应的视图,value 也有对应的视图,剩下就是key-value 的映射键值对没有对应的视图,所以EntrySet 就是 TreeMap 中所有映射键值对的视图集合。但是 TreeMap 本身就不是一个映射键值对的集合吗?为什么其内部还要在追加一个 EntrySet 视图集合??? EntrySet 视图集合的重点在于视图,一般视图都是重点在可读,也就是在迭代,查询等业务中使用到的。有一些特殊情况,也会提高一两个写的方法。比如下面的删除。

3.4.5 相关集合迭代器

3.4.5.1 PrivateEntryIterator 迭代器

        privateEntryIterator 迭代器,是 TreeMap 所有迭代器的基类。

   

3.4.5.2 ValueIterator 迭代器

        value 的迭代器,直接逐个迭代到最后一个为止        

3.4.5.3 KeyIterator 迭代器

          
3.4.5.4 EntryIterator 迭代器

3.4.5.5 DescendingKeyIterator 倒排 key 迭代器

 

3.4.6  相关子集Map

3.4.7 相关分割器

3.4.8 Entry 映射实体类 (红黑树节点)

    static final class Entry<K,V> implements Map.Entry<K,V> {
        K key; // key 真正元素
        V value; // value 真正元素
        Entry<K,V> left; // 左节点
        Entry<K,V> right; // 右节点
        Entry<K,V> parent; // 父节点
        boolean color = BLACK; // 红黑树颜色,默认黑色

        Entry(K key, V value, Entry<K,V> parent) {
            this.key = key;
            this.value = value;
            this.parent = parent;
        }

        public K getKey() {
            return key;
        }

        public V getValue() {
            return value;
        }

        public V setValue(V value) {
            V oldValue = this.value;
            this.value = value;
            return oldValue;
        }

        public boolean equals(Object o) {
            return o instanceof Map.Entry<?, ?> e
                    && valEquals(key,e.getKey())
                    && valEquals(value,e.getValue());
        }

        public int hashCode() {
            int keyHash = (key==null ? 0 : key.hashCode());
            int valueHash = (value==null ? 0 : value.hashCode());
            return keyHash ^ valueHash;
        }

        public String toString() {
            return key + "=" + value;
        }
    }

3.5 TreeMap 新增业务

3.5.1 put(key, value)

        新增的key-value键值对,键值冲突进行替换旧键值

    public V put(K key, V value) {
        return put(key, value, true);
    }

3.5.2 putIfAbsent(key, value)

       新增的key-value键值对,键值冲突不替换旧键值

    @Override
    public V putIfAbsent(K key, V value) {
        return put(key, value, false);
    }

 3.5.3 put(key, value, replaceOld)

        新增的key-value键值对,键值冲突替换不替换旧键值由replaceOld决定

/**
 *
 * @param key   要新增的key
 * @param value 要新增的value
 * @param replaceOld 是否替换旧的值 true - 替换 | false - 不替换
 */
private V put(K key, V value, boolean replaceOld) {
        Entry<K,V> t = root;
        // 如果树是空的(即根节点为 null),则调用 addEntryToEmptyMap 方法插入第一个节点,并返回 null
        if (t == null) {
            addEntryToEmptyMap(key, value);
            return null;
        }
        
        int cmp; // 比较结果
        Entry<K,V> parent; // 父节点
        // cpr:比较器,如果有提供比较器,则使用它进行键的比较;否则,使用键的自然顺序进行比较。
        Comparator<? super K> cpr = comparator;
        if (cpr != null) { // 使用比较器
            do {
                parent = t;
                // 使用提供的比较器 cpr 进行键的比较
                cmp = cpr.compare(key, t.key);
                // 循环遍历树,比较当前键与节点键的大小,决定向左还是向右子树移动。
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                // 如果找到相同的键,根据 replaceOld 参数决定是否替换旧值,并返回旧值
                else {
                    V oldValue = t.value;
                    if (replaceOld || oldValue == null) {
                        t.value = value;
                    }
                    return oldValue;
                }
            } while (t != null);
        } else { // 否则使用自然排序比较
            Objects.requireNonNull(key);
            @SuppressWarnings("unchecked")
            Comparable<? super K> k = (Comparable<? super K>) key;
            do {
                parent = t;
                // 使用自然排序进行键的比较
                cmp = k.compareTo(t.key);
                // 循环遍历树,比较当前键与节点键的大小,决定向左还是向右子树移动。
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                // 如果找到相同的键,根据 replaceOld 参数决定是否替换旧值,并返回旧值
                else {
                    V oldValue = t.value;
                    if (replaceOld || oldValue == null) {
                        t.value = value;
                    }
                    return oldValue;
                }
            } while (t != null);
        }
        // 如果没有找到相同的键,在遍历结束后,根据比较结果 (cmp < 0) 决定新节点插入到父节点的左子树或右子树中。
        addEntry(key, value, parent, cmp < 0);
        return null; // 调用 addEntry 方法进行插入,并返回 null
    }

3.5.4 addEntryToEmptyMap(key, value)

        addEntryToEmptyMap 方法在 TreeMap 为空时用于添加第一个节点(即根节点)。这是一个私有方法,只在 TreeMap 内部使用。 

    private void addEntryToEmptyMap(K key, V value) {
        compare(key, key); // 目的是对键进行类型检查,并确保键非空
        root = new Entry<>(key, value, null);
        // 更新树的大小和修改计数
        size = 1;
        modCount++;
    }

3.5.5 addEntry(key, value, parent, addToLeft)

    /**
     * 新增新的Entry
     * @param key    要插入的key
     * @param value  要插入的value
     * @param parent 新节点的父节点
     * @param addToLeft 新节点是否应该作为父节点的左子节点
     */
    private void addEntry(K key, V value, Entry<K, V> parent, boolean addToLeft) {
        // 将数据封装成一个Entry节点类
        Entry<K,V> e = new Entry<>(key, value, parent);
        if (addToLeft) // 如果该节点是父节点的左子节点则加在左边
            parent.left = e;
        else // 否则是右子节点
            parent.right = e;
        /*
         * 调用 fixAfterInsertion 方法,以确保插入新节点后树仍然满足红黑树的性质
         * fixAfterInsertion 方法会调整节点的颜色和位置,以保持树的平衡性。
         */
        fixAfterInsertion(e);
        // 更新树的大小和修改计数
        size++;
        modCount++;
    }

3.6 TreeMap 删除业务

3.6.1 remove(key)

        根据 key 进行删除 Entry 映射实体类

    public V remove(Object key) {
        Entry<K,V> p = getEntry(key);
        if (p == null)
            return null;

        V oldValue = p.value;
        deleteEntry(p);
        return oldValue;
    }

3.6.2 deleteEntry(e)

        deleteEntry 方法用于从 TreeMap 中删除一个节点。该方法需要确保在删除节点后,树仍然保持红黑树的性质

    private void deleteEntry(Entry<K,V> p) {
        // 1. 更新修改计数和大小
        modCount++; // 增加 modCount 以记录对树结构的修改次数
        size--; // 减少 size,因为我们将删除一个节点

        // 2. 处理有两个子节点的节点
        if (p.left != null && p.right != null) {
            // 如果节点 p 有两个子节点,则找到它的后继节点 s
            Entry<K,V> s = successor(p);
            // 将后继节点 s 的键和值复制到节点 p
            p.key = s.key;
            p.value = s.value;
            // 将 p 更新为后继节点 s,以便在后续步骤中删除 s
            p = s;
        }


        /*
         * 3. 找到替换节点:如果 p 有左子节点,则 replacement 为 p 的左子节点。
         * 否则,如果 p 有右子节点,则 replacement 为 p 的右子节点。
         */
        Entry<K,V> replacement = (p.left != null ? p.left : p.right);

        if (replacement != null) { 
            // 3.1 如果替换节点存在,首先将其父节点指向 p 的父节点
            replacement.parent = p.parent;
            // 3.2 如果 p 是根节点,则将 root 设置为替换节点
            if (p.parent == null)
                root = replacement;
            // 3.3 否则,将替换节点链接到 p 的父节点(作为左子节点或右子节点)
            else if (p == p.parent.left)
                p.parent.left  = replacement;
            else
                p.parent.right = replacement;

            // 3.4 将 p 的左右子节点和父节点都置为 null
            p.left = p.right = p.parent = null;

            // 3.5 如果 p 的颜色是黑色,则调用 fixAfterDeletion 方法修复红黑树的性质。
            if (p.color == BLACK)
                fixAfterDeletion(replacement);
        // p 没有替换节点且是根节点的情况
        } else if (p.parent == null) { 
            root = null; // 如果 p 没有子节点且是根节点,则将 root 设置为 null。

        
        } else { // p 没有替换节点且不是根节点的情况
            // 如果 p 没有子节点且不是根节点,首先检查 p 的颜色。
            // 如果 p 的颜色是黑色,则调用 fixAfterDeletion 方法修复红黑树的性质。
            if (p.color == BLACK)
                fixAfterDeletion(p);

            // 将 p 从父节点的左子节点或右子节点中移除,并将 p 的父节点置为 null。
            if (p.parent != null) {
                if (p == p.parent.left)
                    p.parent.left = null;
                else if (p == p.parent.right)
                    p.parent.right = null;
                p.parent = null;
            }
        }
    }

3.7 TreeMap 查询业务

    public V get(Object key) {
        Entry<K,V> p = getEntry(key);
        return (p==null ? null : p.value);
    }

3.8 TreeMap的 NavigableMap 的 lowerEntry(key)

    public Map.Entry<K,V> lowerEntry(K key) {
        return exportEntry(getLowerEntry(key));
    }
    final Entry<K,V> getLowerEntry(K key) {
        Entry<K,V> p = root;
        // 进行循环比较
        while (p != null) {
            int cmp = compare(key, p.key);
            // key 和 p 比较  大于0 则key在 p 的右边
            if (cmp > 0) {
                if (p.right != null)
                    p = p.right;
                else
                    return p;
            } else { // 否则相反,在左边
                if (p.left != null) {
                    p = p.left;
                } else {
                    Entry<K,V> parent = p.parent;
                    Entry<K,V> ch = p;
                    while (parent != null && ch == parent.left) {
                        ch = parent;
                        parent = parent.parent;
                    }
                    return parent;
                }
            }
        }
        return null;
    }

        其他的相关导航方法也都是类似。

2.9 TreeMap 与 HashMap 区别

1. 底层数据结构

  • TreeMap:
    • 底层使用红黑树(Red-Black Tree)实现。
  • HashMap:
    • 底层使用哈希表(Hash Table)实现。

2. 排序

  • TreeMap:
    • 维护键的自然顺序(或者通过提供的 Comparator 进行排序)。
    • 迭代时,元素是按升序排列的。
  • HashMap:
    • 不保证顺序,键值对的顺序是不可预测的。

3. 性能

  • TreeMap:
    • 插入、删除和查找操作的时间复杂度为 O(log⁡n)O(\log n)O(logn)。
  • HashMap:
    • 插入、删除和查找操作的平均时间复杂度为 O(1)O(1)O(1),但在最坏情况下为 O(n)O(n)O(n)(例如所有键都碰撞在同一个桶中)。

4. 空间复杂度

  • TreeMap:
    • 相对来说空间开销较大,因为需要维护红黑树的结构。
  • HashMap:
    • 空间利用率较高,因为哈希表通常只存储键值对和少量的元数据。

5. null 值

  • TreeMap:
    • 不允许 null 键,但允许 null 值。
  • HashMap:
    • 允许 null 键和 null 值。

6. 使用场景

  • TreeMap:
    • 适用于需要键有序的情况,例如需要按顺序遍历键值对,或者需要范围查找(如子集、头部集或尾部集)。
  • HashMap:
    • 适用于对顺序没有要求的情况,只需快速插入、删除和查找操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/783108.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用langchain与你自己的数据对话(二):向量存储与嵌入_langchain chat with your data

之前我以前完成了“使用langchain与你自己的数据对话(一)&#xff1a;文档加载与切割这篇文章&#xff0c;没有阅读的朋友可以先阅读一下&#xff0c;今天我们来继续讲解第三门课&#xff1a;向量存储与嵌入。 Langchain在实现与外部数据对话的功能时需要经历下面的5个阶段&am…

【智能制造-11】X型焊枪和C型焊枪

手工焊枪分为X型焊枪和C型焊枪两种。 X焊枪中&#xff0c;气缸活塞杆与活动枪臂体之间以轴连接&#xff0c;气缸活塞做直线运动&#xff0c;焊枪臂绕转轴摆动&#xff0c;进行焊接。 C型焊枪中&#xff0c;气缸活塞杆与活动枪臂联动&#xff0c;进行直线往复运动&#xff0c;进…

简单实现联系表单Contact Form自动发送邮件

如何实现简单Contact Form自动邮件功能&#xff1f;怎样简单设置&#xff1f; 联系表单不仅是访客与网站所有者沟通的桥梁&#xff0c;还可以收集潜在客户的信息&#xff0c;从而推动业务的发展。AokSend将介绍如何简单实现一个联系表单&#xff0c;自动发送邮件的过程&#x…

声明一个类模板,利用它分别实现两个整数、浮点数和字符的比较,求出大数和小数

在之前的文章中曾介绍了函数模板&#xff0c;对于功能相同而数据类型不同的一些函数&#xff0c;不必定义各个函数&#xff0c;可以定义一个可对任何类型变量进行操作的函数模板&#xff0c;在调用函数时&#xff0c;系统会根据实参的类型&#xff0c;取代函数模板中的类型参数…

应用层协议原理——因特网提供的运输服务

我们已经考虑了计算机网络能够一般性地提供的运输服务。现在我们要更为具体地考察由因特网提供的运输服务类型。因特网(更一般的是TCP/IP网络)为应用程序提供两个运输层协议&#xff0c;即UDP和TCP。当软件开发者为因特网创建一个新的应用时&#xff0c;首先要做出的决定是&…

游戏AI的创造思路-技术基础-决策树(2)

上一篇写了决策树的基础概念和一些简单例子&#xff0c;本篇将着重在实际案例上进行说明 目录 8. 决策树应用的实际例子 8.1. 方法和过程 8.1.1. 定义行为 8.1.2. 确定属性 8.1.3. 构建决策树 8.1.4. 实施行为 8.1.5. 实时更新 8.2. Python代码 8. 决策树应用的实际例子…

大模型网信办备案全网最详细说明【+流程+附件】

根据目前公开的国内大模型算法备案统计来看&#xff0c;首批境内深度合成服务算法备案清单&#xff0c;总共通过41家&#xff0c;14家互联网大厂和独角兽企业成功申报算法备案32个&#xff0c;6家新兴互联网公司成功申报算法备案9个&#xff0c;仅占比21.9%。 第二批境内…

Python标准库常用模块的典型用法介绍与案例

目录 1. os模块 典型用法 案例 2. sys模块 典型用法 案例 3. datetime模块 典型用法 案例 4. re模块 典型用法 案例 5. json模块 典型用法 案例 6. random模块 典型用法 案例 7. collections模块 典型用法 案例 总结 Python作为一门功能强大的编…

控件-ProgressBar

常用属性 1.android:max:进度条的最大值 2. android: progress:进度条已完成进度值 3. android: indeterminate:如果设置成true,则进度条不精确显示进度 4.style"?android:attr/progressBarStyleHorizontal"水平进度条 案例 进度条加载

探索TXE、TC、RXNE标志位在串口通信中的轮询与中断应用

浅谈一下STM32串口中断之TXE,TC,RXNE标志位 之前做一个项目&#xff0c;用到了串口中断&#xff0c;但是对TXE、TC和RXNE标志位的作用和使用方法不是很清楚&#xff0c;导致在调试过程中遇到了一些问题。通过查阅相关资料和实际操作&#xff0c;我对这三个标志位有了更深入的了…

Python酷库之旅-第三方库Pandas(010)

目录 一、用法精讲 22、pandas.read_hdf函数 22-1、语法 22-2、参数 22-3、功能 22-4、返回值 22-5、说明 22-6、用法 22-6-1、数据准备 22-6-2、代码示例 22-6-3、结果输出 23、pandas.HDFStore.put方法 23-1、语法 23-2、参数 23-3、功能 23-4、返回值 23-5…

【数据分析】Pandas_DataFrame读写详解:案例解析(第24天)

系列文章目录 一、 读写文件数据 二、df查询数据操作 三、df增加列操作 四、df删除行列操作 五、df数据去重操作 六、df数据修改操作 文章目录 系列文章目录前言一、 读写文件数据1.1 读写excel文件1.2 读写csv文件1.3 读写mysql数据库 二、df查询数据操作2.1 查询df子集基本方…

2.5 C#视觉程序开发实例1----CamManager实现模拟相机采集图片

2.5 C#视觉程序开发实例1----CamManager实现模拟相机采集图片 1 目标效果视频 CamManager 2 CamManager读取本地文件时序 3 BD_Vision_Utility添加代码 3.0 导入链接库 BD_OperatorSets.dllSystem.Windows.Forms.dllOpencvSharp 3.1 导入VisionParam中创建的文件Util_FileO…

乡村振兴指数与其30个原始变量数据(Shp/Dta/Excel格式,2000-2022年)

数据简介&#xff1a;这份数据是我国各地级市乡村振兴指数与其30各原始变量数据并对其进行地图可视化表达。城镇化是当今中国社会经济发展的必由之路。当前我国城镇化处于发展的关键时期&#xff0c;但城镇化发展的加快却是一把双刃剑&#xff0c;为何要如此形容呢?因为当前城…

【04】微服务通信组件Feign

1、项目中接口的调用方式 1.1 HttpClient HttpClient 是 Apache Jakarta Common 下的子项目&#xff0c;用来提供高效的、最新的、功能丰富的支持 Http 协议的客户端编程工具包&#xff0c;并且它支持 HTTP 协议最新版本和建议。HttpClient 相比传统 JDK 自带的 URLConnectio…

科研绘图系列:R语言径向柱状图(Radial Bar Chart)

介绍 径向柱状图(Radial Bar Chart),又称为雷达图或蜘蛛网图(Spider Chart),是一种在极坐标系中绘制的柱状图。这种图表的特点是将数据点沿着一个或多个从中心向外延伸的轴来展示,这些轴通常围绕着一个中心点均匀分布。 特点: 极坐标系统:数据点不是在直角坐标系中展…

AI时代还需要产品经理吗?需要什么样的?

在人工智能技术迅速发展的今天&#xff0c;我们不禁要思考&#xff0c;产品经理这个角色是否仍然重要&#xff1f;AI时代是否还需要他们&#xff1f; 很明确的说&#xff0c;需要&#xff01;为什么呢&#xff1f; 首先&#xff0c;我们必须认识到&#xff0c;AI虽然具有强大…

如何理解李彦宏说的“不要卷模型,要卷应用”

如何理解李彦宏说的“不要卷模型&#xff0c;要卷应用” “大家不要卷模型&#xff0c;要卷应用”这句话的意思是&#xff0c;呼吁行业不要把过多的精力和资源投入到模型的研发竞争中&#xff0c;而是应该更加注重基于模型的应用开发。 李彦宏提出这一观点的原因主要有以下几点…

容联云发布容犀大模型应用,重塑企业“营销服”|WAIC 2024

7月6日&#xff0c;在2024世界人工智能大会上&#xff0c;容联云成功举办主题为“数智聚合 产业向上”的生成式应用与大模型商业化实践论坛。 论坛上&#xff0c;容联云发布了容犀智能大模型应用升级&#xff0c;该系列应用包括容犀Agent Copilot、容犀Knowledge Copilot、容犀…

PHP星座微信小程序系统源码

&#x1f31f;每日星运&#xff0c;尽在掌握&#xff01;星座微信小程序&#xff0c;你的专属星空指南✨ &#x1f308; 一、每日运势&#xff0c;精准推送 想知道今天的你运势如何&#xff1f;星座微信小程序来告诉你&#xff01;&#x1f52e; 每天醒来&#xff0c;打开小程…