C/C++语言知识点二

news2025/2/26 7:27:42

1. 编程算法之“哨兵”思想

        哨兵思想是一种编程技巧,通过在数据结构的边界或特定位置放置一个特殊值(称为“哨兵”),来简化逻辑判断和提高代码效率。哨兵通常是一个标记值,用于指示某种条件或边界,从而避免额外的边界检查或条件判断。

哨兵思想的应用场合:

  1. 数组或链表的遍历:在遍历数组或链表时,可以在末尾放置一个哨兵值,避免在每次循环中检查是否越界。

    // 例如,在查找数组中的某个元素时,可以将目标值作为哨兵放在数组末尾,从而简化查找逻辑。
    int find(int arr[], int n, int target) {
        int last = arr[n - 1]; // 保存最后一个元素
        arr[n - 1] = target;   // 将目标值作为哨兵
    
        int i = 0;
        while (arr[i] != target) {
            i++;
        }
    
        arr[n - 1] = last; // 恢复最后一个元素
    
        if (i < n - 1 || arr[n - 1] == target) {
            return i; // 找到目标值
        }
        return -1; // 未找到
    }
  2. 循环终止条件

    • 在循环中,哨兵可以作为终止条件,避免额外的判断。
    • 例如,在读取用户输入时,可以使用特定的哨兵值(如 -1 或 EOF)来终止循环。
      int sum = 0;
      int value;
      
      while (true) {
          scanf("%d", &value);
          if (value == -1) { // -1 作为哨兵
              break;
          }
          sum += value;
      }
      printf("Sum: %d\n", sum);
  3. 排序算法

    • 在某些排序算法(如插入排序)中,哨兵可以减少比较次数。
    • 例如,在插入排序中,可以将数组的第一个元素作为哨兵,避免每次比较时检查数组边界。
  4. 字符串处理

    • 在字符串处理中,哨兵可以标记字符串的结束位置。
    • 例如,C 语言中的字符串以 \0 作为哨兵,表示字符串的结束。
  5. 图的遍历:在图算法中,哨兵可以标记节点的访问状态或边界。


2. Linux内核代码中的一个宏定义

代码:

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

分析: 

  1. (TYPE *)0:将地址0强制类型转换为 TYPE 类型的指针。这里的 0 代表一个空指针,但通过类型转换,它被当作 TYPE 类型的对象来处理。

  2. ((TYPE *)0)->MEMBER:通过上述转换得到的指针访问其 MEMBER 成员。这一步实际上是在访问一个不存在的地址上的成员,但由于编译器在编译时会计算成员的偏移量,所以这一步是安全的。

  3. &((TYPE *)0)->MEMBER:获取 MEMBER 成员变量的地址。由于 MEMBER 是通过类型转换后的指针访问的,所以这个地址实际上是 MEMBERTYPE 结构体中的偏移地址。

  4. (size_t)&((TYPE *)0)->MEMBER:将上述地址转换为 size_t 类型的数据。size_t 是一个无符号整数类型,通常用于表示大小或偏移量。

总结:这个宏的作用是计算并返回 MEMBER 成员在 TYPE 结构体中的偏移量。这个偏移量是一个 size_t 类型的值,表示从结构体的起始地址到成员 MEMBER 的起始地址之间的字节数。


3. 64位和32位Linux系统字节对齐问题

代码分析:

#include <stdio.h>

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

typedef struct s
{
    union
    {
        int a;
        char str[10];
    };
    struct s* next;
} S;

int main()
{
    printf("%d\n", offsetof(S, next));
    return 0;
}

 案例:

#include <stdio.h>

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

typedef struct s
{
    union
    {
        int a;
        char str;
    };
    struct s* next;
} S;

int main()
{
    printf("Size of S: %zu\n", sizeof(S));
    printf("Offset of next: %zu\n", offsetof(S, next));
    return 0;
}

//结果32位、四字节对齐
Size of S: 16
Offset of next: 12

//结果64位、八字节对齐
Size of S: 24
Offset of next: 16

4. const和指针的用法

        在 C/C++ 中,const 关键字用于定义常量或指定某些数据不可修改。它可以应用于变量、指针、函数参数等,具有多种用法和含义。以下是 const 关键字的几种常见用法,特别是与指针结合时的不同含义: 

