简述C++map容器

news2024/12/25 6:09:23

pair键值对

std::pair在很多关联容器(如std::mapstd::multimapstd::setstd:multiset等)中被广泛应用。以std::map为例,std::map是一个键值对的容器,其中每个元素都是一个std::pair,键用于唯一标识元素,值则是与键相关联的数据。

pair是类模板,一般用于表示key/value数据,其实现是结构体。

pair结构模板的定义如下:

template <class T1, class T2>

struct pair

{

    T1 first;     // 第一个成员,一般表示key。

    T2 second;  // 第二个成员,一般表示value。

      pair();       // 默认构造函数。

      pair(const T1 &val1,const T2 &val2);   // 有两个参数的构造函数。

      pair(const pair<T1,T2> &p);           // 拷贝构造函数。

      void swap(pair<T1,T2> &p);           // 交换两个pair。

};

make_pair函数模板的定义如下:

template <class T1, class T2>

make_pair(const T1 &first,const T2 &second)

{

      return pair<T1,T2>(first, second);

}

示例代码:

#include <iostream>
#include<utility>

using  namespace std;

template <class T1, class T2>
struct Pair
{
	T1 first;        // 第一个成员,一般表示key。
	T2 second;  // 第二个成员,一般表示value。
	Pair() {
		cout << "调用了有默认的构造函数。\n";
	}
	Pair(const T1& val1, const T2& val2) :first(val1), second(val2) {
		cout << "调用了有两个参数的构造函数。\n";
	}
	Pair(const Pair<T1, T2>& p) : first(p.first), second(p.second) {
		cout << "调用了拷贝构造函数。\n";
	}
};

template <class T1, class T2>
Pair<T1, T2> make_Pair(const T1& first, const T2& second)
{
	// Pair<T1, T2> p(first, second);
	// return p;        // 返回局部对象。
	return Pair<T1, T2>(first, second);  // 返回临时对象。
}

int main()
{
	pair<int, string> p0;
	cout << "p0 first=" << p0.first << ",second=" << p0.second << endl;

	pair<int, string> p1(1, "吴彦祖");    // 两个参数的构造函数。
	cout << "p1 first=" << p1.first << ",second=" << p1.second << endl;

	pair<int, string> p2 = p1;             // 拷贝构造。
	cout << "p2 first=" << p2.first << ",second=" << p2.second << endl;

	p2.swap(p0);
	cout << "p0 first=" << p0.first << ",second=" << p0.second << endl;
	cout << "p2 first=" << p2.first << ",second=" << p2.second << endl;

	auto p3 = make_pair(2, "陈冠希");
	cout << "键:" << p3.first << ", 值:" << p3.second << endl;
}

运行结果: 

map容器

map 容器封装了红黑树(平衡二叉排序树),用于查找。

包含头文件: #include<map>

map容器的元素是pair键值对。

迭代器是双向迭代器。

map类模板的声明:

template <class K, class V, class P = less<K>, class _Alloc = allocator<pair<const K, V >>>

class map : public _Tree<_Tmap_traits< K, V, P, _Alloc, false>>

{

   …

}

第一个模板参数K:key的数据类型(pair.first)。

第二个模板参数V:value的数据类型(pair.second)。

第三个模板参数P:排序方法,缺省按key升序。

第四个模板参数_Alloc:分配器,缺省用new和delete。

map提供了双向迭代器。

二叉链表:                               

struct BTNode                       

{                                 

   pair<K,V> p;       // 键值对。      

      BTNode *parent;   // 父节点。   

      BTNode *lchirld;    // 左子树。

      BTNode *rchild;    // 右子树。

};                                     

一、构造函数

1)map();  // 创建一个空的map容器。

2)map(initializer_list<pair<K,V>> il); // 使用统一初始化列表。

3)map(const map<K,V>& m);  // 拷贝构造函数。

4)map(Iterator first, Iterator last);  // 用迭代器创建map容器。

5)map(map<K,V>&& m);  // 移动构造函数(C++11标准)。

二、特性操作

size_t size() const;        // 返回容器的实际大小(已使用的空间)。

bool empty() const;      // 判断容器是否为空。

void clear();             // 清空容器。

三、元素操作

V &operator[](K key);             // 用给定的key访问元素。

const V &operator[](K key) const;  // 用给定的key访问元素,只读。

V &at(K key);                     // 用给定的key访问元素。

const V &at(K key) const;         // 用给定的key访问元素,只读。

注意:

