面试题c/c++ --STL 算法与数据结构

1.6 STL

模板

        

模板底层实现:编译器会对函数模板进行两次编译, 在声明的地方对模板代码本身进行编译, 在调用的地方对参数替换后的代码进行编译。

模板传参分析

模板重载 

vector

是动态空间, 随着元素的加入, 它的内部机制会自行扩充空间以容纳新元素 vector 的数据结构其实就 是三个迭代器构成的, 一个指向目前使用的空间头, 一个指向目前使用空间尾, 一个指向目前可用的空  间尾 。当有新元素插入时, 如果目前容量够用则直接插入 若不够则容量扩充至两倍, 依次类推 。扩充  的过程是重新申请一块连续空间, 将原有数据拷贝到新空间, 再释放原有空间, 扩充后原有的迭代器会

失效。

remove() 的实现原理:在遍历容器中的元素时, 一旦遇到目标元素, 就做上标记, 然后继续遍历,     到找到一个非目标元素, 即用此元素将最先做标记的位置覆盖掉, 同时将此非目标元素所在的位置也做  上标记, 等待找到新的非目标元素将其覆盖 remove() 不会改变其容量大小,  erase() 可以改变其容 量大小, 通常将 remove() 返回的迭代器传入 erase() 中清除后续无用元素。

注意事项:

●    插入和删除 元素后, 如果由于内存重分配则会导致迭代器全部失效;没有重分配则插入和删除之后 的迭代器失效 

●    清空 vector 数据时, 如果保存的数据项是指针类型, 需要逐项 delete 否则会造成 内存泄漏

●    频繁调用 push_back 影响: vector 的尾部添加元素, 很有可能引起整个对象存储空间的重新分 配, 这个过程是耗时耗力的 。C++11之后, 新增 emplace_back 方法, 都是添加元素 但是该方法 效率更高 emplace_back 在内存优化方面和运行效率方面有改进, 内存优化方面主要体现在就地 构造( 直接在容器内构造对象, 不用拷贝 一个再使用) +强制类型转换, 在运行效率方面, 由于省  去了拷贝构造, 因此有提高。

list

STL中的 list 是一个双向循环链表, 相比双向链表结构的好处是在构建 list 容器时, 只需借助一个指针 即可轻松表示 list 容器的首尾元素。

deque

支持从头尾两端进行元素的插入和删除操作, 没有容量的概念, 因为它是动态地以 分段连续空间 组合 而成, 随时可以增加一段新的空间并连接起来, 但是拥有复杂的迭代器结构 deque 采用 一块所谓的  map 作为主控, 这里的 map 实际就是一块大小连续的空间, 其中每一个元素称为节点 node 都指向 了另一段连续线性空间, 该空间是 deque 真正的存储空间。

deque 实现原理

1. 送代器是一个类, 其中迭代器中的 node 变量指向 map 的一个单元,  map 中的每个单元指向当 前迭代器对应的数据( 缓冲区), 如下图所示 map 的实现为 vector

2. 当某个数据缓冲区头部或尾部已满时, 将回到 map 中定位到相邻的数据缓冲区 。内部 分段连续  现。

3. 当插入元素时, 当前位置位于首部或尾部时, 直接插入; 则比较当前元素距离首部近还是尾部近, 距离哪边近则将当前位置那段的元素整体移动, 再插入当前元素。

4.    的实现原理

priority_queue 

优先队列( STL为大顶堆), 每个节点大于其子节点, 采用 vector 实现

map  set

STL 原理解析: https://www.bilibili.com/video/BV1NB4y1W7Uf?

spm_id_from=333.999.list.card_archive.click&vd_source=de7529d9789e1cd154061dd03f6490

20

map  set 都是C++的关联容器, 其底层实现都是红黑树。

set multiset 使用红黑树的迭代器是 const 类型的。

map multimap 使用红黑树的迭代器不是 const 类型的。

(key 、val在内部是存储在一个元素中, 因此set 、map底层实现一样)

红黑树( 平衡二叉搜索树)

红黑树定义:

●    每个节点不是红色就是黑色

●    根节点必须是黑色, 相邻节点颜色不一样

●    从根节点到叶子节点的黑色节点个数是一样的