1. 定义常量:const 可以用于定义常量,常量的值在定义后不能被修改。

const int MAX_VALUE = 100;

特点:
定义时必须初始化。
不能通过赋值修改常量的值。

2. const 与指针:const 与指针结合时,可以有不同的含义,具体取决于 const 的位置。

(1) 指向常量的指针: 

const int *pt;

含义:
    pt 是一个指向 const int 的指针。
    指针可以指向不同的对象,但不能通过 pt 修改所指向的对象。

示例:
    int a = 10;
    const int *pt = &a;
    // *pt = 20; // 错误:不能通过 pt 修改 a
    a = 20;      // 正确:可以直接修改 a

(2) 常量指针: 

int *const pt;

含义:
    pt 是一个常量指针,指向 int 类型。
    指针的值(即指向的地址)不能修改,但可以通过 pt 修改所指向的对象。

示例:
    int a = 10;
    int *const pt = &a;
    *pt = 20;     // 正确:可以通过 pt 修改 a
    // pt = &b;   // 错误:不能修改 pt 的值

(3) 指向常量的常量指针: 

const int *const pt;

含义:
    pt 是一个常量指针,指向 const int 类型。
    指针的值(即指向的地址)不能修改,也不能通过 pt 修改所指向的对象。

示例:
    int a = 10;
    const int *const pt = &a;
    // *pt = 20; // 错误:不能通过 pt 修改 a
    // pt = &b;  // 错误:不能修改 pt 的值

3. const 修饰函数参数:const 可以用于修饰函数参数,表示该参数在函数内部不能被修改。

(1) 修饰指针参数

void print(const int *arr, int size); // arr 是一个指向常量的指针,函数内部不能通过 arr 修改所指向的数据。

 示例:

void print(const int *arr, int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
}

(2) 修饰引用参数(C++)

void print(const std::string &str); // str 是一个常量引用,函数内部不能修改 str 的值

示例:

void print(const std::string &str) {
    std::cout << str;
}

4. const 修饰成员函数(C++):在 C++ 中,const 可以修饰类的成员函数,表示该函数不会修改类的成员变量。

class MyClass {
public:
    int getValue() const {
        return value;
    }
private:
    int value;
};

// getValue 是一个常量成员函数,不能修改类的成员变量。

5. const 修饰返回值:const 可以用于修饰函数的返回值,表示返回值不能被修改。

const int* getPointer(); // 返回的指针指向的内容不能被修改。

6. const 修饰全局或局部变量:const 可以用于修饰全局或局部变量,表示变量的值不能被修改。

void func() {
    const int LOCAL_VALUE = 10;
    // LOCAL_VALUE = 20; // 错误:不能修改常量
}

总结:const 关键字的用法非常灵活,主要作用是保证数据的不变性。以下是一些常见的应用场景:

  1. 定义常量。
  2. 修饰指针,限制指针或指向数据的修改。
  3. 修饰函数参数,防止参数被修改。
  4. 修饰成员函数(C++),保证函数不修改对象状态。
  5. 修饰返回值,限制返回值的修改。

通过合理使用 const,可以提高代码的安全性和可读性,避免意外的数据修改。


5. fork函数 

分析代码:

int main() {
    fork() || fork();
}
  1. fork() 的作用

    • fork() 创建一个新的进程(子进程),子进程是父进程的副本。
    • fork() 在父进程中返回子进程的 PID(大于 0),在子进程中返回 0。
    • 如果 fork() 失败,返回 -1。
  2. 逻辑或运算符 || 的特性

    • A || B:如果 A 为真(非零),则不会执行 B(短路特性)。
    • 如果 A 为假(零),则继续执行 B

进程创建过程:

  1. 第一次 fork()

    • 父进程调用 fork(),创建一个子进程。
    • 父进程中,fork() 返回子进程的 PID(大于 0),因此 fork() || fork() 的值为真,短路特性生效,不会执行第二个 fork()
    • 子进程中,fork() 返回 0,因此 fork() || fork() 的值为假,继续执行第二个 fork()
  2. 第二次 fork()

    • 只有在第一次 fork() 创建的子进程中,才会执行第二个 fork()
    • 子进程调用 fork(),创建另一个子进程(孙子进程)。
    • 子进程中,fork() 返回孙子进程的 PID(大于 0),因此 fork() || fork() 的值为真,短路特性生效。
    • 孙子进程中,fork() 返回 0,因此 fork() || fork() 的值为假。

