C++语法知识点合集:7.string类

news2024/9/22 19:32:10

文章目录

  • 一、标准库中的string类
    • 1.string类
    • 2.auto和范围for
    • 3.string类的常用接口说明
  • 二、string类的模拟实现
    • 1. 经典的string类问题
    • 2.浅拷贝
    • 3.深拷贝


一、标准库中的string类

1.string类

  • string是表示字符串的字符串类
  • 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
  • string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator> string;
  • 不能操作多字节或者变长字符的序列。
  • 在使用string类时,必须包含#include头文件以及using namespace std;

2.auto和范围for

  1. auto关键字:自动推断类型,作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期
    推导而得。
  • 用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
  • 当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
  • auto不能作为函数的参数,可以做返回值,但是谨慎使用。
  • auto不能直接用来声明数组。
#include <iostream>
using namespace std;
int func1()
{
    return 10;
}
// 不能做参数
// void func2(auto a)
//{
//} // 可以做返回值,但是建议谨慎使用
auto func3()
{
    return 3;
}
int main()
{
    int a = 10;
    auto b = a;
    auto c = 'a';
    auto d = func1();
    // 编译报错:rror C3531: “e”: 类型包含“auto”的符号必须具有初始值设定项
    // auto e;
    cout << typeid(b).name() << endl; // typeid(variable).name()返回的是类型名称的一个编码
    cout << typeid(c).name() << endl; // int-i char-c  int*-Pi
    cout << typeid(d).name() << endl;
    int x = 10;
    auto y = &x;
    auto *z = &x;
    auto &m = x;
    cout << typeid(x).name() << endl;
    cout << typeid(y).name() << endl;
    cout << typeid(z).name() << endl;
    auto aa = 1, bb = 2;
    // 编译报错:error C3538: 在声明符列表中,“auto”必须始终推导为同一类型
    // auto cc = 3, dd = 4.0;
    // 编译报错:error C3318: “auto []”: 数组不能具有其中包含“auto”的元素类型
    // auto array[] = {4, 5, 6};
    return 0;
}
#include <iostream>
#include <string>
#include <map> // 导入映射容器类 std::map 用于存储键值对
using namespace std;
int main()
{
    // 表示键和值都是std::string类型的映射(即字典)。
    std::map<std::string, std::string> dict = {{"apple", "苹果"}, {"orange", "橙子"}, {"pear", "梨"}};
    // auto的用武之地
    //::iterator 是 std::map 内部定义的一个类型,用来表示一个指向 std::map 容器元素的迭代器。
    // 迭代器可以看作是一个指针,它用于遍历容器中的元素。
    //  std::map<std::string, std::string>::iterator it = dict.begin();
    // it = dict.begin(); it 是声明的迭代器变量。
    // dict.begin() 是一个方法,它返回一个迭代器,指向 dict 容器中的第一个元素。即访问 dict 中的第一个键值对。
    auto it = dict.begin();
    while (it != dict.end())
    {
        cout << it->first << ":" << it->second << endl;
        ++it;
    }
    return 0;
}
  1. 范围for
  • 对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。
  • for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围,自动迭代,自动取数据,自动判断结束。
  • 范围for可以作用到数组和容器对象上进行遍历
  • 范围for的底层很简单,容器遍历实际就是替换为迭代器,这个从汇编层也可以看到。
#include <iostream>
#include <string>
#include <map>
using namespace std;
int main()
{
    int array[] = {1, 2, 3, 4, 5};
    // C++11的遍历
    // 这相当于告诉编译器 请遍历 array 中的每一个元素,并在每次迭代时将当前元素的引用赋给 e。
    for (auto &e : array) //: 表示遍历的范围 左边是循环变量 右边是要遍历的容器
        e *= 2;
    for (auto e : array)
        cout << e << " " << endl;
    string str("hello world");
    for (auto ch : str)
    {
        cout << ch << " ";
    }
    cout << endl;
    return 0;
}