1)[ ]运算符:如果指定键不存在,会向容器中添加新的键值对;如果指定键不存在,则读取或修改容器中指定键的值。

2)at()成员函数:如果指定键不存在,不会向容器中添加新的键值对,而是直接抛出out_of_range 异常。

示例代码:

#include <iostream>
#include <map>
using  namespace std;

int main()
{
	map<string, string> m({ { "08","冠希" }, { "03","于晏" }, { "01","彦祖" }, { "07","德华" }, { "05","学友" } });

	cout << "m[08]=" << m["08"] << endl;     // 显示key为08的元素的value。
	cout << "m[09]=" << m["09"] << endl;    // 显示key为09的元素的value。key为09的元素不存在,将添加新的键值对。
	cout << "m.at(03)=" << m.at("03") << endl;
	//m.at("099");错误!!
	m["07"] = "黎明";                                          // 把key为07的元素的value修改为黎明。
	m["12"] = "富城";                                          // 将添加新的键值对。

	for (auto& val : m)
		cout << val.first << "," << val.second << "  ";
	cout << endl;
}

运行结果:

四、赋值操作

给已存在的容器赋值,将覆盖容器中原有的内容。

1)map<K,V> &operator=(const map<K,V>& m);         // 把容器m赋值给当前容器。

2)map<K,V> &operator=(initializer_list<pair<K,V>> il);  // 用统一初始化列表给当前容器赋值。

五、交换操作

void swap(map<K,V>& m);    // 把当前容器与m交换。

交换的是树的根结点。

六、比较操作

bool operator == (const map<K,V>& m) const;

bool operator != (const map<K,V>& m) const;

七、查找操作

1)查找键值为key的键值对

在map容器中查找键值为key的键值对,如果成功找到,则返回指向该键值对的迭代器;失败返回end()。

iterator find(const K &key);

const_iterator find(const K &key) const;  // 只读。

2)查找键值>=key的键值对

在map容器中查找第一个键值>=key的键值对,成功返回迭代器;失败返回end()。

iterator lower_bound(const K &key);

const_iterator lower_bound(const K &key) const;  // 只读。

3)查找键>key的键值对

在map容器中查找第一个键值>key的键值对,成功返回迭代器;失败返回end()。

iterator upper_bound(const K &key);

const_iterator upper_bound(const K &key) const;  // 只读。

4)统计键值对的个数

统计map容器中键值为key的键值对的个数。

size_t count(const K &key) const;

八、插入和删除

1)void insert(initializer_list<pair<K,V>> il);  // 用统一初始化列表在容器中插入多个元素。

2)pair<iterator,bool> insert(const pair<K,V> &value);  // 在容器中插入一个元素,返回值pair:first是已插入元素的迭代器,second是插入结果。

3)void insert(iterator first,iterator last);  // 用迭代器插入一个区间的元素。

4)pair<iterator,bool> emplace (...);  // 将创建新键值对所需的数据作为参数直接传入,map容器将直接构造元素。返回值pair:first是已插入元素的迭代器,second是插入结果。

例:mm.emplace(piecewise_construct, forward_as_tuple(8), forward_as_tuple("冰冰", 18));

5)iterator emplace_hint (const_iterator pos,...); // 功能与第4)个函数相同,第一个参数提示插入位置,该参数只有参考意义,如果提示的位置是正确的,对性能有提升,如果提示的位置不正确,性能反而略有下降,但是,插入是否成功与该参数元关。该参数常用end()和begin()。成功返回新插入元素的迭代器;如果元素已经存在,则插入失败,返回现有元素的迭代器。

6)size_t erase(const K & key);  // 从容器中删除指定key的元素,返回已删除元素的个数。

7)iterator erase(iterator pos);  // 用迭代器删除元素,返回下一个有效的迭代器。

8)iterator erase(iterator first,iterator last);  // 用迭代器删除一个区间的元素,返回下一个有效的迭代器。

示例代码:

#include <iostream>
#include <map>
using  namespace std;