进程树结构:

父进程
|
├─ 子进程
|   |
|   └─ 孙子进程
|
└─ 子进程

进程总数:总共创建了 3 个进程

  1. 父进程:1 个。
  2. 子进程:1 个。
  3. 孙子进程:1 个。

总结:

  • 代码 fork() || fork() 会创建 3 个进程
  • 第一次 fork() 创建 1 个子进程。
  • 第二次 fork() 在子进程中创建 1 个孙子进程。
  • 父进程和子进程都会执行 fork(),但由于逻辑或运算符的短路特性,父进程不会执行第二个 fork()

6. 按指针引用值传递参数 

代码分析: 下面这段代码的输出结果为:

#include <stdio.h>
void change(int *a, int &b, int c)
{
    c=*a;
    b=30;
    *a=20;
}

int main ( )
{
    int a = 10, b = 20, c = 30;
    change(&a, b, c);
    printf( "%d, %d, %d, ", a, b, c);
    return 0;
}

1. 函数 change 的参数传递

  • int *a
    • 传递指针,函数内部可以通过指针修改 a 的值。
  • int &b
    • 传递引用(C++ 特性),函数内部可以直接修改 b 的值。
  • int c
    • 传递值,函数内部对 c 的修改不会影响外部的 c

2. 函数 change 的逻辑 

void change(int *a, int &b, int c)
{
    c = *a;    // 将指针 a 指向的值赋值给 c(局部变量,不影响外部的 c)
    b = 30;    // 将引用 b 的值修改为 30
    *a = 20;   // 将指针 a 指向的值修改为 20
}

3. main 函数的逻辑

int main()
{
    int a = 10, b = 20, c = 30;
    change(&a, b, c);
    printf("%d, %d, %d, ", a, b, c);
    return 0;
}
  • 调用 change 函数
    • &a 传递 a 的地址。
    • b 传递 b 的引用。
    • c 传递 c 的值。
  • change 函数执行后
    • *a = 20 修改了 a 的值为 20
    • b = 30 修改了 b 的值为 30
    • c = *a 修改了局部变量 c 的值为 10,但外部的 c 不受影响。

总结:

  • 指针 int *a:可以修改外部变量的值。
  • 引用 int &b:可以直接修改外部变量的值。
  • 值传递 int c:对局部变量的修改不影响外部变量。

最终输出结果为:20, 30, 30。


7. 调用几次构造函数

题目内容是:

MyClass 为一个类,执行 MyClass a, *p; 语句时会自动调用该类构造函数的次数是()

选项:

  • A: 2
  • B: 5
  • C: 4
  • D: 9

解题思路:

  1. MyClass a

    • 这是一个数组,包含 4 个 MyClass 对象。
    • 每个对象在创建时都会调用构造函数,因此会调用 4 次构造函数。
  2. MyClass *p

    • 这是一个指针数组,包含 5 个 MyClass 类型的指针。
    • 指针本身是内置类型,不会调用 MyClass 的构造函数。
    • 这些指针默认初始化为 nullptr,不会创建 MyClass 对象。
  3. 总结

    • MyClass a 会调用 4 次构造函数。
    • MyClass *p 不会调用构造函数。
    • 总共调用构造函数的次数是 4 次

8. 统计二进制数中1的个数

题目内容是:

要求:求下面函数的返回值:
int func(int x)
{
    int countx = 0;
    while(x)
    {
        countx++;
        x = x&(x-1);
    }
    return countx;
} 

这个函数的返回值是 整数 x 的二进制表示中 1 的个数。以下是详细分析: 

解题思路:

  1. x = x & (x - 1)

    • 这个操作会将 x 的二进制表示中最右边的 1 置为 0
    • 例如:
      • 如果 x = 12(二进制 1100),则 x - 1 = 11(二进制 1011)。
      • x & (x - 1) = 1100 & 1011 = 1000(二进制 1000)。
      • 下一次循环时,x = 8(二进制 1000),x - 1 = 7(二进制 0111)。
      • x & (x - 1) = 1000 & 0111 = 0000(二进制 0000)。
      • 循环结束。
  2. countx++

    • 每次循环将 countx 加 1,表示找到了一个 1

 示例 1:

int x = 12; // 二进制 1100
int result = func(x);

分析
第一次循环:
    x = 1100,x & (x - 1) = 1000,countx = 1。
第二次循环:
    x = 1000,x & (x - 1) = 0000,countx = 2。
循环结束,返回 2。

示例 2:

int x = 7; // 二进制 0111
int result = func(x);

分析:
第一次循环:
    x = 0111,x & (x - 1) = 0110,countx = 1。
第二次循环:
    x = 0110,x & (x - 1) = 0100,countx = 2。
第三次循环:
    x = 0100,x & (x - 1) = 0000,countx = 3。
循环结束,返回 3。

9. 编写代码:判断一个数是不是2的N次方

方法 1:利用二进制特性

2 的 N 次方的二进制表示中,只有一个 1,其余位都是 0。例如:

  • 1(2⁰):0001
  • 2(2¹):0010
  • 4(2²):0100
  • 8(2³):1000

因此,判断一个数是否是 2 的 N 次方,可以检查它的二进制表示是否只有一个 1

#include <stdio.h>

int isPowerOfTwo(int x) {
    // 如果 x 是 2 的 N 次方,则 x & (x - 1) == 0
    return x > 0 && (x & (x - 1)) == 0;
}

int main() {
    int x;
    printf("Enter a number: ");
    scanf("%d", &x);

    if (isPowerOfTwo(x)) {
        printf("%d is a power of two.\n", x);
    } else {
        printf("%d is not a power of two.\n", x);
    }

    return 0;
}
解释:
  • x > 0:确保 x 是正整数。
  • (x & (x - 1)) == 0:如果 x 是 2 的 N 次方,则 x & (x - 1) 的结果为 0

 

方法 2:循环除以 2

通过循环将 x 反复除以 2,如果最终结果为 1,则 x 是 2 的 N 次方。

#include <stdio.h>

int isPowerOfTwo(int x) {
    if (x <= 0) {
        return 0; // 非正整数不可能是 2 的 N 次方
    }
    while (x > 1) {
        if (x % 2 != 0) {
            return 0; // 如果不能被 2 整除,则不是 2 的 N 次方
        }
        x /= 2;
    }
    return 1; // 最终结果为 1,是 2 的 N 次方
}

int main() {
    int x;
    printf("Enter a number: ");
    scanf("%d", &x);

    if (isPowerOfTwo(x)) {
        printf("%d is a power of two.\n", x);
    } else {
        printf("%d is not a power of two.\n", x);
    }

    return 0;
}
解释:
  • 如果 x 能被 2 整除,则继续除以 2,直到 x 变为 1
  • 如果在过程中 x 不能被 2 整除,则不是 2 的 N 次方。

 

方法 3:利用对数

如果 log₂(x) 是整数,则 x 是 2 的 N 次方。

#include <stdio.h>
#include <math.h>

int isPowerOfTwo(int x) {
    if (x <= 0) {
        return 0; // 非正整数不可能是 2 的 N 次方
    }
    double log2x = log2(x);
    return log2x == (int)log2x; // 判断 log2x 是否为整数
}

int main() {
    int x;
    printf("Enter a number: ");
    scanf("%d", &x);

    if (isPowerOfTwo(x)) {
        printf("%d is a power of two.\n", x);
    } else {
        printf("%d is not a power of two.\n", x);
    }

    return 0;
}
解释:
  • 计算 log₂(x),如果结果是整数,则 x 是 2 的 N 次方。

总结:

  • 推荐方法:方法 1(利用二进制特性),效率最高,代码简洁。
  • 其他方法:方法 2 和方法 3 也可以实现,但效率较低。

 

#include <stdio.h>

#define ISPOWER_OF_TWO(x) ((x&(x-1))==0)

int main(void)
{
    int n;
    printf("Please enter a number, n = ");
    scanf("%d", &n);
    if(ISPOWER_OF_TWO(n))
        printf("n is the power of two\n");
    else
        printf("n is not the power of two\n");
    return 0;
}
#include <stdio.h>