3.string类的常用接口说明

  1. string类对象的常见构造
  • string() 构造空的string类对象,即空字符串
  • string(const char* s) 用C-string来构造string类对象
  • string(size_t n, char c) string类对象中包含n个字符c
  • string(const string&s) 拷贝构造函数
void Teststring()
{
	string s1; // 构造空的string类对象s1
	string s2("hello bit"); // 用C格式字符串构造string类对象s2
	string s3(s2); // 拷贝构造s3
}
  1. string类对象的容量操作
  • size 返回字符串有效字符长度
// string::size
#include <iostream>
#include <string>

int main ()
{
  std::string str ("Test string");
  std::cout << "The size of str is " << str.size() << " bytes.\n";
  return 0;
}
  • length 返回字符串有效字符长度
  • capacity 返回空间总大小
  • empty 检测字符串释放为空串,是返回true,否则返回false
  • clear 清空有效字符
  • reserve 为字符串预留空间
// string::reserve
#include <iostream>
#include <fstream>
#include <string>

int main ()
{
  std::string str;

  std::ifstream file ("test.txt",std::ios::in|std::ios::ate);
  if (file) {
    std::ifstream::streampos filesize = file.tellg();
    str.reserve(filesize);

    file.seekg(0);
    while (!file.eof())
    {
      str += file.get();
    }
    std::cout << str;
  }
  return 0;
}
  • resize 将有效字符的个数改成n个,多出的空间用字符c填充
// resizing string
#include <iostream>
#include <string>

int main ()
{
  std::string str ("I like to code in C");
  std::cout << str << '\n';

  unsigned sz = str.size();

  str.resize (sz+2,'+');
  std::cout << str << '\n';

  str.resize (14);
  std::cout << str << '\n';
  return 0;
}

output

I like to code in C
I like to code in C++
I like to code

  1. size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况
    下基本都是用size()。
  2. clear()只是将string中有效字符清空,不改变底层空间大小。
  3. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
  4. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserve不会改变容量大小。
  1. string类对象的访问及遍历操作
  • operator[] 返回pos位置的字符,const string类对象调用
// string::operator[]
#include <iostream>
#include <string>
using namespace std;
int main()
{
    string str("Test string");
    for (int i = 0; i < str.length(); ++i)
    {
        cout << str[i];
    }
    return 0;
}
  • begin+ end begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器
// string::begin/end
#include <iostream>
#include <string>
using namespace std;
int main()
{
    string str("Test string");
    for (string::iterator it = str.begin(); it != str.end(); ++it)
        cout << *it;
    cout << '\n';

    return 0;
}
  • rbegin + rend rbegin一个指向容器中最后一个元素的反向迭代器 + rend返回一个指向字符串开头之前位置的反向迭代器。
// string::rbegin/rend
#include <iostream>
#include <string>
using namespace std;
int main()
{
    string str("now step live...");
    // reverse_iterator C++ 标准库中提供的一种反向迭代器
    for (string::reverse_iterator rit = str.rbegin(); rit != str.rend(); ++rit)
        cout << *rit;
    return 0;
}
  1. string类对象的修改操作
  • push_back 在字符串后尾插字符c
// string::push_back
#include <iostream>
#include <fstream>
#include <string>
// 这段代码从 test.txt 文件中读取所有字符并将其存储在 str 字符串中,然后将 str 输出到控制台
int main()
{
    std::string str;
    // std::ios::in 表示以只读方式打开文件
    std::ifstream file("test.txt", std::ios::in);
    if (file)
    {
        while (!file.eof())            // file.get() 从文件中读取一个字符
            str.push_back(file.get()); // str.push_back() 将读取到的字符添加到字符串 str 的末尾
    }
    std::cout << str << '\n'; // 将读取到的完整字符串 str 输出到控制台。
    return 0;
}
  • append 在字符串后追加一个字符串