实现:有个虚拟头结点, 左右指针分别指向红黑树最左侧和最右侧节点, 便于最大最小值查找 。每个节点都有左右指针 、父节点指针和K-V值( 还有颜色值)为什么采用红黑树实现:

●    二叉树在某些情况下可能会退化为 O(N) 的时间复杂度;

●    AVL树左右子树高度差最大为1, 红黑树不遵循高度差条件, 为的是减少旋转的次数

 hashtable

STL 原理解析: https://www.bilibili.com/video/BV1NB4y1W7Uf?

spm_id_from=333.999.list.card_archive.click&vd_source=de7529d9789e1cd154061dd03f6490

20

hash 转换:

1. 整数值直接作为 hash 

2. 字符串各字符处理( 只要够乱就可) 作为 hash 

哈希表扩充: 当元素个数大于 buckets 大小时, 将会进行哈希表扩充( 约2倍数扩充), 并重新分配所 有元素。

碰撞处理: 同一位置用链表存储

实现: unordered_set 、unordered_map。

STL 底层实现

●    只有一个链表的头结点

●    每个桶指向上一个有效桶的最后一个节点( 即上一个节点)

1.7 算法

memcpy 实现

        

void mymemcpy(void* dst, const void* src, size_t num) {assert((dst != nullptr) && (src != nullptr));const char* psrc = (const char*)src; //因为void*是⽆法完成 '++' 或 '--'
的char* pdst = (char*)dst;if (pdst > psrc && pdst < psrc + num) {for (size_t i = num - 1; i >= 0 && i < num; --i) {pdst[i] = psrc[i];}} else {for (size_t i = 0; i < num; ++i) {pdst[i] = psrc[i];}}
}

 读写锁

        

class ReadWriteLock {
private:
std::mutex write;
std::shared_mutex read; // C++14
int readCnt;
public:
ReadWriteLock(): readCnt(0) {}
void readLock() {
read.lock();
if (++ readCnt == 1) {
write.lock();
}
read.unlock();
}
void unreadLock() {
read.lock();
if (-- readCnt == 0) {
write.unlock();
}
read.unlock();
}
void writeLock() {
write.lock();
}
void unwriteLock() {
write.unlock();
}
};

死锁复现代码

        

#include <iostream>
#include <thread>
#include <mutex>
#include <unistd.h>
using namespace std;
int data = 1;
mutex mt1,mt2;
void a2() {
mt2.lock();
sleep(1);
data = data * data;
mt1.lock(); //此时a1已经对mt1上锁,所以要等待
cout<<data<<endl;
mt1.unlock();
mt2.unlock();
}
void a1() {
mt1.lock();
sleep(1);
data = data+1;
mt2.lock(); //此时a2已经对mt2上锁,所以要等待
cout<<data<<endl;
mt2.unlock();
mt1.unlock();
}
int main() {
thread t2(a2);
thread t1(a1);
t1.join();
t2.join();
cout<<"main here"<<endl; //要t1线程、t2线程都执⾏完毕后才会执⾏
return 0;
}
⼆叉树序列号与反序列化
        
// 序列化
void serializeSub(TreeNode* node, string &res) {if (!node) {res += "NULL,";}else {res += to_string(node->val) + ",";serializeSub(node->left, res);serializeSub(node->right, res);}
}
string serialize(TreeNode* root) {string res = "";serializeSub(root, res);return res;
}
// 反序列化
TreeNode* deserializeSub(queue<string> &q) {string cur = q.front();q.pop();if (cur == "NULL") {return nullptr;}else {TreeNode *node = new TreeNode(stoi(cur));node->left = deserializeSub(q);node->right = deserializeSub(q);return node;}
}
TreeNode* deserialize(string data) {queue<string> q;string cur = "";for (char c: data) {if (c != ',') {cur += c;}else {q.push(cur);cur.clear();}}
return deserializeSub(q);
}
⽣产者消费者模式
        
