C++ 模拟实现 map 和 set:掌握核心数据结构


文章目录

  • C++ 模拟实现 map 和 set:掌握核心数据结构
  • 一、set 和 map 的结构
    • 1.1 set的结构
    • 1.2 map的结构
  • 二、对红黑树的改造
    • 2.1 改造红黑树的节点
    • 2.2 改造红黑树
      • 2.2.1 仿函数的使用
      • 2.2.2 插入函数的改造
      • 2.2.3 删除函数的改造
  • 三、对迭代器的改造
    • 3.1 *、->、!=、==
    • 3.2 begin和end
    • 3.3 ++ 和 --
    • 3.4 const迭代器
    • 3.5 复用红黑树接口实现set/map中的成员函数
      • 3.5.1 set成员函数
      • 3.5.2 map成员函数
  • 四、源代码总结
    • 4.1 Myset.h
    • 4.2 Mymap.h
    • 4.3 RBTree.h


一、set 和 map 的结构

STL中set和map底层是一颗红黑树,模拟set和map需要一颗红黑树作为我们的成员变量
点击这里了解红黑树


1.1 set的结构

set结构就是 K模型,所以set容器对红黑树的封装如下:
在这里插入图片描述


1.2 map的结构

map结构就是 KV模型,所以map容器对红黑树的封装如下
在这里插入图片描述


二、对红黑树的改造

在这里插入图片描述


2.1 改造红黑树的节点

其中红黑树的节点类型就是模版参数T
在这里插入图片描述


2.2 改造红黑树

2.2.1 仿函数的使用

在这里插入图片描述
在这里插入图片描述


然后我们将所有需要比较key的函数利用仿函数进行替换,我们以Find为例
在这里插入图片描述


2.2.2 插入函数的改造

在这里插入图片描述

代码如下(示例):

pair<iterator, bool> Insert(const T& data)
{//情况一:如果是根节点if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;return make_pair(iterator(_root),true);}KeyOfT kot;Node* parent = nullptr;Node* cur = _root;while (cur){if (kot(cur->_value) < kot(data)){parent = cur;cur = cur->_right;}else if (kot(cur->_value) > kot(data)){parent = cur;cur = cur->_left;}else{return make_pair(iterator(cur), false);}}//找到插入位置cur = new Node(data);Node* newnode = cur;if (kot(parent->_value) < kot(data)){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;while (parent && parent->_col == RED){Node* grandfather = parent->_parent;if (parent == grandfather->_left){Node* uncle = grandfather->_right;//情况三:如果叔叔存在且为红if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}else{//情况四:叔叔不存在/存在且为黑,且cur在parent的左侧if (cur == parent->_left){//     g  //   p   u// c RotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else//情况五:叔叔不存在 / 存在且为黑,cur在parent的右侧{//     g//   p   u//     cRotateLR(grandfather);cur->_col = BLACK;grandfather->_col = RED;}//这时该子树的根节点变为黑色,不需要继续调整break;}}else{Node* uncle = grandfather->_left;//情况三:如果叔叔存在且为红if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandfather->_col = RED;//继续调整cur = grandfather;parent = cur->_parent;}else{//情况四:叔叔不存在/存在且为黑,且cur在parent的左侧if (cur == parent->_right){//    g//  u   p//        cRotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else // 情况五:叔叔不存在 / 存在且为黑,cur在parent的右侧{//    g//  u   p//    cRotateRL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}//这时该子树的根节点变为黑色,不需要继续调整break;}}}//防止情况三改到根节点变为红色_root->_col = BLACK;return make_pair(iterator(newnode), true);
}

2.2.3 删除函数的改造

在这里插入图片描述

代码如下(示例):