// appending to string
#include <iostream>
#include <string>

int main()
{
    std::string str;
    std::string str2 = "Writing ";
    std::string str3 = "print 10 and then 5 more";

    // used in the same order as described above:
    str.append(str2); // "Writing "
    // 将字符串 str3 中从第 6 个字符开始的 3 个字符(即 "10 ")添加到 str 末尾,结果为 "Writing 10 "。
    str.append(str3, 6, 3); // "10 "
    // str.append("dots are cool", 5);:将字符串 "dots are cool" 的前 5 个字符(即 "dots ")添加到 str 末尾
    str.append("dots are cool", 5); // "dots "
    str.append("here: ");           // "here: "
    // 在 str 末尾添加 10 个 . 字符
    str.append(10u, '.'); // ".........."
    // 将字符串 str3 从第 8 个字符到末尾的所有字符(即 " and then 5 more")添加到 str 末尾,
    str.append(str3.begin() + 8, str3.end()); // " and then 5 more"
                                              // str.append(5, 0x2E);:在 str 末尾再添加 5 个 . 字符
    str.append(5, 0x2E);                      // "....."

    std::cout << str << '\n';
    return 0;
}
  • operator+= 在字符串后追加字符串str
// string::operator+=
#include <iostream>
#include <string>

int main()
{
    std::string name("John");
    std::string family("Smith");
    name += " K. "; // c-string
    name += family; // string
    name += '\n';   // character

    std::cout << name;
    return 0;
}
  • c_str 返回C格式字符串
// strings and c-strings
#include <iostream>
#include <cstring>
#include <string>

int main()
{
    std::string str("Please split this sentence into tokens");

    char *cstr = new char[str.length() + 1];
    std::strcpy(cstr, str.c_str());
    char *p = std::strtok(cstr, " ");

    while (p != 0)
    {
        std::cout << p << '\n';
        p = std::strtok(NULL, " ");
    }

    delete[] cstr;
    return 0;
} // cstr now contains a c-string copy of str
  // strtok函数用于分割字符串,它通过修改原字符串来实现分割操作,
  // 即在找到分隔符后,会将其替换为'\0'(空字符),使得返回的子字符串是独立的。
  // strtok函数的第一个参数在第一次调用时是要分割的字符串,
  // 在后续调用时应传递NULL,以继续分割同一个字符串。
  // char *p = std::strtok(cstr, " ");
  • find + npos 从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
// string::find
#include <iostream> // std::cout
#include <string>   // std::string

int main()
{
    std::string str("There are two needles in this haystack with needles.");
    std::string str2("needle");

    // different member versions of find in the same order as above:

    // 使用find函数在字符串str中查找str2(即"needle")首次出现的位置。
    // find返回的是子字符串的起始位置,如果未找到子字符串,则返回std::string::npos。
    std::size_t found = str.find(str2);
    // 如果find函数找到了str2,则found不等于std::string::npos,进入条件分支。
    if (found != std::string::npos)
        std::cout << "first 'needle' found at: " << found << '\n';

    // find函数这次使用的是三个参数的版本
    // needles are small":要查找的字符串。
    // found + 1:从上次找到的位置的下一个字符开始查找,即在字符串str中查找第二个"needle"的出现位置
    // 只使用前6个字符(即"needle")进行匹配查找。
    found = str.find("needles are small", found + 1, 6);
    if (found != std::string::npos)
        std::cout << "second 'needle' found at: " << found << '\n';

    // 查找字符串"haystack"的位置,并输出。
    found = str.find("haystack");
    if (found != std::string::npos)
        std::cout << "'haystack' also found at: " << found << '\n';

    // 查找第一个句号"."的位置,并输出。
    found = str.find('.');
    if (found != std::string::npos)
        std::cout << "Period found at: " << found << '\n';

    // let's replace the first needle:
    // 使用replace函数将字符串str中第一个出现的str2("needle")替换为"preposition"。
    // 1.str.find(str2):找到str2的起始位置。
    // 2.str2.length():获取str2的长度。
    // 3.preposition":用这个字符串替换找到的"needle"。
    str.replace(str.find(str2), str2.length(), "preposition");
    std::cout << str << '\n';

    return 0;
}
  • rfind 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
