当前位置: 首页 > news >正文

C++高频知识点(二十九)

文章目录

  • 141. 说说归并排序的思路
    • 基本介绍
    • 排序思路
    • 代码实现
    • 自己考研时候写的归并排序代码
  • 142. 智能指针 weak_ptr有什么用,可以提升为shared_ptr吗?
    • weak_ptr 的作用(解决循环引用问题)
    • 使用 weak_ptr 解决循环引用
    • weak_ptr可以提升为 shared_ptr 吗?
  • 143. 用C++实现二分查找
    • 1. 递归实现:
    • 2. 迭代实现:
  • 144. 静态链接和动态链接有什么区别?(高频)
    • 静态编译:
    • 动态链接:
  • 145. volatile关键字有什么作用?
    • 例子1:硬件寄存器
      • 如果使用 volatile:
      • 如果不使用 volatile:
    • 例子2:多线程编程
      • 如果使用 volatile:
      • 如果不使用 volatile:

141. 说说归并排序的思路

基本介绍

在这里插入图片描述

排序思路

在这里插入图片描述

在这里插入图片描述

代码实现

#include <iostream>
using namespace std;// 合并两个有序数组
void merge(int arr[], int l, int m, int r) {int n1 = m - l + 1;int n2 = r - m;// 创建临时数组int L[n1], R[n2];// 拷贝数据到临时数组 L[] 和 R[]for (int i = 0; i < n1; i++)L[i] = arr[l + i];for (int j = 0; j < n2; j++)R[j] = arr[m + 1 + j];// 合并临时数组到 arr[l..r]int i = 0; // 初始化左边索引int j = 0; // 初始化右边索引int k = l; // 初始化合并子数组索引while (i < n1 && j < n2) {if (L[i] <= R[j]) {arr[k] = L[i];i++;} else {arr[k] = R[j];j++;}k++;}// 拷贝剩余元素while (i < n1) {arr[k] = L[i];i++;k++;}while (j < n2) {arr[k] = R[j];j++;k++;}
}// 归并排序函数
void mergeSort(int arr[], int l, int r) {if (l < r) {// 找到中间点int m = l + (r - l) / 2;// 递归排序左半部分mergeSort(arr, l, m);// 递归排序右半部分mergeSort(arr, m + 1, r);// 合并两部分merge(arr, l, m, r);}
}// 打印数组函数
void printArray(int arr[], int size) {for (int i = 0; i < size; i++) {cout << arr[i] << " ";}cout << endl;
}int main() {// 初始化一个数组int arr[] = {12, 11, 13, 5, 6, 7};int arr_size = sizeof(arr) / sizeof(arr[0]);// 输出未排序的数组cout << "未排序数组: \n";printArray(arr, arr_size);// 进行归并排序mergeSort(arr, 0, arr_size - 1);// 输出排序后的数组cout << "排序后的数组: \n";printArray(arr, arr_size);return 0;
}

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

自己考研时候写的归并排序代码

#include <bits/stdc++.h>using namespace std;void merge(vector<int>& arr, int low, int mid, int high) {vector<int> t(high - low + 1, 0);int k = 0;int i = low, j = mid + 1;while(i <= mid && j <= high) {if(arr[i] <= arr[j]) {t[k++] = arr[i++];} else {t[k++] = arr[j++];}}while(i <= mid) {t[k++] = arr[i++];}while(j <= high) {t[k++] = arr[j++];}for(int i = low, k = 0; i <= high; ++i) {arr[i] = t[k++];}
}void MergeSort(vector<int>& arr, int left, int right) {if(left < right) {int mid = left + (right - left) / 2;MergeSort(arr, left, mid);MergeSort(arr, mid + 1, right);merge(arr, left, mid, right);}
}int main() {vector<int> arr = {38, 27, 43, 3, 9, 82, 10};const int n = arr.size();MergeSort(arr, 0, n - 1);for(const int& num: arr) {cout << num<< " ";}cout << endl;return 0;
}

在这里插入图片描述

142. 智能指针 weak_ptr有什么用,可以提升为shared_ptr吗?

weak_ptr 的作用(解决循环引用问题)

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

