【C++ 面试 - STL】每日 3 题(七)

news2024/9/23 19:21:14

✍个人博客:Pandaconda-CSDN博客
📣专栏地址:http://t.csdnimg.cn/fYaBd
📚专栏简介:在这个专栏中,我将会分享 C++ 面试中常见的面试题给大家~
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪

19. 如何实现无锁 map?

可以使用哈希表和 CAS(Compare-And-Swap)操作:

  1. 创建一个哈希表,将键值对映射到哈希桶(bucket)中。
  2. 使用哈希函数来确定每个键应该映射到哪个桶中。
  3. 对于每个桶,使用无锁链表(例如,带有头节点的单向链表)来存储键值对。
  4. 对于插入操作,首先计算键的哈希值,然后找到相应的桶。接下来,使用 CAS 操作将新的键值对插入链表的开头。
  5. 对于查找操作,计算键的哈希值,找到相应的桶,然后在链表中查找键。
  6. 对于删除操作,计算键的哈希值,找到相应的桶,然后在链表中查找并删除键。
  7. 为了处理并发冲突,你需要使用 CAS 操作,如果 CAS 失败,表示有其他线程正在修改链表,你需要重试或采取其他策略。
    一个简单的代码示例,使用 CAS 操作来实现基本的无锁 map。
#include <iostream>
#include <vector>
#include <atomic>

template <typename K, typename V>
class LockFreeMap {
private:
    struct Node {
        K key;
        V value;
        std::atomic<Node*> next;

        Node(const K& k, const V& v) : key(k), value(v), next(nullptr) {}
    };

    std::vector<std::atomic<Node*>> buckets;
    static const size_t num_buckets = 100; // 根据需要设置桶的数量

    size_t hash(const K& key) const {
        // 简单哈希函数,根据需要使用更复杂的哈希函数
        return std::hash<K>{}(key) % num_buckets;
    }

public:
    LockFreeMap() : buckets(num_buckets) {}

    void insert(const K& key, const V& value) {
        size_t bucket_index = hash(key);
        Node* newNode = new Node(key, value);

        while (true) {
            Node* head = buckets[bucket_index].load();
            newNode->next = head;
            if (buckets[bucket_index].compare_exchange_strong(head, newNode)) {
                return; // 插入成功
            }
        }
    }

    bool find(const K& key, V& value) const {
        size_t bucket_index = hash(key);
        Node* current = buckets[bucket_index].load();

        while (current) {
            if (current->key == key) {
                value = current->value;
                return true; // 找到了
            }
            current = current->next;
        }

        return false; // 没找到
    }

    bool remove(const K& key) {
        size_t bucket_index = hash(key);
        Node* current = buckets[bucket_index].load();
        Node* prev = nullptr;

        while (current) {
            if (current->key == key) {
                if (prev) {
                    prev->next.store(current->next.load());
                } else {
                    buckets[bucket_index].store(current->next.load());
                }
                delete current;
                return true; // 移除成功
            }
            prev = current;
            current = current->next.load();
        }

        return false; // 没找到要移除的节点
    }
};

int main() {
    LockFreeMap<int, std::string> map;

    map.insert(1, "One");
    map.insert(2, "Two");
    map.insert(3, "Three");

    std::string value;
    if (map.find(2, value)) {
        std::cout << "Found: " << value << std::endl;
    } else {
        std::cout << "Not Found" << std::endl;
    }

    if (map.remove(3)) {
        std::cout << "Removed: 3" << std::endl;
    } else {
        std::cout << "Not Found" << std::endl;
    }

    return 0;
}

上述代码仅供参考,无锁数据结构的实现要考虑更多的细节和错误处理。还有就是这里没有考虑并发性能问题。如果需要高性能的无锁数据结构,可以考虑使用专业的并发数据结构库。

20. emplace_back 与 push_back 的区别

对 push/insert 更新成了 emplace,传入参数时直接在容器的底层构造。
在这里插入图片描述

#include <iostream>
#include <vector>

using namespace std;

class Test
{
public:
    Test(int a) { cout << "Test(int)" << endl; }
    Test(int a, int b) { cout << "Test(int, int)" << endl; }
    Test(const Test&) { cout << "Test(const Test&)" << endl; }
    Test(Test&&) { cout << "Test(Test&&)" << endl; }
    ~Test() { cout << "~Test()" << endl; }
};

int main()
{
    vector<Test> vec;
    vec.reserve(100);
    vec.push_back(10);
    cout << "--------" << endl;
    vec.emplace_back(10); //没有拷贝构造,直接在vec底层构造
    cout << "--------" << endl;
    return 0;
}