// string::rfind
#include <iostream>
#include <string>
#include <cstddef>

int main()
{
    std::string str("The sixth sick sheik's sixth sheep's sick.");
    std::string key("sixth");
    // rfind函数用于在字符串str中从右到左查找key(即"sixth")最后一次出现的位置。
    // rfind返回的是子字符串的起始位置索引。如果未找到,返回std::string::npos
    std::size_t found = str.rfind(key);
    if (found != std::string::npos)
        // 第一个参数found是要替换的起始位置。
        // 第二个参数key.length()是要替换的长度(即"sixth"的长度)。
        str.replace(found, key.length(), "seventh");

    std::cout << str << '\n';

    return 0;
}
  • substr 在str中从pos位置开始,截取n个字符,然后将其返回
// string::substr
#include <iostream>
#include <string>

int main()
{
    std::string str = "We think in generalities, but we live in details.";
    // (quoting Alfred N. Whitehead)
    // 第一个参数3表示子字符串的起始位置(从0开始计数,所以位置3对应的是"think"中的't')。
    // 第二个参数5表示子字符串的长度,也就是从位置3开始,提取5个字符。
    std::string str2 = str.substr(3, 5); // "think"

    std::size_t pos = str.find("live"); // position of "live" in str
    // 再次使用substr函数,从位置pos开始提取子字符串,直到字符串str的末尾。
    std::string str3 = str.substr(pos); // get from "live" to the end

    std::cout << str2 << ' ' << str3 << '\n';

    return 0;
}
  1. 在string尾部追加字符时,s.push_back© / s.append(1, c) / s += 'c’三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。
  2. 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好。
  1. string类非成员函数
  • operator+ 尽量少用,因为传值返回,导致深拷贝效率低
  • operator>> 输入运算符重载
// extract to string
#include <iostream>
#include <string>

main()
{
    std::string name;

    std::cout << "Please, enter your name: ";
    std::cin >> name;
    std::cout << "Hello, " << name << "!\n";

    return 0;
}
  • operator<< 输出运算符重载
// inserting strings into output streams
#include <iostream>
#include <string>

main()
{
    std::string str = "Hello world!";
    std::cout << str << '\n';
    return 0;
}
  • getline 获取一行字符串
// extract to string
#include <iostream>
#include <string>

int main()
{
    std::string name;

    std::cout << "Please, enter your full name: ";
    std::getline(std::cin, name);  从标准输入流(键盘输入)中读取一整行字符并存储到 name 变量中
    std::cout << "Hello, " << name << "!\n";

    return 0;
}
  • relational operators 大小比较
// string comparisons
#include <iostream>
#include <vector>

int main()
{
    std::string foo = "alpha";
    std::string bar = "beta";

    if (foo == bar)
        std::cout << "foo and bar are equal\n";
    if (foo != bar)
        std::cout << "foo and bar are not equal\n";
    if (foo < bar)
        std::cout << "foo is less than bar\n";
    if (foo > bar)
        std::cout << "foo is greater than bar\n";
    if (foo <= bar)
        std::cout << "foo is less than or equal to bar\n";
    if (foo >= bar)
        std::cout << "foo is greater than or equal to bar\n";

    return 0;
}
  1. vs和g++下string结构的说明

vs下string的结构:
string总共占28个字节,内部结构稍微复杂一点,先是有一个联合体,联合体用来定义string中字符串的存储空间:
当字符串长度小于16时,使用内部固定的字符数组来存放;当字符串长度大于等于16时,从堆上开辟空间
还有一个size_t字段保存字符串长度,一个size_t字段保存从堆上开辟空间总的容量
最后还有一个指针做一些其他事情
故总共占16+4+4+4=28个字节