class A {
public:std::shared_ptr<B> b;
};class B {
public:std::shared_ptr<A> a;
};

在这个例子中,A 和 B 互相持有对方的 shared_ptr,这就会导致它们的引用计数永远不会变为 0,进而造成内存泄漏。

使用 weak_ptr 解决循环引用

为了打破这种循环引用,可以使用 std::weak_ptr。例如,在类 B 中,将 shared_ptr<A> 改为 weak_ptr<A>:

class A {
public:std::shared_ptr<B> b;
};class B {
public:std::weak_ptr<A> a;  // 使用 weak_ptr,避免循环引用
};

weak_ptr 不增加引用计数,因此,B 类的 a 指针不会阻止 A 对象被销毁。

weak_ptr可以提升为 shared_ptr 吗?

weak_ptr 可以 提升为 shared_ptr。这通过 lock() 方法实现:

std::shared_ptr<A> sharedA = weakA.lock();

在这里插入图片描述

#include <iostream>
#include <memory>class A {
public:void hello() { std::cout << "Hello, World!" << std::endl; }
};int main() {std::shared_ptr<A> sharedA = std::make_shared<A>();std::weak_ptr<A> weakA = sharedA; // weak_ptr 不增加引用计数// 提升 weak_ptr 为 shared_ptrstd::shared_ptr<A> sharedB = weakA.lock();if (sharedB) {sharedB->hello();  // 输出 "Hello, World!"} else {std::cout << "Object is already destroyed!" << std::endl;}return 0;
}

143. 用C++实现二分查找

二分查找是一个经典的算法,通常用来在有序数组中查找某个元素。二分查找的时间复杂度为 O(log n),其中 n 是数组的大小。

在这里插入图片描述
以下是 C++ 实现二分查找的代码示例:

1. 递归实现:

#include <iostream>
#include <vector>
int binarySearchRecursive(const std::vector<int>& arr, int target, int left, int right) {if (left > right) {return -1;  // 元素未找到}int mid = left + (right - left) / 2;  // 避免整数溢出if (arr[mid] == target) {return mid;  // 找到目标元素,返回其下标} else if (arr[mid] > target) {return binarySearchRecursive(arr, target, left, mid - 1);  // 在左半部分继续查找} else {return binarySearchRecursive(arr, target, mid + 1, right);  // 在右半部分继续查找}
}
int main() {std::vector<int> arr = {1, 3, 5, 7, 9, 11, 13, 15};int target = 7;int result = binarySearchRecursive(arr, target, 0, arr.size() - 1);if (result != -1) {std::cout << "Element found at index: " << result << std::endl;} else {std::cout << "Element not found." << std::endl;}return 0;
}

2. 迭代实现:

#include <iostream>
#include <vector>
int binarySearchIterative(const std::vector<int>& arr, int target) {int left = 0;int right = arr.size() - 1;while (left <= right) {int mid = left + (right - left) / 2;  // 避免整数溢出if (arr[mid] == target) {return mid;  // 找到目标元素,返回其下标} else if (arr[mid] > target) {right = mid - 1;  // 在左半部分继续查找} else {left = mid + 1;  // 在右半部分继续查找}}return -1;  // 元素未找到
}
int main() {std::vector<int> arr = {1, 3, 5, 7, 9, 11, 13, 15};int target = 7;int result = binarySearchIterative(arr, target);if (result != -1) {std::cout << "Element found at index: " << result << std::endl;} else {std::cout << "Element not found." << std::endl;}return 0;
}

在这里插入图片描述

144. 静态链接和动态链接有什么区别?(高频)

在 C++ 中,静态链接和动态链接是两种不同的程序链接方式。

在这里插入图片描述
它们在编译、链接、运行时的行为和性能上有所不同。

静态编译:

在这里插入图片描述

动态链接:

在这里插入图片描述
假设你在 Linux 上有一个程序需要使用数学函数库。
在这里插入图片描述
在这里插入图片描述

145. volatile关键字有什么作用?

在这里插入图片描述

例子1:硬件寄存器

假设你在编程时有一个控制硬件的寄存器,比如某个硬件设备通过内存映射的方式提供一个状态寄存器,你的程序每次需要检查这个寄存器的值来了解设备的状态。

如果使用 volatile:

volatile int statusRegister;  // 硬件状态寄存器
if (statusRegister == 1) {// 做一些处理
}
  • 编译器不会对 statusRegister 做任何优化。每次访问时,都会从内存中读取这个变量的值,确保读取到最新的状态。这是因为硬件的状态可能在程序运行时被硬件或外部事件改变,编译器不能假设它的值会保持不变。

如果不使用 volatile:

int statusRegister;
if (statusRegister == 1) {// 做一些处理
}
  • 编译器可能会对 statusRegister 进行优化。例如,它可能在程序开始时读取一次变量的值,并将其缓存到寄存器中,之后直接使用缓存的值,而不是每次从内存读取。这样就可能错过硬件改变的状态,导致程序不能及时响应硬件变化。

例子2:多线程编程

假设有两个线程,一个线程负责更新一个标志位,另一个线程负责检查这个标志位是否发生了变化。

如果使用 volatile:

volatile bool flag = false;void thread1() {flag = true;  // 线程1将flag设为true
}void thread2() {while (!flag) {// 线程2一直等待,直到flag变为true}std::cout << "Flag is true!" << std::endl;
}
  • 使用 volatile 确保线程2每次检查 flag 时,都能从内存中读取最新的值。即使线程1在其他地方修改了 flag,线程2也能实时看到变化。

如果不使用 volatile:

bool flag = false;void thread1() {flag = true;  // 线程1将flag设为true
}void thread2() {while (!flag) {// 线程2一直等待,直到flag变为true}std::cout << "Flag is true!" << std::endl;
}
  • 编译器可能会优化 flag 的访问,导致线程2在检查 flag 时读取到缓存的旧值,而不是内存中的最新值。这样线程2可能永远不会看到 flag 变为 true,导致死循环。

之后我会持续更新,如果喜欢我的文章,请记得一键三连哦,点赞关注收藏,你的每一个赞每一份关注每一次收藏都将是我前进路上的无限动力 !!!↖(▔▽▔)↗感谢支持!

http://www.dtcms.com/a/340079.html

相关文章:

  • HarmonyOS 中的 泛型类和泛型接口
  • 51单片机拼接板(开发板积木)
  • 爬小红书搜索详情软件:根据关键词采集笔记详情,包含正文内容、发布时间、转评赞藏等
  • C++开发基础之:队列用法与生产者消费者模型实战和可直接复用的线程安全的队列
  • 疏老师-python训练营-Day50预训练模型+CBAM注意力
  • 会话技术之<Cookie>和<Session>的区别联系
  • “数据权限”的道和术
  • 从 SGD 到梯度累积:Epoch、Batch、Step 的关系全解析
  • 使用redis读写锁实现抢券功能
  • Hive 存储管理测试用例设计指南
  • 力扣(最小栈)
  • Android逆向工程:Smali语法解析完整指南
  • [ Maven 开发工具 ] 环境搭建及配置
  • DRM驱动架构浅析-上(DRM基础概要与U-Boot阶段驱动解析)
  • 基于 OpenMV 的矩形识别与 STM32 串口通信(电子设计大赛实用教程)
  • k8s运维实践:高可用Redis Cluster(三主三从)与Proxy部署方案
  • 使用 Docker 安装长安链管理平台 + 部署区块链与示例合约
  • daily notes[3]
  • Eigen中Dense 模块简要介绍和实战应用示例(最小二乘拟合直线、协方差矩阵计算和稀疏求解等)
  • 三极管驱动led灯搭配的电阻选取方法
  • 跟随广州AI导游深度探寻广州历史底蕴​
  • 如何做一次AIMD
  • 农田扫描提速37%!基于检测置信度的无人机“智能抽查”路径规划,Coovally一键加速模型落地
  • [OWASP]智能体应用安全保障指南
  • 英伟达显卡驱动怎么更新 详细步骤教程
  • MySQL练习题50题(附带详细教程)
  • Day13_【DataFrame数据组合concat连接】【案例】
  • C5.5:VDB及后面的电路讨论
  • 决策树(2)
  • Yum使用时报错