else //待删除结点的左右子树均不为空
{//替换法删除//寻找待删除结点右子树当中key值最小的结点作为实际删除结点Node* minParent = cur;Node* minRight = cur->_right;while (minRight->_left){minParent = minRight;minRight = minRight->_left;}// 原本直接可以赋值// cur->_value = minRight->_value //将待删除结点的键值改为minRight的键值Node* newnode = new Node(minRight->_value,cur->_col);Node* parent = cur->_parent;//重新链接祖父孙三代节点关系cur->_left->_parent = newnode;cur->_right->_parent = newnode;if (parent){if (parent->_left == cur){parent->_left = newnode;}else{parent->_right = newnode;}}else{//如果是根节点_root = newnode;}newnode->_parent = parent;newnode->_left = cur->_left;newnode->_right = cur->_right;//如果minParent是curif (minParent == cur){minParent = newnode;}delete cur;delParent = minParent; //标记实际删除的父节点delCur = minRight; //标记实际删除的结点
}

三、对迭代器的改造

3.1 *、->、!=、==

在这里插入图片描述

代码如下(示例):

template<class T, class Ref, class Ptr>
struct __RBTreeIterator
{typedef RBNode<T> Node;typedef __RBTreeIterator<T, Ref, Ptr> Self;Node* _node;//构造__RBTreeIterator(Node* node):_node(node){}Ref operator*(){return _node->_value;}Ptr operator->(){return &_node->_value;}//判断两个正向迭代器是否不同bool operator!=(const Self& s) const{return _node != s._node;}//判断两个正向迭代器是否相同bool operator==(const Self& s) const{return _node == s._node;}Node* getNode(){return _node;}
};

3.2 begin和end

在这里插入图片描述

代码如下(示例):

typedef __RBTreeIterator<T, T&, T*> iterator;//普通迭代器
typedef __RBTreeIterator<T, const T&, const T*> const_iterator;//const迭代器
//最左节点
iterator begin()
{Node* cur = _root;while (cur && cur->_left){cur = cur->_left;}return iterator(cur);
}
iterator end()
{return iterator(nullptr);
}
//const版本begin和end
const_iterator begin()const
{Node* cur = _root;while (cur && cur->_left){cur = cur->_left;}return const_iterator(cur);
}const_iterator end()const
{return const_iterator(nullptr);
}

3.3 ++ 和 –

在这里插入图片描述

代码如下(示例):

 //前置++Self& operator++(){//如果右子树不为空if (_node->_right){//寻找该结点右子树当中的最左结点Node* left = _node->_right;while (left->_left){left = left->_left;}_node = left;}else{Node* cur = _node;Node* parent = cur->_parent;//寻找孩子不在右的祖先while (parent && cur == parent->_right){cur = parent;parent = cur->_parent;}_node = parent;}return *this;}//前置--Self& operator--(){if (_node->_left) //结点的左子树不为空{//寻找该结点左子树当中的最右结点Node* right = _node->_left;while (right->_right){right = right->_right;}_node = right;}else{//寻找孩子不在父亲左的祖先Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_left){cur = parent;parent = parent->_parent;}_node = parent;}return *this;}

3.4 const迭代器

在这里插入图片描述

代码如下(示例):

//普通迭代器构造const迭代器
__RBTreeIterator(const __RBTreeIterator<T,T&,T*>& it):_node(it._node)
{}

3.5 复用红黑树接口实现set/map中的成员函数

3.5.1 set成员函数

代码如下(示例):

template<class K>
class set
{struct SetKeyOfT{const K& operator()(const K& key){return key;}};
public://typename声明是一个类型而不是静态变量typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;//成员函数iterator begin(){return _t.begin();}iterator end(){return _t.end();}const_iterator begin() const{return _t.begin();}const_iterator end() const{return _t.end();}pair<iterator, bool> insert(const K& key){return _t.Insert(key);}//删除函数void erase(const K& key){_t.Erase(key);}//查找函数iterator find(const K& key){return _t.Find(key);}
private:RBTree<K, K, SetKeyOfT> _t;
};

3.5.2 map成员函数

代码如下(示例):