#include <iostream>
#include <thread>
#include <vector>
#include <queue>
#include <mutex>
#include <condition_variable>
using namespace std;
#define PRODUCT_SIZE 2
#define CUSTUM_SIZE 2
#define POOL_SIZE 3
mutex m;
condition_variable cv;
queue<int> que;
int num = 0;
void producter() {
while (true) {
std::unique_lock<std::mutex> lck(m);
while (que.size() >= POOL_SIZE) {
cv.wait(lck);
}
int data = num ++;
que.push(data);
cout << this_thread::get_id() << "⽣产了" << data << endl;
cv.notify_all();
}
}
void customer() {
while (true) {
std::unique_lock<std::mutex> lck(m);
while (que.empty()) {
cv.wait(lck);
}
cout << this_thread::get_id() << "消费了" << que.front() << endl;
que.pop();
cv.notify_all();
}
}
int main() {
vector<thread> pools;
for (int i = 0; i < PRODUCT_SIZE; ++ i) {
pools.push_back(thread(producter));
}
for (int i = 0; i < CUSTUM_SIZE; ++ i) {
pools.push_back(thread(customer));
}
for (int i = 0; i < PRODUCT_SIZE + CUSTUM_SIZE; ++ i) {
pools[i].join();
}
return 0;
}
⼆叉树-前中后迭代算法模板
        
vector<int> inorderTraversal(TreeNode* root) {vector<int> res;stack<pair<TreeNode*, bool>> st;st.push({root, false}); // root 节点未被访问while (!st.empty()) {auto tmp = st.top();st.pop();if (!tmp.first) continue;if (!tmp.second) {TreeNode* node = tmp.first;// 对于其他顺序遍历,仅改变下⾯三⾏代码即可(遍历逆序)st.push({node->right, false});st.push({node, true});st.push({node->left, false});}else {res.emplace_back(tmp.first->val);}}return res;
}
⼿写智能指针
        
#include <iostream>
#include <cstdlib> // 智能指针头⽂件
#include <utility> // 智能指针头⽂件
#include <memory> // 智能指针头⽂件
template<typename T>
class SmartPtr {
private:
size_t* _count;
T* _ptr;
public:
// 构造函数
SmartPtr(T* ptr=nullptr): _ptr(ptr) {
if (ptr) {
_count = new size_t(1);
}
else {
_count = new size_t(0);
}
}// 析构函数
~SmartPtr() {
if ((*_count) > 0) {
-- (*_count);
}
if ((*_count) == 0) {
delete _ptr;
delete _count;
_ptr = nullptr;
_count = nullptr;
}
}// 拷⻉构造函数
SmartPtr(const SmartPtr& ptr) {
if (this == &ptr) {
return ;
}
_ptr = ptr._ptr;
_count = ptr._count;
(*_count) ++;
}// 拷⻉赋值运算符
SmartPtr& operator=(const SmartPtr& ptr) {
if (_ptr == ptr._ptr) {
return *this;
}
_ptr = ptr._ptr;
_count = ptr._count;
(*_count) ++;
return *this;
}T& operator*() const { return *_ptr; }
T* operator->() const { return _ptr; }
operator bool() const { return _ptr; }
size_t use_count() const { return *_count; }
};
int main() {
std::shared_ptr<int> p1(new int(3));
std::cout << p1.use_count() << std::endl; // 1
std::shared_ptr<int> p2(p1);
std::cout << p1.use_count() << std::endl; // 2
std::cout << p2.use_count() << std::endl; // 2
std::shared_ptr<int> p3;
std::cout << p3.use_count() << std::endl; // 0
p3 = p2;
std::cout << p2.use_count() << std::endl; // 3
std::cout << p3.use_count() << std::endl; // 3
std::shared_ptr<int> p4 = p3;
std::cout << p3.use_count() << std::endl; // 4
std::cout << p4.use_count() << std::endl; // 4
std::cout << std::endl << std::endl;
///
SmartPtr<int> sp1(new int(3));
std::cout << sp1.use_count() << std::endl; // 1
SmartPtr<int> sp2(sp1);
std::cout << sp1.use_count() << std::endl; // 2
std::cout << sp2.use_count() << std::endl; // 2
SmartPtr<int> sp3;
std::cout << sp3.use_count() << std::endl; // 0
sp3 = sp2;
std::cout << sp2.use_count() << std::endl; // 3
std::cout << sp3.use_count() << std::endl; // 3
SmartPtr<int> sp4 = sp3;
std::cout << sp3.use_count() << std::endl; // 4
std::cout << sp4.use_count() << std::endl; // 4
return 0;
}
⼗⼤排序算法(升序实现)
稳定排序:冒泡排序、插⼊排序、归并排序