emplace_back 源码:

在这里插入图片描述

21. STL 迭代器如何实现?

1、 迭代器是一种抽象的设计理念,通过迭代器可以在不了解容器内部原理的情况下遍历容器,除此之外,STL 中迭代器一个最重要的作用就是作为容器与 STL 算法的粘合剂。

2、 迭代器的作用就是提供一个遍历容器内部所有元素的接口,因此迭代器内部必须保存一个与容器相关联的指针,然后重载各种运算操作来遍历,其中最重要的是 * 运算符与 -> 运算符,以及 ++、-- 等可能需要重载的运算符重载。这和 C++ 中的智能指针很像,智能指针也是将一个指针封装,然后通过引用计数或是其他方法完成自动释放内存的功能。

3、最常用的迭代器的相应型别有五种:value type、difference type、pointer、reference、iterator catagoly;

iterator catagoly 迭代器又被分为五类:input iterator、output iterator、forward iterator、bidirectional iterator、random adccess iterator。

从属关系:(input iterator、output iterator) -> forward iterator -> bidirectional iterator -> random adccess iterator

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

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

相关文章

3.js - Water2不显示水波纹

文中需要的资源&#xff0c;在我的资源那里能下载 【3.js 有2个水的生成方式&#xff1a;Water、Water2】 注意&#xff1a; 这个问题&#xff0c;是基于 Water2的 如下方式&#xff0c;不显示波纹 import * as THREE from three import { OrbitControls } from three/exam…

人工智能相关学科的关系

禹晶、肖创柏、廖庆敏《数字图像处理》资源二维码

C++——类与对象(一)

目录 引言 面向过程与面向对象 1.面向过程 2.面向对象 类 1.类的定义 2.类的访问限定符 3.类域 4.类域与其他作用域 对象 1.类对象的实例化 2.对象的大小 2.1 如何计算对象的大小 2.2 内存对齐规则 2.3 示例 3.this指针 3.1 this指针的引入 3.2 this指针的详…

Nacos Config的配置中心

1.创建一个新的文件 2.导入依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven…

review——Linux:进程地址空间

目录 前言 一、页表 1.回顾一下fork接口 2..先看一个有意思的现象 3.地址映射与页表 二、进程地址空间 1.进程地址空间是什么 2.进程地址空间与页表起到了什么作用 3.进程地址空间有什么作用 4.缺页中断与写时拷贝 5.写时拷贝的相关问题 6.关于内存空间申请的讨 前言 不知道大…

SpringCloud-02 Consul服务注册与发现

Consul是一种用于服务发现、配置和分布式协调的开源工具。Consul提供了以下主要功能&#xff1a; 1.服务发现&#xff1a;Consul允许开发人员在微服务架构中注册和发现服务。它可以自动检测新添加的服务并为它们分配唯一的网络地址。 2.健康检查&#xff1a;Consul可以定期检查…

Linux学习-虚拟化平台安装和使用

注&#xff1a;系统使用Rock8.6 下载链接 通过百度网盘分享的文件&#xff1a;cirros.qcow2&#xff0c;node_base.xml等2个文件 链接&#xff1a;https://pan.baidu.com/s/1hupGQsMjrXMgngCy3lQLhw?pwdhlr6 提取码&#xff1a;hlr6[rootharbor ~]# cat /etc/redhat-releas…

Origin画图——柱状图与点线图结合优化

1.如何将下列不好看的柱状图进行优化呢。 2.首先双击坐标轴&#xff0c;将轴的参数进行修改&#xff0c;包含朝向大小&#xff0c;粗细。修改后如下所示。 3.然后我们来修改柱状图&#xff0c;双击柱状图&#xff0c;依次修改内容。 4.选取颜色&#xff0c;按照修改后&#…

网络层 VI(路由算法与路由协议)【★★★★★★】

&#xff08;★★&#xff09;代表非常重要的知识点&#xff0c;&#xff08;★&#xff09;代表重要的知识点。 一、路由算法 路由算法的目的很简单&#xff1a;给定一组路由器及连接路由器的链路&#xff0c;路由算法要找到一条从源路由器到目的路由器的“最佳”路径。通常&a…

跑步戴的耳机哪个品牌的好?五大高口碑骨传导耳机推荐!

跑步&#xff0c;作为一项简单而高效的运动方式&#xff0c;越来越受到人们的青睐。在跑步的过程中&#xff0c;音乐往往能够成为我们最好的伴侣&#xff0c;它不仅能够激发我们的热情&#xff0c;还能帮助我们保持节奏&#xff0c;让跑步变得更加轻松愉快。然而&#xff0c;选…