int main()
{
	map<string, string> m({ { "08","冠希" }, { "03","于晏" }, { "01","彦祖" }, { "07","德华" }, { "05","学友" } });

	// 执行插入操作并检查返回值
	auto result = m.insert(make_pair("08", "富城"));

	// result的类型是std::pair<std::map<std::string, std::string>::iterator, bool>
	// result.first是指向插入位置的迭代器(如果插入成功)或已存在相同键的迭代器(如果插入失败)
	// result.second是一个布尔值,表示插入是否成功

	if (result.second) {
		std::cout << "插入成功" << std::endl;
	}
	else {
		std::cout << "插入失败,键已存在" << std::endl;
	}

	for (auto& val : m)
		cout << val.first << "," << val.second << "  ";
	cout << endl;

	

	// 在map容器中查找键值为key的键值对,如果成功找到,则返回指向该键值对的迭代器;失败返回end()。
	auto it1 = m.find("05");
	if (it1 != m.end())
		cout << "查找成功:" << it1->first << "," << it1->second << endl;
	else
		cout << "查找失败。\n";

	// 在map容器中查找第一个键值 >= key的键值对,成功返回迭代器;失败返回end()。
	auto it2 = m.lower_bound("05");
	if (it2 != m.end())
		cout << "查找成功:" << it2->first << "," << it2->second << endl;
	else
		cout << "查找失败。\n";

	//	在map容器中查找第一个键值 > key的键值对,成功返回迭代器;失败返回end()。
	auto it3 = m.upper_bound("05");
	if (it3 != m.end())
		cout << "查找成功:" << it3->first << "," << it3->second << endl;
	else
		cout << "查找失败。\n";

	//	统计map容器中键值为key的键值对的个数。
	cout << "count(05)=" << m.count("05") << endl;   // 返回1。
	cout << "count(06)=" << m.count("06") << endl;   // 返回0。
}

运行结果: 

std::map 的 insert 函数在遇到重复键的情况时,会根据其内部实现做出相应处理。通常情况下,它不会覆盖已有的键值对(与 std::unordered_map 不同,std::unordered_map 若插入重复键,会覆盖原来的值),而是会返回一个表示插入结果的对象,这个对象包含了一些信息来表明插入操作是否真正成功插入了新元素。 我们可以接受返回值来确认是否插入成功。

在容器中插入一个元素,返回值pair:first是已插入元素的迭代器,second是插入结果。

按照字符串的字典序比较规则(这也是 std::map 默认用于比较键的规则,因为键是 std::string 类型):

"01" < "03" < "05" < "07" < "08"

所以查找lower和upper时候会找到学友和德华;

unordered_map容器

unordered(无序)

unordered_map容器封装了哈希表,查找、插入和删除元素时,只需要比较几次key的值。

包含头文件: #include<unordered_map>

unordered_map容器的元素是pair键值对。

unordered_map类模板的声明:

template <class K, class V, class _Hasher = hash<K>, class _Keyeq = equal_to<K>,

    class _Alloc = allocator<pair<const K, V>>>

class unordered_map : public _Hash<_Umap_traits<K, V, _Uhash_compare<K, _Hasher, _Keyeq>, _Alloc, false>>

{

      …

}

第一个模板参数Kkey的数据类型(pair.first)。

第二个模板参数Vvalue的数据类型(pair.second)。

第三个模板参数_Hasher:哈希函数,默认值为std::hash<K>

第四个模板参数_Keyeq:比较函数,用于判断两个key是否相等,默认值是std::equal_to<K>

第五个模板参数_Alloc:分配器,缺省用newdelete

创建std::unordered_map类模板的别名:

template<class K,class V>

using umap = std::unordered_map<K, V>;

std::map 和 std::unordered_map 区别:

1. 底层数据结构

  • std::map

    • std::map 的底层数据结构是基于红黑树(Red-Black Tree)实现的。红黑树是一种自平衡二叉搜索树,它在插入和删除节点时会通过一系列的旋转和颜色调整操作来保持树的平衡,使得树的高度始终保持在一个相对较低的水平(最坏情况下为 O(logn),其中n  是树中节点的数量)。
    • 这种数据结构的优点是能够保证元素按照键的大小顺序进行有序存储,并且在查找、插入和删除操作时,平均时间复杂度都为O(logn) 。例如,当你插入一个新的键值对到 std::map 中时,它会根据键的大小在红黑树中找到合适的位置进行插入,并自动调整树的结构以保持平衡和有序。
  • std::unordered_map

    • std::unordered_map 的底层数据结构是基于哈希表(Hash Table)实现的。哈希表通过一个哈希函数将键映射到一个特定的桶(Bucket)中,每个桶可以存储一个或多个键值对。理想情况下,当哈希函数设计得比较好时,查找操作可以在常数时间O(1)  内完成,因为可以通过计算键的哈希值直接定位到对应的桶,然后在桶内进行查找。
    • 然而,哈希表存在哈希冲突(Hash Collision)的问题,即不同的键可能通过哈希函数计算得到相同的哈希值,从而被映射到同一个桶中。为了解决哈希冲突,通常会采用一些冲突解决策略,如链地址法(将冲突的键值对链接成一个链表存放在同一个桶中)或开放地址法(通过一定的规则在哈希表中重新寻找空闲的位置来存放冲突的键值对)。