g++下string的结构
G++下,string是通过写时拷贝实现的,string对象总共占4个字节,内部只包含了一个指针,该指针将来指向一块>堆空间,内部包含了如下字段:

  • 空间总大小
  • 字符串有效长度
  • 引用计数
  • 指向堆空间的指针,用来存储字符串。

二、string类的模拟实现

1. 经典的string类问题

#include <assert.h>
#include <string.h>
using namespace std;
// 为了和标准库区分,此处使用String
class String
{
public:
    /*String()
    :_str(new char[1])
    {*_str = '\0';}
    */
    // String(const char* str = "\0") 错误示范
    // String(const char* str = nullptr) 错误示范
    String(const char *str = "")
    {
        // 这个构造函数的参数 str 被赋予了一个默认值 "",
        // 这是一个指向空字符串的指针(即一个只包含终止符 \0 的字符数组)。
        // 如果在创建 String 对象时没有传递参数,那么 str 将自动被赋值为 "",即空字符串。
        if (nullptr == str)
        {
            assert(false);
            return;
        }
        _str = new char[strlen(str) + 1];
        strcpy(_str, str);
    }
    ~String()
    {
        if (_str)
        {
            delete[] _str;
            _str = nullptr;
        }
    }

private:
    char *_str;
};
// 测试
void TestString()
{
    String s1("hello bit!!!");
    String s2(s1);
}

上述String类没有显式定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认的,当用s1构造s2时,编译器会调用默认的拷贝构造。最终导致的问题是,s1、s2共用同一块内存空间,在释放时同一块空间被释放多次而引起程序崩溃,这种拷贝方式,称为浅拷贝。

2.浅拷贝

也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以当继续对资源进项操作时,就会发生发生了访问违规。

可以采用深拷贝解决浅拷贝问题,即:每个对象都有一份独立的资源,不要和其他对象共享。

3.深拷贝

如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供。

在这里插入图片描述

  1. 对比下面的赋值运算符
String &operator=(String s)
{
        swap(_str, s._str);
        return *this;
}

传值方式的使用:
在赋值运算符中,使用传值意味着函数参数String s在调用时会创建一个副本。也就是说,当执行String a = b;时,会调用operator=(String s),而参数s是对象b的一个副本。即当operator=被调用时,编译器会生成一个新的String对象(s),它是被赋值对象的副本。
swap(_str, s._str);将当前对象的内部指针_str与副本对象s的内部指针进行交换。由于s是传值过来的副本对象,交换之后,当前对象_str指向了副本对象的内存,而副本对象s则指向了当前对象原来所指向的内存。
交换操作完成后,副本对象s会在函数结束时自动销毁,其析构函数会释放它持有的内存,即之前当前对象持有的内存。因此,这种方式下的赋值运算符不会导致内存泄漏。为更优写法。

 String& operator=(const String& s)
{
    if(this != &s)
    {
    String strTmp(s);
    swap(_str, strTmp._str);
    }
    return *this;
}

这个赋值运算符首先检查是否是自我赋值,然后为字符串分配新内存并将字符串内容复制过来,最后释放旧内存。这样做的优点是直接了当,但缺点是容易引入内存泄漏的风险,特别是在内存分配成功但复制内容失败时。

  1. 对比拷贝构造函数
String(const String &s)
        : _str(nullptr)
    {
        String strTmp(s._str);
        swap(_str, strTmp._str);
    }

由于在拷贝构造函数中,首先创建了一个临时对象 strTmp,即使在创建临时对象时发生异常,当前对象的状态也不会被改变。只有当 strTmp 构造成功后,才会进行交换操作。因此,当前对象总是保持在一种安全状态。为更优写法。

String(const String &s)
    : _str(new char[strlen(s._str) + 1])
{
    strcpy(_str, s._str);
}