#define ISPOWER_OF_TWO(x) ((x > 0) && ((x & (x - 1)) == 0))

int main(void)
{
    int n;
    printf("Please enter a number, n = ");
    scanf("%d", &n);
    if(ISPOWER_OF_TWO(n))
        printf("n is the power of two\n");
    else
        printf("n is not the power of two\n");
    return 0;
}

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

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

相关文章

国产OS上完整编译Qt5.15、搭建基本开发环境需要的库

近期有师弟问我国产OS安装Qt5.15编译老是不完整&#xff0c;不是没声音&#xff0c;就是没视频&#xff0c;或者没有xcb。通过QEMU模拟Arm64&#xff0c;闲来20几天摸索&#xff0c;完整编译了Qt5.15&#xff0c;并编译成功了我的SDR玩具taskBus。 1.主要结论&#xff1a; 该O…

MyBatis简明教程

MyBatis 是一个用于简化数据库操作的持久层框架&#xff0c;它的核心思想是 将 SQL 与 Java 代码解耦&#xff0c;让开发者专注于 SQL 的编写&#xff0c;同时自动处理重复的数据库操作步骤。 一、核心思想&#xff1a;SQL 与 Java 解耦 传统 JDBC 需要开发者手动管理数据库连…

有什么区别?Elastic 和 Splunk 数据层

作者&#xff1a;来自 Elastic Ugo Sangiorgi, Matt Wehle 了解 Elastic 和 Splunk 数据管理方法之间的主要区别&#xff0c;以便做出明智的决策&#xff0c;实现高效的数据处理 在数据管理领域&#xff0c;在讨论如何根据不同的性能要求提供和/或保留数据时&#xff0c;经常会…

BGP状态和机制

BGP邻居优化 为了增加稳定性,通常建议实验回环口来建立邻居。更新源:建立邻居和邻居所学习到的路由的下一跳。多跳:EBGP邻居建立默认选哟直连,因为TTL=1,如果非直连,必须修改TTL。命令备注peer 2.2.2.2 connect-interface lo1配置更新源peer 2.2.2.2 ebgp-max-hop 2配置T…

【电机控制器】PY32F00BF15U6TR-从KEIL5中计算资源消耗资源

【电机控制器】PY32F00BF15U6TR-从KEIL5中计算资源消耗资源 文章目录 [TOC](文章目录) 前言一、MCU芯片手册二、实验三、实验结论四、参考资料总结 前言 使用工具&#xff1a; 1.KEIL5编译器 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、MCU芯片…

python实战项目58:采集蜻蜓FM热门音频top排行榜

python实战项目58:采集蜻蜓FM热门音频top排行榜 一、采集流程介绍二、数据接口采集三、使用xpath提取页面数据1、抓包,找到数据接口2、发送请求,获取数据3、提取数据4、保存数据一、采集流程介绍 蜻蜓FM热门音频top排行榜的链接为: https://m.qingting.fm/rank/,首页如下图…

STM32【3】芯片的底层组成概论

关于单片机的组成 单片机的意思是&#xff0c;小小计算电脑&#xff0c;麻雀虽小&#xff0c;五脏俱全&#xff0c;里面包含了CPU&#xff0c;ROM&#xff0c;RAM&#xff0c;各种外设。 CPU地位最高&#xff0c;可以访问ROM和RAM&#xff0c;Flash&#xff0c;GPIO等外设&…

基于django图书信息管理系统的搭建(增删改查)

✍django项目搭建教程 ☞ ----------------- 教程 本文主要讲解django如何连接数据库MySQL并且可视化展示&#xff0c;实现增删改查功能 目录 一. 创建django应用 二. 数据库配置 三. 查看数据库 四. 编写代码 4.1视图函数 4.2 配置URL 4.3创建模板文件 4.…

Kotlin 知识点二 延迟初始化和密封类

对变量延迟初始化 Kotlin 语言的许多特性&#xff0c;包括变量不可变&#xff0c;变量不可为空&#xff0c;等等。这些特性 都是为了尽可能地保证程序安全而设计的&#xff0c;但是有些时候这些特性也会在编码时给我们带来不 少的麻烦。 比如&#xff0c;如果你的类中存在很多…