冒泡排序:N个数需要进⾏N-1次冒泡,每次冒泡确定⼀个最⼤值位置。元素交换次数为原数组逆序度。

        

void bubbleSort(std::vector<int>& nums, int n) {
for (int i = 1; i < n; ++ i) { // 冒泡次数
bool is_swap = false;
for (int j = 1; j < n - i + 1; ++ j) {
if (nums[j] < nums[j - 1]) {
std::swap(nums[j], nums[j - 1]);
is_swap = true;
}
}
if (!is_swap) break;
}
}

 

插⼊排序:分为已排序和未排序,初始化已排序区间只有数组第⼀个元素。遍历未排序的每⼀个元素, 倒序⽐较与已排序区间的⼤⼩关系,确定当前未排序元素的位置。元素交换次数为原数组逆序度。
        
void insertSort(std::vector<int>& nums, int n) {
for (int i = 1; i < n; ++ i) {
for (int j = i; j > 0 && nums[j] < nums[j - 1]; -- j) {
std::swap(nums[j], nums[j - 1]);
}
}
}
选择排序:从头开始遍历数组,然后将该元素与其后⾯的区间进⾏⽐较,选择最⼩的元素并交换
void selectSort(std::vector<int>& nums, int n) {
for (int i = 0; i < n - 1; ++ i) {
int k = i;
for (int j = i + 1; j < n; ++ j) {
if (nums[j] < nums[k]) {
k = j;
}
}
std::swap(nums[k], nums[i]);
}
}
快速排序:先找到⼀个枢纽,然后在当前数组中把⽐这个枢纽⼩的元素放左边,⼤的元素放右边,两部分数据依次递归排序下去直到有序。
void quickSort(std::vector<int>& nums, int l, int r) {
if (l >= r) return;
int left = l, right = r, key = nums[l];
while (left < right) {
while (left < right && nums[right] >= key) -- right;
while (left < right && nums[left] <= key) ++ left;
if (left < right) {
std::swap(nums[left], nums[right]);
}
}
std::swap(nums[left], nums[l]);
quickSort(nums, l, left - 1);
quickSort(nums, left + 1, r);
}
归并排序:⾸先将数组等分递归排序,然后通过⼀个临时数组,⽐较两个数组的⼤⼩从⽽合并两个数组。
        
void mergeSort(std::vector<int>& nums, int l, int r) {
if (l < r) {
int mid = l + (r - l ) / 2;
mergeSort(nums, l, mid);
mergeSort(nums, mid + 1, r);vector<int> tmp(r - l + 1);int i = l, j = mid + 1;int k = 0;while (i <= mid && j <= r) {if (nums[i] < nums[j]) {tmp[k ++] = nums[i ++];}else {tmp[k ++] = nums[j ++];}}while (i <= mid) { tmp[k ++] = nums[i ++]; }while (j <= r) { tmp[k ++] = nums[j ++]; }for (int p = 0; p < k; ++ p) {nums[l + p] = tmp[p];}
}
}
堆排序:从最后⼀个⽗节点逆序构建最⼤堆(根节点/0下标值为最⼤),然后循环N-1次,不断将0下标与最后下标数交换,并调整堆(其中堆越来越⼩)
        
void heapify(vector<int>& nums, int f, int n) {
int left = f * 2 + 1;int right = left + 1;
while (left < n) {
int index = f;
if (nums[index] < nums[left]) index = left;
if (right < n && nums[index] < nums[right]) index = right;
if (index == f) {
break;
}
else {
swap(nums[f], nums[index]);
f = index;
left = f * 2 + 1;right = left + 1;
}
}
}
void heapSort(std::vector<int>& nums, int n) {
if (n < 2) return ;
// 从最后⼀个⽗节点调整为最⼤堆
for (int i = n / 2 - 1; i >= 0; -- i) {
heapify(nums, i, n);
}
// 最⼤值放最后,将剩下调整为堆
for (int i = n - 1; i > 0; -- i) {
std::swap(nums[0], nums[i]);
heapify(nums, 0, i);
}
}
桶排序:将数据分到有限数量的桶⾥,然后每个桶分别排序(可能使⽤其他排序算法),最后每个桶内数据合并
计数排序:获取数组最⼤manV和最⼩值mixV,然后⽣成manV-mixV+1⼤⼩的数组,分别计数对应值的次数,然后再恢复数值输出结果
基数排序:针对正整数排序,对每⼀个数补⻬最⻓位数,然后从低位开始排序,排序的过程类似于多次桶排序
希尔排序:从 len/2 步⻓开始排序,每次步⻓取半,直到最后成为插⼊排序

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

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