这个拷贝构造函数使用了直接分配新内存的方式。它根据传入对象String中的字符串长度,分配相同长度的新内存,然后将字符串内容复制到新内存中。


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

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

相关文章

鸿蒙 HarmonyOS 下拉控件

✍️作者简介&#xff1a;小北编程&#xff08;专注于HarmonyOS、Android、Java、Web、TCP/IP等技术方向&#xff09; &#x1f433;博客主页&#xff1a; 开源中国、稀土掘金、51cto博客、博客园、知乎、简书、慕课网、CSDN &#x1f514;如果文章对您有一定的帮助请&#x1f…

Verilog和Matlab实现RGB888互转YUV444

文章目录 一、色彩空间1.1 RGB色彩空间1.2 CMYK色彩空间1.3 YUV色彩空间 二、色彩空间转换公式2.1 RGB转CMYK2.2 CMYK转RGB2.3 RGB888转YUV4442.4 YUV444转RGB888 三、MATLAB实现RGB888转YUV4443.1 matlab代码3.2 matlab结果 四、Verilog实现RGB888转YUV444 一、色彩空间 色彩空…

python_openCV_计算图片中的区域的黑色比例

希望对原始图片进行处理,然后计算图片上的黑色和白色的占比 上图, 原始图片 import numpy as np import cv2 import matplotlib.pyplot as pltdef cal_black(img_file):#功能: 计算图片中的区域的黑色比例#取图片中不同的位置进行计算,然后计算器数值#----------------p…

如何使用事件流相关操作

文章目录 1. 概念介绍2. 使用方法StreamControllerStreamBuilder 3. 示例代码 我们在上一章回中介绍了管理Stream事件流相关的内容&#xff0c;本章回中将介绍如何使用Stream事件流输入输出数据 。闲话休提&#xff0c;言归正传&#xff0c;让我们一起Talk Flutter吧。 1. 概念…

【VSCode v1.93.0】手动配置远程remote-ssh

开发环境 VS Code版本&#xff1a;1.93.0 (Windows) Ubuntu版本&#xff1a;20.04 使用VS Code 插件remote-ssh远程访问Ubuntu服务器中的代码&#xff0c;若Ubuntu无法联网&#xff0c;在连接的时候会报错&#xff1a; Could not establish connection to "xxxx": F…

前端玩Postgres数据库:Ai大法一把梭

大家好&#xff0c;我是程序员凌览。 前段时间分享如何白嫖一台服务器 &#x1f449;&#x1f3fc;&#x1f449;&#x1f3fc;白嫖不是梦&#xff0c;三分钟搞定一台服务器。 本文分享如何在平台Vercel白嫖服务器的同时蹭个postgres数据库。 创建数据库 切换到Storage&…

828华为云征文|基于Flexus云服务器X实例的应用场景-部署自己的博客系统

&#x1f534;大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 先看这里 写在前面效果图部署拾壹博客系统项目架构项目特点详细介绍部署博客系统更改redis的信息打包后端上传jar到服务器中打包前端项目 总结 写在前面 华为云828云服务器活…

【加密社】如何根据.dat文件恢复密钥

加密社 看了这篇指南&#xff0c;你将了解助记词和密钥地址&#xff08;qianbao&#xff09;背后的基本原理。 以及&#xff0c;如何找回你的大饼密钥。 Not your key, not your coin 如果你不掌握自己加密货币钱包的私钥&#xff0c;那么你实际上并不能完全控制你的资产 在当今…

每日OJ_牛客_走迷宫(简单bfs)

目录 牛客_走迷宫&#xff08;简单bfs&#xff09; 解析代码&#xff1a; 牛客_走迷宫&#xff08;简单bfs&#xff09; 走迷宫__牛客网 解析代码&#xff1a; 采用一个二维数组&#xff0c;不断的接受迷宫地图(因为有多个地图)&#xff0c;获取到迷宫地图后&#xff0c;采…