template<class K, class V>
class map
{//仿函数struct MapKeyOfT{const K& operator()(const pair<K, V>& kv){return kv.first;}};
public://typename声明是一个类型而不是静态变量typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::iterator iterator; typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::const_iterator const_iterator;//成员函数iterator begin(){return _t.begin();}iterator end(){return _t.end();}const_iterator begin() const{return _t.begin();}const_iterator end() const{return _t.end();}pair<iterator, bool> insert(const pair<K,V>& key){return _t.Insert(key);}//删除函数void erase(const K& key){_t.Erase(key);}//查找函数iterator find(const K& key){return _t.Find(key);}//[]运算符重载V& operator[](const K& key){pair<iterator, bool> ret = _t.Insert(make_pair(key, V()));return ret.first->second;}
private:RBTree<K, pair<const K, V>, MapKeyOfT> _t;
};

在这里插入图片描述


四、源代码总结

4.1 Myset.h

代码如下(示例):

#pragma once
// Myset.h
#include"RBTree.h"
namespace bit
{template<class K>class set{struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:typedef typename RBTree<K, const K, SetKeyOfT>::Iterator iterator;typedef typename RBTree<K, const K, SetKeyOfT>::ConstIteratorconst_iterator;iterator begin(){return _t.Begin();}iterator end(){return _t.End();}const_iterator begin() const{return _t.Begin();}const_iterator end() const{return _t.End();}pair<iterator, bool> insert(const K& key){return _t.Insert(key);}iterator find(const K& key){return _t.Find(key);}private:RBTree<K, const K, SetKeyOfT> _t;};void Print(const set<int>& s){set<int>::const_iterator it = s.end();while (it != s.begin()){--it;// 不⽀持修改//*it += 2;cout << *it << " ";}cout << endl;}void test_set(){set<int> s;int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };for (auto e : a){s.insert(e);}for (auto e : s){cout << e << " ";}cout << endl;Print(s);}
}

4.2 Mymap.h

代码如下(示例):

#pragma once
#include"RBTree.h"
namespace bit
{template<class K, class V>class map{struct MapKeyOfT{const K& operator()(const pair<K, V>& kv){return kv.first;}};public:typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::Iteratoriterator;typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::ConstIteratorconst_iterator;iterator begin(){return _t.Begin();}iterator end(){return _t.End();}const_iterator begin() const{return _t.Begin();}const_iterator end() const{return _t.End();}pair<iterator, bool> insert(const pair<K, V>& kv){return _t.Insert(kv);}iterator find(const K& key){return _t.Find(key);}V& operator[](const K& key){pair<iterator, bool> ret = insert(make_pair(key, V()));return ret.first->second;}private:RBTree<K, pair<const K, V>, MapKeyOfT> _t;};void test_map(){map<string, string> dict;dict.insert({ "sort", "排序" });dict.insert({ "left", "左边" });dict.insert({ "right", "右边" });dict["left"] = "左边,剩余";dict["insert"] = "插⼊";dict["string"];map<string, string>::iterator it = dict.begin();while (it != dict.end()){// 不能修改first,可以修改second//it->first += 'x';it->second += 'x';cout << it->first << ":" << it->second << endl;++it;}cout << endl;}
}

4.3 RBTree.h

代码如下(示例):

#pragma once
#include<iostream>
using namespace std;// RBtree.h
enum Colour
{RED,BLACK
};
template<class T>
struct RBTreeNode
{T _data;RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;Colour _col;RBTreeNode(const T& data): _data(data), _left(nullptr), _right(nullptr), _parent(nullptr){}
};
template<class T, class Ref, class Ptr>
struct RBTreeIterator
{typedef RBTreeNode<T> Node;typedef RBTreeIterator<T, Ref, Ptr> Self;Node* _node;Node* _root;RBTreeIterator(Node* node, Node* root):_node(node), _root(root){}Self& operator++(){if (_node->_right){// 右不为空,右⼦树最左结点就是中序第⼀个Node* leftMost = _node->_right;while (leftMost->_left){leftMost = leftMost->_left;}_node = leftMost;}else{// 孩⼦是⽗亲左的那个祖先Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_right){cur = parent;parent = cur->_parent;}_node = parent;}return *this;}Self& operator--(){if (_node == nullptr) // end(){// --end(),特殊处理,⾛到中序最后⼀个结点,整棵树的最右结点Node* rightMost = _root;while (rightMost && rightMost->_right){rightMost = rightMost->_right;}_node = rightMost;}else if (_node->_left){// 左⼦树不为空,中序左⼦树最后⼀个Node* rightMost = _node->_left;while (rightMost->_right){rightMost = rightMost->_right;}_node = rightMost;}else{// 孩⼦是⽗亲右的那个祖先Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_left){cur = parent;parent = cur->_parent;}_node = parent;}return *this;}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator!= (const Self& s) const{return _node != s._node;}bool operator== (const Self& s) const{return _node == s._node;}
};
template<class K, class T, class KeyOfT>
class RBTree
{typedef RBTreeNode<T> Node;
public:typedef RBTreeIterator<T, T&, T*> Iterator;typedef RBTreeIterator<T, const T&, const T*> ConstIterator;Iterator Begin(){Node* leftMost = _root;while (leftMost && leftMost->_left){leftMost = leftMost->_left;}return Iterator(leftMost, _root);}Iterator End(){return Iterator(nullptr, _root);}ConstIterator Begin() const{Node* leftMost = _root;while (leftMost && leftMost->_left){leftMost = leftMost->_left;}return ConstIterator(leftMost, _root);}ConstIterator End() const{return ConstIterator(nullptr, _root);}RBTree() = default;~RBTree(){Destroy(_root);_root = nullptr;}pair<Iterator, bool> Insert(const T & data){if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;return make_pair(Iterator(_root, _root), true);}KeyOfT kot;Node* parent = nullptr;Node* cur = _root;while (cur){if (kot(cur->_data) < kot(data)){parent = cur;cur = cur->_right;}else if (kot(cur->_data) > kot(data)){parent = cur;cur = cur->_left;}else{return make_pair(Iterator(cur, _root), false);}}cur = new Node(data);Node* newnode = cur;// 新增结点。颜⾊红⾊给红⾊cur->_col = RED;if (kot(parent->_data) < kot(data)){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;while (parent && parent->_col == RED){Node* grandfather = parent->_parent;// g// p uif (parent == grandfather->_left){Node* uncle = grandfather->_right;if (uncle && uncle->_col == RED){// u存在且为红 -》变⾊再继续往上处理parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}else{// u存在且为⿊或不存在 -》旋转+变⾊if (cur == parent->_left){// g// p u//c//单旋RotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{// g// p u// c//双旋RotateL(parent);RotateR(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}else{// g// u pNode* uncle = grandfather->_left;// 叔叔存在且为红,-》变⾊即可if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandfather->_col = RED;// 继续往上处理cur = grandfather;parent = cur->_parent;}else // 叔叔不存在,或者存在且为⿊{// 情况⼆:叔叔不存在或者存在且为⿊// 旋转+变⾊// g// u p// cif (cur == parent->_right){RotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{// g// u p// cRotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}}_root->_col = BLACK;return make_pair(Iterator(newnode, _root), true);
}
Iterator Find(const K& key)
{Node* cur = _root;while (cur){if (cur->_kv.first < key){cur = cur->_right;}else if (cur->_kv.first > key){cur = cur->_left;}else{return Iterator(cur, _root);}}return End();
}
private:void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL)subRL->_parent = parent;Node* parentParent = parent->_parent;subR->_left = parent;parent->_parent = subR;if (parentParent == nullptr){_root = subR;subR->_parent = nullptr;}else{if (parent == parentParent->_left){parentParent->_left = subR;}else{parentParent->_right = subR;}subR->_parent = parentParent;}}void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR)subLR->_parent = parent;Node* parentParent = parent->_parent;subL->_right = parent;parent->_parent = subL;if (parentParent == nullptr){_root = subL;subL->_parent = nullptr;}else{if (parent == parentParent->_left){parentParent->_left = subL;}else{parentParent->_right = subL;}subL->_parent = parentParent;}}void Destroy(Node* root){if (root == nullptr)return;Destroy(root->_left);Destroy(root->_right);delete root;}
private:Node* _root = nullptr;
};

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

根据ASTM D4169-23e1标准,如何选择合适的流通周期进行测试?

根据ASTM D4169-23e1标准及行业实践&#xff0c;选择流通周期&#xff08;DC&#xff09;需综合以下因素&#xff1a;一、核心选择依据‌产品属性与包装形式‌‌重量体积‌&#xff1a;轻小包裹&#xff08;<4.53kg且<0.056m&#xff09;适用DC2/3/4/6/9/13-17等周期&…

MySQL的触发器:

目录 触发器的概念&#xff1a; 创建触发器&#xff1a; 查看触发器&#xff1a; 查看当前数据库的所有触发器的定义&#xff1a; 查看当前数据中某个触发器的定义&#xff1a; 从系统information_schema的TRIGGERS表中查询"salary_check_trigger"触发器的信息…

基于ubuntu搭建gitlab

原文地址&#xff1a;基于ubuntu搭建gitlab – 无敌牛 欢迎参观我的网站&#xff1a;无敌牛 – 技术/著作/典籍/分享等 之前介绍了一个使用 git openssh-server 搭建一个极简 git 库的方法&#xff0c;感兴趣可以查看往期文章&#xff1a;手搓一个极简远端git库 – 无敌牛 。…

测试GO前沿实验室:为水系电池研究提供多维度表征解决方案

测试GO前沿实验室&#xff1a;为水系电池研究提供多维度表征解决方案随着全球能源转型加速&#xff0c;水系电池因其高安全性、低成本和环境友好特性&#xff0c;成为下一代储能技术的重要发展方向。测试狗前沿实验室针对水系电池研发中的关键科学问题&#xff0c;整合先进表征…

Spring Boot 中 YAML 配置文件详解

Spring Boot 中 YAML 配置文件详解 在 Spring Boot 项目中&#xff0c;配置文件是不可或缺的一部分&#xff0c;用于自定义应用行为、覆盖默认设置。除了传统的 properties 文件&#xff0c;Spring Boot 对 YAML&#xff08;YAML Ain’t Markup Language&#xff09;格式提供了…

Milvus安装可视化工具,attu,保姆级

安装包链接&#xff1a;GitHub - zilliztech/attu: Web UI for Milvus Vector Databasehttps://github.com/zilliztech/attu?tabreadme-ov-file 下滑 举例&#xff1a;windows&#xff1a;下载安装&#xff0c;然后就可以连接了&#xff08;安装完打开后如果需要输入用户名密码…

避免“卡脖子”!如何减少内存I/O延迟对程序的影响?

单来说&#xff0c;内存 IO 就像是计算机的 “数据高速公路”&#xff0c;负责在内存和其他设备&#xff08;如硬盘、CPU 等&#xff09;之间传输数据。它的速度和效率直接影响着计算机系统的整体性能。 你有没有想过&#xff0c;当你点击电脑上的一个应用程序&#xff0c;它是…

V4L2摄像头采集 + WiFi实时传输实战全流程

&#x1f4d6; 推荐阅读&#xff1a;《Yocto项目实战教程:高效定制嵌入式Linux系统》 &#x1f3a5; 更多学习视频请关注 B 站&#xff1a;嵌入式Jerry V4L2摄像头采集 WiFi实时传输实战全流程 1. 实战场景概述 目标&#xff1a; 嵌入式设备&#xff08;如RK3588/正点原子开发…

Java 之 设计模式

1.单例模式1. ​​饿汉式&#xff08;Eager Initialization&#xff09;​​​​核心原理​​&#xff1a;类加载时立即创建实例&#xff0c;通过静态变量直接初始化。​​代码示例​​&#xff1a;public class Singleton {private static final Singleton INSTANCE new Sing…

[激光原理与应用-185]:光学器件 - BBO、LBO、CLBO晶体的全面比较

一、相同点非线性光学晶体属性BBO、LBO、CLBO均为非中心对称晶体&#xff0c;具备非线性光学效应&#xff0c;广泛应用于激光频率转换&#xff08;如倍频、三倍频、和频、差频&#xff09;、光学参量振荡&#xff08;OPO&#xff09;及电光调制等领域。宽透光范围三者均覆盖紫外…

Android APN加载耗时优化可行性分析

背景 根据Android系统底层机制和行业实践,本文讨论 APN 加载耗时从4.2s降至0.8s的数据合理性和技术可行性,需结合具体优化手段和硬件环境综合分析。 以下是关键判断依据及行业参考: ⚙️ 一、APN加载耗时基准参考 未优化场景的典型耗时 首次开机或重置后:APN需从apns-con…

mysql进阶-sql调优

概述优化索引在MySQL初阶的课程中已经介绍了索引&#xff0c;我们知道InnoDB存储引擎使⽤B树作为索引默认的数据结构来组织数据&#xff0c;为频繁查询的列建⽴索引可以有效的提升查询效率&#xff0c;那么如何利⽤索引编写出⾼效的SQL查询语句&#xff1f;以及如何分析某个查询…

海量数据处理问题详解

1.从a&#xff0c;b两个文件各存放50亿个url&#xff08;每个url大小为64B&#xff09;&#xff0c;如何在内存为4G中查找a&#xff0c;b中相同的url 计算各文件存放大小&#xff1a;50亿*64B 大约为320G&#xff0c;而内存只有4G&#xff0c;显然存放不下&#xff0c;此时我们…

AI 记忆管理系统:工程实现设计方案

本文档为《从“健忘”到“懂我”&#xff1a;构建新一代AI记忆系统》中所述理念的详细工程实现方案。它将聚焦于技术选型、模块设计、数据流转和核心算法&#xff0c;为开发团队提供清晰的落地指引。 1. 系统架构与技术选型 为实现分层记忆与读写分离的设计理念&#xff0c;我们…

Linux驱动学习day26天(RS485)

一、原理通过芯片将232信号转换成485信号&#xff0c;485表示0和1的方法&#xff1a;Va - Vb 的电压差在2~6V时表示1&#xff0c;Va - Vb 的电压差在-2~-6V时表示0。这样传输不容易受到干扰&#xff0c;并且传输距离长。我们需要做的事情就是发送&#xff1a;使能DE(driver ena…

从零构建TransformerP1-了解设计

欢迎来到啾啾的博客&#x1f431;。 记录学习点滴。分享工作思考和实用技巧&#xff0c;偶尔也分享一些杂谈&#x1f4ac;。 有很多很多不足的地方&#xff0c;欢迎评论交流&#xff0c;感谢您的阅读和评论&#x1f604;。 目录引言1 概念回顾1.1 序列任务1.1.1 将序列变成模型…

JVM 终止机制详解:用户线程与守护线程

用户线程未执行完是否会阻止 JVM 终止&#xff1f;答案是&#xff1a;取决于线程类型。让我详细解释&#xff1a; 核心规则 #mermaid-svg-bg5xpyMAeRWNGGk2 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-bg5xpyMAe…

Linux Vim 常用快捷键

Vim中最常用的快捷键&#xff0c;熟练掌握它们可以大大提高编辑效率。移动光标h- 左移j- 下移k- 上移l- 右移w- 移动到下一个单词开头b- 移动到上一个单词开头e- 移动到单词末尾0- 移动到行首$- 移动到行尾gg- 移动到文件开头G- 移动到文件末尾:n- 跳转到第n行插入模式i- 在光标…

【Bellman负环】Cycle Finding

题目翻译给定一个有向图&#xff0c;你的任务是判断它是否包含负环&#xff0c;并给出这样一个环的示例。输入 第一行输入两个整数 n 和 m&#xff1a;分别表示节点数和边数。节点编号为 1, 2, ..., n。 接下来 m 行描述边&#xff0c;每行有三个整数 a, b, c&#xff1a;表示存…

数据结构(六):树与二叉树

一、树的基本概念树的定义树&#xff08;Tree&#xff09;是由 n&#xff08;n ≥ 0&#xff09;个节点组成的有限集合&#xff0c;当 n 0 时称为空树。非空树中&#xff1a;有且仅有一个根节点&#xff08;Root&#xff09;&#xff1b;其余节点可以划分为若干个互不相交的子…