相关文章

Apache Airflow (十二) :PythonOperator

&#x1f3e1; 个人主页&#xff1a;IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 &#x1f6a9; 私聊博主&#xff1a;加入大数据技术讨论群聊&#xff0c;获取更多大数据资料。 &#x1f514; 博主个人B栈地址&#xff1a;豹哥教你大数据的个人空间-豹…

内网穿透的应用-如何在Docker中部署MinIO服务并结合内网穿透实现公网访问本地管理界面

文章目录 前言1. Docker 部署MinIO2. 本地访问MinIO3. Linux安装Cpolar4. 配置MinIO公网地址5. 远程访问MinIO管理界面6. 固定MinIO公网地址 前言 MinIO是一个开源的对象存储服务器&#xff0c;可以在各种环境中运行&#xff0c;例如本地、Docker容器、Kubernetes集群等。它兼…

HTTPS流量抓包分析中出现无法加载key

HTTPS流量抓包分析(TLSv1.2)&#xff0c;这篇文章分析的比较透彻&#xff0c;就不班门弄斧了 https://zhuanlan.zhihu.com/p/635420027 写个小问题&#xff1a;RSA密钥对话框加载rsa key文件的时候注意不要在中文目录下&#xff0c;否则会提示&#xff1a;“Enter the passwor…

单张图像3D重建:原理与PyTorch实现

近年来&#xff0c;深度学习&#xff08;DL&#xff09;在解决图像分类、目标检测、语义分割等 2D 图像任务方面表现出了出色的能力。DL 也不例外&#xff0c;在将其应用于 3D 图形问题方面也取得了巨大进展。 在这篇文章中&#xff0c;我们将探讨最近将深度学习扩展到单图像 3…

【MySql】13- 实践篇(十一)

文章目录 1. 自增主键为什么不是连续的&#xff1f;1.1 自增值保存在哪儿&#xff1f;1.2 自增值修改机制1.2.1 自增值的修改时机1.2.2 自增值为什么不能回退? 1.3 自增锁的优化1.3.1 自增锁设计历史 2. Insert语句为何很多锁?2.1 insert … select 语句2.2 insert 循环写入2…

以“防方视角”观Shiro反序列化漏洞

为方便您的阅读&#xff0c;可点击下方蓝色字体&#xff0c;进行跳转↓↓↓ 01 案例概述02 攻击路径03 防方思路 01 案例概述 这篇文章来自微信公众号“潇湘信安”&#xff0c;记录的某师傅如何发现、利用Shiro反序列化漏洞&#xff0c;又是怎样绕过火绒安全防护实现文件落地、…

BLIP-2:冻结现有视觉模型和大语言模型的预训练模型

Li J, Li D, Savarese S, et al. Blip-2: Bootstrapping language-image pre-training with frozen image encoders and large language models[J]. arXiv preprint arXiv:2301.12597, 2023. BLIP-2&#xff0c;是 BLIP 系列的第二篇&#xff0c;同样出自 Salesforce 公司&…

物流实时数仓:采集通道搭建

系列文章目录 物流实时数仓&#xff1a;环境搭建 文章目录 系列文章目录前言一、环境准备1.前置环境2.hbase安装1.上传并解压2.配置环境变量3.拷贝jar包4.编写配置文件5.分发配置文件 3.Redis安装1.安装需要的编译环境2.上传并解压文件3.编译安装4.后台访问 4.ClickHouse安装5…

OpenCvSharp从入门到实践-(01)认识OpenCvSharp开发环境搭建

目录 一、OpenCV 二、OpenCvSharp 三、OpenCvSharp开发环境搭建 四、下载 五、其他 一、OpenCV OpenCV是基于Apache2.0许可&#xff08;开源&#xff09;发行的跨平台计算机视觉和机器学习函数库&#xff0c;支持Windows、Linux、Android和Mac OS操作系统。OpenCV由一系…

Oracle for Windows安装和配置——Oracle for Windows net配置