智能匹配新高度:相亲交友系统如何运用AI技术提升用户体验

在数字化时代&#xff0c;相亲交友系统正逐渐融入人工智能&#xff08;AI&#xff09;技术&#xff0c;以提升用户体验和匹配效率。AI的引入不仅改变了传统的交友方式&#xff0c;还为用户带来了更加个性化和精准的交友体验。以下是一篇关于如何运用AI技术提升相亲交友系统用户…

第L8周:机器学习|K-means聚类算法

本文为&#x1f517;365天深度学习训练营中的学习记录博客 &#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 &#x1f680; 文章来源&#xff1a;K同学的学习圈子深度学习 聚类算法的定义&#xff1a; 聚类就是将一个庞杂数据集中具有相似特征的数据自动归类到一…

YOLOV5入门教学-common.py文件

在 YOLOv5 框架中&#xff0c;common.py 文件是一个核心组件&#xff0c;负责定义深度学习模型的基础模块和常用操作。无论是卷积层、激活函数、特征融合还是其他复杂的模型结构&#xff0c;common.py 都提供了灵活且高效的实现。在这篇文章中&#xff0c;我们将深入解析 commo…

【科普知识】一体化电机掉电后“位置精准复位“机制与规律

在工业自动化、机器人技术及精密控制领域&#xff0c;电机作为核心执行元件&#xff0c;其稳定运行和精确控制对于整个系统的性能至关重要。 然而&#xff0c;电机在运行过程中可能会遭遇突然断电的情况&#xff0c;这会导致电机失去驱动力并停止在当前位置&#xff0c;甚至在…

基于YOLOv10的垃圾检测系统

基于YOLOv10的垃圾检测系统 (价格90) 包含 [CardBoard, Glass, Metal, Paper, Plastic] 5个类 [纸板, 玻璃, 金属, 纸张, 塑料] 通过PYQT构建UI界面&#xff0c;包含图片检测&#xff0c;视频检测&#xff0c;摄像头实时检测。 &#xff08;该系统可以根据数据训练出的…

Minimax-秋招正式批-面经(计网)

6. websocket和http区别 websocket知识点总结_防火墙 websocket-CSDN博客 相同点 都是基于TCP协议&#xff0c;都是可靠性传输协议都是应用层协议 不同点 HTTP 类型&#xff1a; 请求-响应式的无状态协议&#xff0c;半双工通信&#xff0c;同一时刻只能一个方向上有动作通…

变阻箱和负载箱的区别

变阻箱和负载箱是两种常见的电力设备&#xff0c;它们在电力系统中起着重要的作用。虽然它们都是用来调节电流的&#xff0c;但是它们的工作原理和用途有很大的区别。 首先&#xff0c;我们来看看变阻箱。变阻箱是一种可以改变电阻值的设备&#xff0c;它的主要作用是调节电流…

el-table使用type=“expand”根据数据条件隐藏展开按钮

一&#xff1a;添加className <el-table :data"tableData" border :loading"loading" :row-class-name"getRowClass" expand-change"expandchange"><el-table-column type"expand"><template #default"…

基于51单片机的智能小车转向控制系统设计与实现

文章目录 前言资料获取设计介绍功能介绍具体实现截图参考文献设计获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师&#xff0c;一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对…

PCB散热设计

随着电子设备性能的不断提升&#xff0c;电路板上的元器件集成度越来越高&#xff0c;发热量也随之增加。如何有效管理这些热量&#xff0c;保证电路板在高温环境下的稳定运行&#xff0c;成为设计过程中一个不可忽视的问题。如果散热不佳&#xff0c;电子元件可能会因过热导致…

python3删除es 45天前索引,生产环境验证过

本人es版本 环境 pip install --upgrade elasticsearch==7.16.3代码 from datetime import datetime, timedelta from elasticsearch import Elasticsearch