廊坊网站设计公司自己建设论坛网站

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

廊坊网站设计公司,自己建设论坛网站,广告设计专业学校有哪些,外贸流程及详细介绍岛屿数量-200 class Solution {//深度优先搜索 dfs public:int vis[300][300] {0};//用于标记的数组#xff0c;标记是否遍历过int cnt 0;//岛屿计数//上下左右的移动方向数组int dx[4]{-1,1,0,0};int dy[4]{0,0,-1,1};//深度优先搜索void dfs(vectorvectorchar {0};//用于标记的数组标记是否遍历过int cnt 0;//岛屿计数//上下左右的移动方向数组int dx[4]{-1,1,0,0};int dy[4]{0,0,-1,1};//深度优先搜索void dfs(vectorvectorchar grid,int x,int y){for(int i0;i4;i){int bx xdx[i];int by ydy[i];//检查边界if(bx0||bxgrid.size()||by0||bygrid[0].size())continue;//检查是否被标记过已经遍历过当前位置的值是否为1被标记过或者值为1就跳过if(vis[bx][by]||grid[bx][by]!1)continue;//标记当前点为已经访问vis[bx][by]1;//递归搜索相邻的格子dfs(grid,bx,by);}}int numIslands(vectorvectorchar grid) {//遍历数组for(int i0;igrid.size();i){for(int j0;jgrid[0].size();j){//如果没有被标记过为0并且值为1if(!vis[i][j]grid[i][j]1){//岛屿计数加1cnt;//当前元素标记为1表示已经访问过vis[i][j]1;//深度优先搜索dfs(grid,i,j);}}}return cnt;} }; 每日问题 右值引用和移动语义 右值引用和移动语义 在 C11 中引入了 右值引用 和 移动语义 这两个重要概念它们主要用于优化性能减少不必要的资源拷贝尤其是在处理大对象时。理解这两个概念有助于写出更加高效的 C 代码。

  1. 右值和左值 在讨论右值引用之前我们需要先理解 左值 和 右值 的区别 左值 (Lvalue)指代内存中的某个位置有持久性的可以对其取地址。 示例变量、数组元素、解引用的指针等。例如int a 10; 中的 a 是左值。右值 (Rvalue)临时的、没有持久性的数据不能取地址。通常是表达式计算的结果、常量、临时对象等。 示例a b 或 func() 返回的临时对象。例如int x a b; 中的 a b 是右值。 左值 和 右值 的区分在 C11 中变得更加重要特别是在涉及到 右值引用 和 移动语义 时。
  2. 右值引用 右值引用是 C11 引入的新特性它用于捕获 右值。与传统的 左值引用 不同右值引用是用来绑定 右值 的目的是为了解决不必要的拷贝操作和资源的浪费。 右值引用的特点 右值引用只能绑定 右值而不能绑定左值。右值引用使得对象的资源如内存、文件句柄等能够被 转移move而不是复制拷贝。 右值引用的声明 int r 5; // 5 是右值r 是右值引用3. 移动语义 移动语义 允许资源从一个对象 转移move 到另一个对象而不是复制资源。这通过右值引用实现避免了昂贵的深拷贝操作特别是在处理大型对象如 std::vector、std::string时大大提高了性能。 关键概念 移动构造函数一个特殊的构造函数它接收一个右值引用并转移而不是复制其资源。移动赋值运算符与移动构造函数类似它接收一个右值引用并转移资源。 例子移动构造函数和移动赋值运算符 考虑一个自定义的类 MyClass它管理一个动态分配的数组。我们希望能够利用 移动语义 来避免不必要的资源拷贝。 #include iostream #include cstringclass MyClass { private:char* data;public:// 普通构造函数MyClass(const char* str) {data new char[strlen(str) 1];strcpy(data, str);std::cout Constructing: data std::endl;}// 移动构造函数MyClass(MyClass other) noexcept {data other.data; // 转移所有权other.data nullptr; // 使其他对象处于有效的空状态std::cout Moving: data std::endl;}// 移动赋值运算符MyClass operator(MyClass other) noexcept {if (this ! other) {delete[] data; // 删除原来的资源data other.data; // 转移所有权other.data nullptr; // 使其他对象处于有效的空状态}std::cout Move Assigning: data std::endl;return *this;}// 析构函数~MyClass() {delete[] data;std::cout Destructing: (data ? data : nullptr) std::endl;}void print() const {std::cout Data: data std::endl;} };int main() {MyClass obj1(Hello, World!); // 使用普通构造函数MyClass obj2 std::move(obj1); // 使用移动构造函数obj2.print(); // 输出 obj2 的数据// obj1 不再持有有效数据因为它的资源已被转移obj1.print(); // 输出 obj1 的数据nullMyClass obj3(Temporary);obj3 std::move(obj2); // 使用移动赋值运算符return 0; }输出 Constructing: Hello, World! Moving: Hello, World! Data: Hello, World! Destructing: nullptr Move Assigning: Hello, World! Destructing: Temporary Destructing: Hello, World!4. 为什么使用移动语义 移动语义的主要优点在于它允许将资源的所有权从一个对象转移到另一个对象而不是进行昂贵的复制操作。 性能优化 在没有移动语义的情况下当一个对象被复制时通常需要执行深拷贝操作这可能会消耗大量时间尤其是对于包含大量数据的对象如 std::vector、std::string。但是使用移动语义数据的所有权被直接转移避免了复制操作从而提高了性能。 使用场景 当一个对象的生命周期短并且不再需要它时可以将它的资源转移到另一个对象中。当你返回一个临时对象时移动语义能避免不必要的复制。
  3. 右值引用与常规引用的区别 左值引用 ()可以绑定到 左值引用已经存在的对象。不能绑定到临时对象或常量。右值引用 ()只能绑定到 右值即临时对象、表达式的结果等。允许资源的转移避免了深拷贝。 举个例子 int a 10; int lref a; // 左值引用绑定到左值 a int rref 20; // 右值引用绑定到右值 206. 总结 右值引用 () 允许我们捕获和操作 右值为 移动语义 提供支持。移动语义 允许我们将对象的资源从一个对象转移到另一个对象避免了不必要的拷贝从而提高了程序的性能。移动构造函数 和 移动赋值运算符 是支持移动语义的核心它们通过转移对象的资源来避免复制操作。 通过右值引用和移动语义我们能够写出更高效、性能更好的 C 代码尤其是在处理大型数据结构和容器时。 自动类型推导auto 和 decltype 自动类型推导auto 和 decltype 在 C 中auto 和 decltype 都是与类型推导相关的关键字它们帮助程序员简化代码避免手动指定冗长或复杂的类型。
  4. auto 关键字 auto 是 C11 引入的关键字用来自动推导变量的类型。编译器根据变量的初始化表达式来推导变量的类型。 基本用法 auto x 10; // x 的类型是 int auto y 3.14; // y 的类型是 double auto z hello; // z 的类型是 const char*用于函数返回类型 auto 也可以用于函数的返回类型特别是当返回类型较为复杂时或者返回值的类型依赖于某些表达式的计算结果。 auto add(int a, int b) {return a b; // 返回值的类型自动推导为 int }用于迭代器 auto 在使用 STL 容器时特别有用避免了繁琐的类型声明尤其是迭代器类型的声明。 #include vectorstd::vectorint vec {1, 2, 3, 4, 5}; for (auto it vec.begin(); it ! vec.end(); it) {std::cout *it ; // 自动推导 it 的类型 }2. decltype 关键字 decltype 是 C11 引入的另一个关键字它的作用是查询表达式的类型。decltype 不会计算表达式的值只会返回该表达式的类型。 基本用法 int x 10; decltype(x) y 20; // y 的类型与 x 相同都是 intdouble z 3.14; decltype(z) w 2.71; // w 的类型是 double用于推导函数返回类型 有时候函数的返回类型可能很复杂如模板函数这时可以用 decltype 来推导返回类型而无需手动指定。 templatetypename T, typename U auto multiply(T a, U b) - decltype(a * b) {return a * b; // 返回值的类型是 a * b 的类型 }3. auto 和 decltype 的区别 auto用于变量声明时编译器根据初始化表达式来推导类型。适用于你知道变量的初始值但不想显式写出类型时。 自动推导类型适用于变量声明。 如果初始化表达式返回引用或常量auto 会丢弃引用或常量。 decltype用于获取任何表达式的类型无论是否为引用、常量、指针等。适用于你想要查询某个表达式类型或返回类型时。 获取表达式的类型不对类型进行推导。 如果表达式是一个引用类型decltype 会保留这个引用。 举例说明两者的区别 int x 10; int ref x;// auto 会推导为 int因为初始化值是 x auto a x; // a 的类型是 int// decltype 会保留引用类型 decltype(ref) b x; // b 的类型是 int4. 使用场景和最佳实践 使用 auto 适用于复杂类型的变量声明尤其是当类型很长或难以确定时。 减少代码重复和冗长特别是在模板编程中。 迭代器类型、返回类型等都可以通过 auto 自动推导。 示例 std::vectorint::iterator it vec.begin(); auto it2 vec.begin(); // 自动推导类型使用 decltype 当你需要保持某个变量的类型特别是引用类型时decltype 是非常有用的。 用于函数返回类型推导或者在模板编程中获取表达式类型。 示例 decltype(x y) result x y; // result 的类型与 x y 相同5. 组合使用auto 和 decltype 这两个关键字可以结合使用尤其是在模板编程或复杂类型的情况中非常有用。 示例 template typename T auto sum(T a, T b) - decltype(a b) {return a b; }在这里auto 用于返回类型decltype 用于推导 a b 的类型。 总结 auto 关键字用于变量声明时自动推导类型简化代码尤其在复杂类型或迭代器类型中非常有用。 decltype 用于查询表达式的类型保持原始类型信息适用于需要精确控制类型的场景。 auto 和 decltype 经常一起使用帮助简化和增强代码的可读性与灵活性。