2、元素顺序

由于其基于红黑树的实现,std::map 中的元素会按照键的大小顺序自动进行排序。unordered_map 中的元素是无序的,因为哈希表本身并不保证元素的顺序。键值对在哈希表中的存储位置主要取决于键的哈希值以及冲突解决策略。所以,当你遍历 unordered_map 时,元素的出现顺序是不确定的,可能与插入顺序不同,也不一定按照键的任何特定顺序排列

例如:

#include <iostream>
#include <unordered_map>

int main() {
    std::unordered_map<int, std::string> myUnorderedMap;

    myUnorderedMap.insert({ 1, "one" });
    myUnorderedMap.insert({ 3, "three" });
    myUnorderedMap.insert({ 2, "two" });

    // 遍历unordered_map输出所有键值对,顺序不确定
    for (auto it = myUnorderedMap.begin(); it != myUnorderedMap.end(); ++it) {
        std::cout << "键:" << it->first << ", 值:" << it->second << std::endl;
    }

    return 0;
}

 

这个结果每次输出结果都一样,这其实是有一定概率会出现的情况。虽然理论上 std::unordered_map 的遍历顺序是不确定的,因为它是基于哈希表实现的,元素存储位置取决于键的哈希值以及哈希冲突解决策略等因素。但在实际情况中,如果数据量比较小,而且哈希函数(std::unordered_map 默认的哈希函数或者你自定义的哈希函数,如果有的话)对于你所插入的这些键计算出来的哈希值分布相对比较均匀,没有产生过多的哈希冲突,那么就有可能每次遍历输出的顺序看起来是一样的

不过,当你插入的数据量逐渐增大,或者插入一些特殊的键值使得哈希冲突情况发生变化时,就很可能会出现不同的遍历顺序了。

例如:

#include <iostream>
#include <unordered_map>
#include<random>
#include<utility>
int main() {
    std::unordered_map<int, int> myUnorderedMap;

    for (int i = 1; i < 1000000; i++)
    {
        std::random_device rd;
        std::mt19937 gen(rd());

        // 定义分布范围为1到1000000
        std::uniform_int_distribution<> dis(1, 1000000);

        // 生成随机数
        int randomNumber = dis(gen);
        myUnorderedMap.insert(std::make_pair(i, randomNumber));
    }

   

    // 遍历unordered_map输出所有键值对,顺序不确定
    for (auto it = myUnorderedMap.begin(); it != myUnorderedMap.end(); ++it) {
        std::cout << "键:" << it->first << ", 值:" << it->second << std::endl;
    }

    return 0;
}

如果生成的数足够多,顺序是不确定的。

3、查找、插入和删除操作的性能特点

  • std::map

    • 查找、插入和删除操作的平均时间复杂度都是 O(logn)。这意味着在数据量较大时,这些操作的执行时间会随着数据量的增加而以对数级别的速度增长。虽然这种增长速度相对较慢,但相比一些常数时间复杂度的操作(如理想情况下的哈希表查找)还是要慢一些。不过,由于 std::map 能够保持元素的有序性,在一些需要基于顺序进行查找(如查找某个键值对之后的所有键值对)或者进行范围查找(如查找键在某个区间内的所有键值对)的场景下,它具有独特的优势。
  • std::unordered_map

    • 在理想情况下,查找操作的时间复杂度可以达到 O(1),即可以在常数时间内完成查找。这是因为通过哈希函数可以直接定位到键值对可能所在的桶,然后在桶内进行查找。然而,实际情况中,由于哈希冲突的存在,当哈希冲突比较严重时,查找操作可能会退化为链表查找(如果采用链地址法解决冲突),此时查找时间复杂度可能会变为O(n) ,其中  是桶内键值对的数量。插入和删除操作的时间复杂度也类似,在理想情况下为 O(1),但在哈希冲突严重时可能会变差。总体来说,当哈希函数设计得比较好,并且哈希冲突不太严重时,std::unordered_map 在查找、插入和删除操作上的性能要优于 std::map