基于SpringBoot的“古城景区管理系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“古城景区管理系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统整体功能图 系统首页界面 系统注册界面 景…

力扣hot100 —— 电话号码字母组合; 子集 (非回溯做法)简单易懂

由于博主对回溯也不是很熟悉&#xff0c;这里提出一种简单易懂的解法&#xff08;有点暴力&#xff09; 解题思路&#xff1a; 每个数字对应有自己的字母串&#xff1b; 首先遍历将每个字母存入也就是 res{{a},{b},{c}} 然后遍历后续数子对应的字母&#xff0c;让每个字母与…

【Redis】在Java中以及Spring环境下操作Redis

Java环境下&#xff1a; 1.创建maven 项目 2.导入依赖 <!-- redis --><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>4.3.2</version></dependency> 此处使用的是Jedis&…

Directx上传堆和默认堆注意事项

前景 之前我用directx写上传堆上传给默认堆Index&#xff0c;但是我发现数据无法被GPU读取 void HelloTriangle::createDefaultBuffer(const void* data, const UINT byteSize, ComPtr<ID3D12Resource>& defaultBuffer) {ThrowIfFiled(m_Device->CreateCommitte…

Java封装弱密码校验工具类

弱密码校验工具类 通过检查密码是否符合某些安全策略来判断其强度 ● 密码长度 ● 字符类型 ● 常见密码组合 import java.util.Arrays; import java.util.HashSet; import java.util.Set;public class WeakPasswordCheckUtil {// 常见弱密码列表&#xff08;可根据需求扩展&…

Figure自研模型Helix发布,人形机器人迈向新纪元?

Figure 公司自 2022 年成立以来&#xff0c;便在人形机器人领域崭露头角&#xff0c;成为行业内备受瞩目的新星。公司由连续创业者 Brett Adcock 创立&#xff0c;总部位于美国加利福尼亚州桑尼维尔&#xff0c;汇聚了来自波士顿动力公司、特斯拉、谷歌 DeepMind 等知名企业的顶…

vue3.0将后端返回的word文件流转换为pdf并导出+html2pdf.js将页面导出为pdf

实现思路 1.将Word文档转换为HTML&#xff1a;mammoth.js&#xff0c;它可以将.docx文件转换为HTML 2.将HTML转换为PDF&#xff1a;使用html2pdf.js将HTML转换为PDF 如果想要相同的效果&#xff0c;也可以把前端页面直接导出转换为pdf: 运用的插件&#xff1a;html2pdf.js 后端…

(Arrow)试时间处理变得更简单

前言 Arrow库并不是简单的二次开发,而是在datetime的基础上进行了扩展和增强。它通过提供更简洁的API、强大的时区支持、丰富的格式化和解析功能以及人性化的显示,填补了datetime在某些功能上的空白。如果你需要更高效、更人性化的日期时间处理方式,Arrow库是一个不错的选择…

锂电池使用和存储电压

表格补充说明&#xff1a; 每列数据中&#xff0c;2S和3S电池的数值都是单电芯数值的2倍和3倍&#xff1b;对于其他电压的电池&#xff0c;将单电芯数值乘以相应S数即可&#xff1b;理论上单个电芯过放电压为3.0V&#xff0c;实际中为了保险&#xff0c;电压降到3.6V即需充电。…

欧拉回路与哈密尔顿回路: Fleury算法与Hierholzer 算法(C++)

图论中的回路是指一个路径, 它从某个顶点开始, 经过所有边恰好一次, 并回到起始顶点. 定义 欧拉回路: 从一个顶点出发, 经过每条边恰好一次, 并且最终回到起始顶点. 哈密尔顿回路: 从一个顶点出发, 经过每个顶点恰好一次, 并且最终回到起始顶点. 欧拉路径: 从一个顶点出发, …

20250221 NLP

1.向量和嵌入 https://zhuanlan.zhihu.com/p/634237861 encoder的输入就是向量&#xff0c;提前嵌入为向量 二.多模态文本嵌入向量过程 1.文本预处理 文本tokenizer之前需要预处理吗&#xff1f; 是的&#xff0c;文本tokenizer之前通常需要对文本进行预处理。预处理步骤可…