两个月冲刺软考——判断是否为阻塞节点,是否可化简,化简顺序是什么?存储器的分层结构;可屏蔽中断与不可屏蔽中断

1.判断是否为阻塞节点&#xff0c;是否可化简&#xff0c;化简顺序是什么&#xff1f; 首先要理解什么是阻塞节点&#xff1f;所谓阻塞节点就是从这个进程开始执行&#xff0c;会让程序陷入死锁&#xff0c;执行不了。解题关键就在于选择入口&#xff1a;挨个去尝试先执行P1、…

Windows安装MinIO对象存储服务详细版本

一、什么是MinIO? Minio 是一个高性能、开源的对象存储服务器。 Minio 具有以下主要特点和优势&#xff1a; 一、功能特点 1. 多平台支持 - 可以在各种操作系统上运行&#xff0c;包括 Linux、Windows 和 macOS。这使得它可以适应不同的服务器环境和开发需求。 2. 对象存储 - …

【从头写CAD】2 建立项目及角度类

文章目录 一、说明二、操作步骤三、角度单位四、源代码1. mod.rs 内容2. angle.rs 内容3. main.rs 补充调试内容 五、运行1. 运行程序 一、说明 CAD离不开角度数据&#xff0c;目前CAD开源项目多用double类型表示角度。我认为有必要独立出来&#xff0c;让三角函数仅出现该类内…

白酒酿造:传统工艺与现代科技的整合

在千年的历史长河中&#xff0c;白酒酿造技艺如一颗璀璨的明珠&#xff0c;闪烁着中华文明的智慧光芒。如今&#xff0c;随着科技的飞速发展&#xff0c;传统酿造工艺与现代科技在这片古老的土地上交织碰撞&#xff0c;共同书写着白酒酿造的新篇章。豪迈白酒&#xff08;HOMANL…

828华为云征文|基于华为云Flexus云服务器X搭建FTP服务器

❀目录 ❀概述❀特点❀环境准备❀安装❀配置文件修改❀创建目录、修改权限❀控制台安全组开启21端口❀工具验证❀总结 ❀概述 FTP文件传输协议是一种在网络中进行文件传输的广泛使用的标准协议。作为网络通信中的基础工具&#xff0c;FTP允许用户通过客户端软件与服务器进行交…

栈和队列——用栈实现队列

栈的特点是先进后出&#xff0c;队列的特点是先进先出。根据题中要求&#xff0c;我们应用两个栈实现一个队列。我们可以类比用队列实现栈&#xff0c;我们可以先将元素都插入到栈1中&#xff0c;当我们想要取出元素时&#xff0c;我们可以将栈1中的所有数据依次插入到栈2中&am…

污点、容忍、不可调度、排水、数据卷

目录 污点taint 污点的格式 1. key:effect 键名&#xff1a;污点类型 2. keyvalue:effect 键名数值&#xff1a;污点类型 污点的类型 1. NoSchedule 2. PreferNoSchedule 3. NoExecute&#xff08;驱逐&#xff09; 设置污点&#xff08;主节点操作&#xff09…

STM32:通过旋转计数器的计数控制舵机旋转的角度

声明&#xff1a;本博客为各模块之间结合的自主研究学习。 目录 一、按键操控舵机旋转&#xff08;单向&#xff09; 1.1、实物图讲解 1.2、代码讲解 1.2.1、PWM.c 具体步骤&#xff1a; 完整代码&#xff1a; 1.2.2、PWM.h 1.2.3、Servo.c && Servo.h 1.2.4、…

ts 类型分类

目录 01 ts 相关指令 02 类型声明空间与变量声明空间 03 类型注解和类型推断 04 类型分类 , 联合类型与交叉类型 05 never类型 any类型 和unknown类型 01 ts 相关指令 全局安装 typescript 模块 npm i -g typescript 安装完成之后 可以将ts文件转换成js文件 tsc xxx.ts…

为什么越来越多的人选择开放式耳机?平价高品质蓝牙耳机推荐

越来越多的人选择开放式耳机&#xff0c;主要是因为其具有多方面的优势&#xff0c;具体如下&#xff1a; 佩戴舒适度高&#xff1a;开放式耳机不入耳&#xff0c;不堵塞耳道&#xff0c;避免了对耳道的压迫和摩擦&#xff0c;长时间佩戴也不易产生闷热感和不适感。例如&#x…