4. 内存占用

  • std::map

    • 由于红黑树需要存储节点之间的指针以及用于保持树平衡的额外信息(如节点的颜色等),相对来说内存占用可能会比 std::unordered_map 要多一些。具体的内存占用情况还会受到键值对类型、树的大小等因素的影响。
  • std::unordered_map

    • std::unordered_map 的内存占用主要取决于哈希表的大小(即桶的数量)以及键值对的数量。一般来说,为了减少哈希冲突,哈希表可能需要设置较大的桶数,这可能会导致一定的内存浪费。但总体而言,在数据量较大且哈希冲突不严重的情况下,std::unordered_map 的内存占用可能相对 std::map 会有一定的优势。

5、总结

std::map 和 std::unordered_map 各有优缺点,在实际应用中,需要根据具体的应用场景和需求来选择合适的容器。如果需要元素按照键的顺序存储并且对查找、插入和删除操作的平均性能要求不是特别高(能够接受O(logn)  的时间复杂度),那么 std::map 是一个不错的选择;如果更看重查找、插入和删除操作的快速执行(希望在理想情况下达到 O(1) 的时间复杂度),并且不需要元素按照特定顺序排列,那么 std::unordered_map 则更为合适。 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

刷题计划 day22回溯(一)【组合】【组合总和 III】【电话号码的字母组合】

⚡刷题计划day22 回溯&#xff08;一&#xff09;开始&#xff0c;此期开启回溯专题&#xff0c;敬请期待关注&#xff0c;可以点个免费的赞哦~ 往期可看专栏&#xff0c;关注不迷路&#xff0c; 您的支持是我的最大动力&#x1f339;~ 目录 回溯算法理论基础 回溯法解决的…

Qt桌面应用开发 第六天(鼠标事件 定时器事件 定时器类 事件分发器 事件过滤器)

目录 1.1鼠标进入和离开enterEvent\leaveEvent 1.2鼠标按下释放和移动mousePressEvent\mouseReleaseEvent\mouseMoveEvent 1.3定时器事件timerEvent 1.4定时器类QTimer 1.5事件分发器event 1.6事件过滤器eventFilter 1.1鼠标进入和离开enterEvent\leaveEvent 事件&#x…

【Linux清空显存占用】Linux 系统中清理 GPU 显存

操作指令 # 查看NVIDIA GPU状态和进程 nvidia-smi # 查找所有包含"python"的进程 ps -ef | grep python # 强制结束进程号为3023的进程 kill -9 3023截图演示 在 Linux 系统中清理 GPU 显存可以采用以下方法&#xff1a; 1. 终止特定进程&#xff08;常用方法&…

对撞双指针(七)三数之和

15. 三数之和 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答案中不可以包含重复的三元组…

vue2-基础核心

vue简介 动态构建用户界面的渐进式 JavaScript 框架 vue的特点: 遵循MVVM模式 采用组件化模式&#xff0c;提高代码复用率&#xff0c;让代码更好维护 声明式编码&#xff0c;无需直接操作DOM&#xff0c;提高开发效率&#xff0c;编码简洁、体积小&#xff0c;运行效率高 本…

Prompting LLMs to Solve Complex Tasks: A Review

文章目录 题目简介任务分解未来方向结论 题目 促使 LLM 解决复杂任务&#xff1a; 综述 论文地址&#xff1a;https://www.intjit.org/cms/journal/volume/29/1/291_3.pdf 简介 大型语言模型 (LLM) 的最新趋势显而易见&#xff0c;这体现在大型科技公司的投资以及媒体和在线社…

反射、依赖注入

特性和依赖注入都是基于反射的&#xff0c;同时反射一般和接口配合着使用。 接口隔离原则 接口隔离原则&#xff1a;主张应该把客户端对一个类的需求分解成更小、更具体的接口&#xff0c;而不是提供一个包含所有功能的大接口。 接口中的需求是&#xff1a;乙方不能少给&am…

MT8768/MTK8768安卓核心板性能参数_联发科安卓智能模块开发方案

MT8768安卓核心板 是一款采用台积电12nm FinFET制程工艺的智能手机芯片。MT8768核心板不仅提供所有高级功能和出色体验&#xff0c;同时确保智能终端具备长电池寿命。该芯片提供了一个1600x720高清(20:9比例)分辨率显示屏&#xff0c;排除了清晰度和功耗之间的平衡问题。该芯片…

VBA技术资料MF229:以毫米为单位设置行高和列宽

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

深入JMeter核心引擎:揭秘JmeterEngine、StandardJmeterEngine、ClientJmeterEngine与Remote的奥秘