2.3. Oracle for Windows net配置 2.3.1. Oracle net配置 2.3.1.1. Oracle net简介 前述章节中,我们只是安装了数据库软件,创建了数据库,测试在服务器本地连接查询数据库。但还不能通过网络远程连接访问数据库,因为我们还没配置用来远程连接访问该数据库的组件Oracle ne…

【Linux】缓冲区+磁盘+动静态库

一、缓冲区 1、缓冲区的概念 缓冲区的本质就是一段用作缓存的内存。 2、缓冲区的意义 节省进程进行数据IO的时间。进程使用fwrite等函数把数据拷贝到缓冲区或者外设中。 3、缓冲区刷新策略 3.1、立即刷新&#xff08;无缓冲&#xff09;——ffush() 情况很少&#xff0c…

【蓝桥杯 第十五届模拟赛 Java B组】训练题(A - I)

目录 A、求全是字母的最小十六进制数 B、Excel表格组合 C、求满足条件的日期 D、 取数字 - 二分 &#xff08;1&#xff09;暴力 &#xff08;2&#xff09;二分 E、最大连通块 - bfs F、哪一天&#xff1f; G、信号覆盖 - bfs &#xff08;1&#xff09;bfs&#xf…

【前端学java】java中的日期操作(12)

往期回顾&#xff1a; 【前端学java】JAVA开发的依赖安装与环境配置 &#xff08;0&#xff09;【前端学 java】java的基础语法&#xff08;1&#xff09;【前端学java】JAVA中的packge与import&#xff08;2&#xff09;【前端学java】面向对象编程基础-类的使用 &#xff08…

使用Python的turtle模块绘制玫瑰花图案(含详细Python代码与注释)

1.1引言 turtle模块是Python的标准库之一&#xff0c;它提供了一个绘图板&#xff0c;让我们可以在屏幕上绘制各种图形。通过使用turtle&#xff0c;我们可以创建花朵、叶子、复杂的图案等等。本博客将介绍如何使用turtle模块实现绘制图形的过程&#xff0c;并展示最终结果。 …

创建一个用户test且使用testtab表空间及testtemp临时表空间并授予其权限,密码随意

文章目录 1、连接到数据库2、创建表空间3、创建用户4、授予权限5、测试 1、连接到数据库 sqlplus / as sysdba2、创建表空间 创建testtab表空间 CREATE TABLESPACE testtab DATAFILE /u01/app/oracle/oradata/orcl/testtab.dbf SIZE 50M AUTOEXTEND ON NEXT 5M MAXSIZE …

Unity中Shader法线贴图(下)理论篇

文章目录 前言一、采样出错的原因二、切线空间是什么&#xff1f;切线空间图解&#xff1a; 三、计算方式1、统一变换到切线空间下进行计算2、统一变换到世界空间下进行计算 四、一般统一变换到世界空间下的坐标进行计算1、求M^-1^2、求出n~w~ 前言 这篇文章&#xff0c;主要解…

[Android] Amazon 的 android 音视频开发文档

https://developer.amazon.com/zh/docs/fire-tv/audio-video-synchronization.html#22-getplaybackheadposition-api-level-3https://developer.amazon.com/zh/docs/fire-tv/audio-video-synchronization.html#22-getplaybackheadposition-api-level-3

车载毫米波雷达行业发展1——概述

1.1 毫米波雷达定义及产品演进 1.1.1 毫米波雷达定义 毫米波雷达(mmWave Radar)是指工作在毫米波波段的雷达&#xff0c;其频域介于 30&#xff5e;300GHz&#xff0c;波长1~10mm。毫米波雷达稳定性高&#xff0c;抗干扰能力强&#xff0c;可穿透雾、烟、灰尘环境&#xff0…

Java基础-----StringBuffer和StringBuilder

文章目录 1.StringBuffer1.1 构造方法1.2 常用方法 2.StringBuilder3.String、StringBuffer、StringBuilder的区别 1.StringBuffer 内容可变的字符串类&#xff0c;适应StringBuffer来对字符串的内容进行动态操作&#xff0c;不会产生额外的对象。StringBuffer在初始时&#x…

AI集成ChatGPT敲代码神器Copilot

&#x1f4d1;前言 本文主要是AI工具Copilot解读文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁️博客首页&#xff1a;CSDN主页放风讲故事 &#x1f304;每日一句&#xff1a;努力…