引言 Apache JMeter是一款广泛使用的开源性能测试工具&#xff0c;它能够帮助开发者和测试人员模拟大量并发用户对应用程序进行负载测试。JMeter的强大功能和灵活性源于其精心设计的核心引擎。本文将深入探讨JMeter的核心引擎&#xff0c;包括JmeterEngine、StandardJmeterEng…

软件工程导论 选填题知识点总结

一 原型化方法是一种动态定义需求的方法&#xff0c;提供完整定义的需求不是原型化方法的特征&#xff0c;其特征包括尽快建立初步需求、简化项目管理以及加强用户参与和决策。 软件危机的表现包括用户对已完成的软件系统不满意的现象经常发生、软件产品的质量往往靠不住、软件…

Rust中Tracing 应用指南

欢迎来到这篇全面的Rust跟踪入门指南。Rust 的tracing是一个用于应用程序级别的诊断和调试的库。它提供了一种结构化的、异步感知的方式来记录日志和跟踪事件。与传统的日志记录相比&#xff0c;tracing能够更好地处理复杂的异步系统和分布式系统中的事件跟踪&#xff0c;帮助开…

机器学习实战:银行客户是否认购定期存款

项目结构与步骤 1. 项目概述 项目名称&#xff1a;葡萄牙银行电话营销活动分析与定期存款认购预测目标&#xff1a;通过分析银行的电话营销数据&#xff0c;构建模型预测客户是否会认购定期存款。数据来源&#xff1a;葡萄牙银行营销活动数据集关键挑战&#xff1a;数据不平衡…

服务器数据恢复—raid5阵列热备盘上线失败导致EXT3文件系统不可用的数据恢复案例

服务器数据恢复环境&#xff1a; 两组分别由4块SAS硬盘组建的raid5阵列&#xff0c;两组阵列划分的LUN组成LVM架构&#xff0c;格式化为EXT3文件系统。 服务器故障&#xff1a; 一组raid5阵列中的一块硬盘离线。热备盘自动上线替换离线硬盘&#xff0c;但在热备盘上线同步数据…

C++vector

Cvector是标准库中的一员&#xff0c;vector直译过来是“向量”、“矢量”的意思&#xff0c;在C中&#xff0c;是一个动态的数组容器&#xff0c;可以动态的开辟空间&#xff0c;自动实现内存的管理&#xff0c;不需要我们手动操作&#xff0c;在标准库中&#xff0c;写作一个…

“漫步北京”小程序及“气象景观数字化服务平台”上线啦

随着科技的飞速发展&#xff0c;智慧旅游已成为现代旅游业的重要趋势。近日&#xff0c;北京万云科技有限公司联合北京市气象服务中心&#xff0c;打造的“气象景观数字化服务平台“和“漫步北京“小程序已经上线&#xff0c;作为智慧旅游的典型代表&#xff0c;以其丰富的功能…

LlamaIndex+本地部署InternLM实践

LlamaIndex本地部署InternLM实践 XTuner是一个调整模型参数的小工具,通过对于给定的大模型输入有限的参数来调整同类型问题的结果输出 ‌LlamaIndex‌是一个将大语言模型&#xff08;LLMs&#xff09;和外部数据连接在一起的工具&#xff0c;主要用于增强大模型的知识获取能力…

【阵列信号处理】相干信号和非相干信号生成

文章目录 一、总结二、知识点相干&#xff08;coherent&#xff09;和非相干&#xff08;incoherent&#xff09;信号相干信号生成代码 相关信号&#xff08;correlated signal&#xff09;相关信号生成代码 正交信号定义 本文记录博主的科研日记。如果对博主的其他文章感兴趣&…

vue3项目部署在阿里云轻量应用服务器上

文章目录 概要整体部署流程技术细节小结 概要 vue3前端项目部署在阿里云轻量服务器 整体部署流程 首先有一个Vue3前端项目和阿里云应用服务器 确保环境准备 如果是新的服务器&#xff0c;在服务器内运行以下命令更新软件包 sudo apt update && sudo apt upgrade -y …

东土科技孵化的“网联汽车高速通信技术”前沿产品亮相2024WICV大会

2024世界智能网联汽车大会&#xff08;WICV&#xff09;于近日在北京召开。本次大会发布了由中国汽车工程学会组织全球200余位专家&#xff0c;联合评审遴选出未来十年对于智能网联汽车发展具有重要影响的十大技术趋势&#xff0c;包括“面向高级别自动驾驶的超级人工智能”“网…