数据结构和算法:复杂度分析

news2024/11/27 2:18:12

算法效率评估

时间效率:算法运行速度的快慢。
空间效率:算法占用内存空间的大小。

效率评估方法主要分为两种:实际测试、理论估算

实际测试问题:
1.难以排除测试环境的干扰因素。
硬件配置会影响算法的性能。需要在各种机器上进行测试,统计平均效率,而这是不现实的。
2.展开完整测试非常耗费资源。
随着输入数据量的变化,算法会表现出不同的效率。因此,为了得到有说服力的结论,需要测试各种规模的输入数据,而这需要耗费大量的计算资源。

由于实际测试具有较大的局限性,因此我们可以考虑仅通过一些计算来评估算法的效率。这种估算方法被称为渐近复杂度分析 (asymptotic complexity analysis),简称复杂度分析

复杂度分析能够体现算法运行所需的时间和空间资源与输入数据大小之间的关系。它描述了随着输入数据大小的增加,算法执行所需时间和空间的增长趋势。
1.“时间和空间资源”分别对应时间复杂度(time complexity)和空间复杂度(space complexity)。
2.“随着输入数据大小的增加”意味着复杂度反映了算法运行效率与输入数据体量之间的关系。
3.“时间和空间的增长趋势”表示复杂度分析关注的 不是运行时间或占用空间的具体值,而是时间或空间增长的“快慢”。

复杂度分析克服了实际测试方法的弊端:
1.独立于测试环境,分析结果适用于所有运行平台;
2.可以体现不同数据量下的算法效率,尤其是在大数据量下的算法性能。

迭代与递归

迭代(iteration) 是一种重复执行某个任务的控制结构。在迭代中,程序会在满足一定的条件下重复执行某段代码,直到这个条件不再满足。

/**
 * File: iteration.cpp
 * Created Time: 2023-08-24
 * Author: Krahets (krahets@163.com)
 */

#include "../utils/common.hpp"

/* for 循环 */
int forLoop(int n) {
    int res = 0;
    // 循环求和 1, 2, ..., n-1, n
    for (int i = 1; i <= n; ++i) {
        res += i;
    }
    return res;
}

/* while 循环 */
int whileLoop(int n) {
    int res = 0;
    int i = 1; // 初始化条件变量
    // 循环求和 1, 2, ..., n-1, n
    while (i <= n) {
        res += i;
        i++; // 更新条件变量
    }
    return res;
}

/* while 循环(两次更新) */
int whileLoopII(int n) {
    int res = 0;
    int i = 1; // 初始化条件变量
    // 循环求和 1, 4, 10, ...
    while (i <= n) {
        res += i;
        // 更新条件变量
        i++;
        i *= 2;
    }
    return res;
}

/* 双层 for 循环 */
string nestedForLoop(int n) {
    ostringstream res;
    // 循环 i = 1, 2, ..., n-1, n
    for (int i = 1; i <= n; ++i) {
        // 循环 j = 1, 2, ..., n-1, n
        for (int j = 1; j <= n; ++j) {
            res << "(" << i << ", " << j << "), ";
        }
    }
    return res.str();
}

/* Driver Code */
int main() {
    int n = 5;
    int res;

    res = forLoop(n);
    cout << "\nfor 循环的求和结果 res = " << res << endl;

    res = whileLoop(n);
    cout << "\nwhile 循环的求和结果 res = " << res << endl;

    res = whileLoopII(n);
    cout << "\nwhile 循环(两次更新)求和结果 res = " << res << endl;

    string resStr = nestedForLoop(n);
    cout << "\n双层 for 循环的遍历结果 " << resStr << endl;

    return 0;
}

在这里插入图片描述

递归 (recursion) 是一种算法策略,通过函数调用自身来解决问题。它主要包含两个阶段:
1.递:程序不断深入地调用自身,通常传入更小或更简化的参数,直到达到“终止条件”。
2.归:触发“终止条件”后,程序从最深层的递归函数开始逐层返回,汇聚每一层的结果。

/**
 * File: recursion.cpp
 * Created Time: 2023-08-24
 * Author: Krahets (krahets@163.com)
 */

#include "../utils/common.hpp"

/* 递归 */
int recur(int n) {
    // 终止条件
    if (n == 1)
        return 1;
    // 递:递归调用
    int res = recur(n - 1);
    // 归:返回结果
    return n + res;
}

/* 使用迭代模拟递归 */
int forLoopRecur(int n) {
    // 使用一个显式的栈来模拟系统调用栈
    stack<int> stack;
    int res = 0;
    // 递:递归调用
    for (int i = n; i > 0; i--) {
        // 通过“入栈操作”模拟“递”
        stack.push(i);
    }
    // 归:返回结果
    while (!stack.empty()) {
        // 通过“出栈操作”模拟“归”
        res += stack.top();
        stack.pop();
    }
    // res = 1+2+3+...+n
    return res;
}

/* 尾递归 */
int tailRecur(int n, int res) {
    // 终止条件
    if (n == 0)
        return res;
    // 尾递归调用
    return tailRecur(n - 1, res + n);
}

/* 斐波那契数列:递归 */
int fib(int n) {
    // 终止条件 f(1) = 0, f(2) = 1
    if (n == 1 || n == 2)
        return n - 1;
    // 递归调用 f(n) = f(n-1) + f(n-2)
    int res = fib(n - 1) + fib(n - 2);
    // 返回结果 f(n)
    return res;
}

/* Driver Code */
int main() {
    int n = 5;
    int res;

    res = recur(n);
    cout << "\n递归函数的求和结果 res = " << res << endl;

    res = forLoopRecur(n);
    cout << "\n使用迭代模拟递归求和结果 res = " << res << endl;

    res = tailRecur(n, 0);
    cout << "\n尾递归函数的求和结果 res = " << res << endl;

    res = fib(n);
    cout << "\n斐波那契数列的第 " << n << " 项为 " << res << endl;

    return 0;
}

在这里插入图片描述

递归:1+2+…+n

/* 递归 */
int recur(int n) {
    // 终止条件
    if (n == 1)
        return 1;
    // 递:递归调用
    int res = recur(n - 1);
    // 归:返回结果
    return n + res;
}

在这里插入图片描述

调用栈

递归函数每次调用自身时,系统都会为新开启的函数分配内存,以存储局部变量、调用地址和其他信息等。
这将导致两方面的结果:
1.函数的上下文数据都存储在称为“栈帧空间”的内存区域中,直至函数返回后才会被释放。因此,递归通常比迭代更加耗费内存空间。
2.递归调用函数会产生额外的开销。因此递归通常比循环的时间效率更低

栈顺序:先入后出

尾递归

如果函数在返回前的最后一步才进行递归调用,则该函数可以被编译器或解释器优化,使其在空间效率上与迭代相当。这种情况被称为尾递归 (tail recursion)。

许多编译器或解释器并不支持尾递归优化,如 Python,即使函数是尾递归形式,仍然可能会遇到栈溢出问题。

普通递归:当函数返回到上一层级的函数后,需要继续执行代码,因此系统需要保存上一层调用的上下文。
尾递归:递归调用是函数返回前的最后一个操作,这意味着函数返回到上一层级后,无须继续执行其他操作,因此系统无须保存上一层函数的上下文。

/* 尾递归 */
int tailRecur(int n, int res) {
    // 终止条件
    if (n == 0)
        return res;
    // 尾递归调用
    return tailRecur(n - 1, res + n);
}

普通递归:求和操作是在“归”的过程中执行的,每层返回后都要再执行一次求和操作。
尾递归:求和操作是在“递”的过程中执行的,“归”的过程只需层层返回。
在这里插入图片描述

递归树

给定一个斐波那契数列 0, 1, 1, 2, 3, 5, 8, 13, … ,求该数列的第 𝑛 个数字:

/* 斐波那契数列:递归 */
int fib(int n) {
    // 终止条件 f(1) = 0, f(2) = 1
    if (n == 1 || n == 2)
        return n - 1;
    // 递归调用 f(n) = f(n-1) + f(n-2)
    int res = fib(n - 1) + fib(n - 2);
    // 返回结果 f(n)
    return res;
}

在函数内递归调用了两个函数,这意味着从一个调用产生了两个调用分支。如图 所示,这样不断递归调用下去,最终将产生一棵层数为 𝑛 的递归树(recursion tree)。
在这里插入图片描述
从本质上看,递归体现了“将问题分解为更小子问题”的思维范式,这种分治策略至关重要。
从算法角度看,搜索、排序、回溯、分治、动态规划等许多重要算法策略直接或间接地应用了这种思维方式。
从数据结构角度看,递归天然适合处理链表、树和图的相关问题,因为它们非常适合用分治思想进行分析。

两者对比

在这里插入图片描述
事实上,“调用栈”和“栈帧空间”这类递归术语已经暗示了递归与栈之间的密切关系。
1.递:当函数被调用时,系统会在“调用栈”上为该函数分配新的栈帧,用于存储函数的局部变量、参数、返回地址等数据。
2.归:当函数完成执行并返回时,对应的栈帧会被从“调用栈”上移除,恢复之前函数的执行环境。
因此,可以使用一个显式的栈来模拟调用栈的行为,从而将递归转化为迭代形式:

/* 使用迭代模拟递归 */
int forLoopRecur(int n) {
    // 使用一个显式的栈来模拟系统调用栈
    stack<int> stack;
    int res = 0;
    // 递:递归调用
    for (int i = n; i > 0; i--) {
        // 通过“入栈操作”模拟“递”
        stack.push(i);
    }
    // 归:返回结果
    while (!stack.empty()) {
        // 通过“出栈操作”模拟“归”
        res += stack.top();
        stack.pop();
    }
    // res = 1+2+3+...+n
    return res;
}

尽管迭代和递归在很多情况下可以互相转化,但不一定值得这样做,有以下两点原因:
1.转化后的代码可能更加难以理解,可读性更差;
2.对于某些复杂问题,模拟系统调用栈的行为可能非常困难;
总之,选择迭代还是递归取决于特定问题的性质。

时间复杂度

运行时间可以直观且准确地反映算法的效率。
1.确定运行平台,包括硬件配置、编程语言、系统环境等,这些因素都会影响代码的运行效率;
2.评估各种计算操作所需的运行时间;
3.统计代码中所有的计算操作,并将所有操作的执行时间求和,从而得到运行时间。
实际上,统计算法的运行时间既不合理也不现实。首先,我们不希望将预估时间和运行平台绑定,因为算法需要在各种不同的平台上运行。其次,我们很难获知每种操作的运行时间,这给预估过程带来了极大的难度。

统计时间增长趋势

时间复杂度分析统计的不是算法运行时间,而是算法运行时间随着数据量变大时的增长趋势

/* 常数阶 */
//虽然运行时间很长,但它与输入数据大小 n 无关
int constant(int n) {
    int count = 0;
    int size = 100000;
    for (int i = 0; i < size; i++)
        count++;
    return count;
}

/* 线性阶 */
int linear(int n) {
    int count = 0;
    for (int i = 0; i < n; i++)
        count++;
    return count;
}

相较于直接统计算法的运行时间,时间复杂度分析的特点:
1.时间复杂度能够有效评估算法效率;
2.时间复杂度的推算方法更简便;
3. 时间复杂度也存在一定的局限性。

函数渐近上界

将线性阶的时间复杂度记为 O ( n ) O(n) O(n) ,这个数学符号称为大 O 记号 big‑ Onotation,表示函数 𝑇(n)的渐近上界 (asymptotic upper bound).
在这里插入图片描述
在这里插入图片描述
计算渐近上界就是寻找一个函数 f ( n ) f(n) f(n) ,使得当 n n n 趋向于无穷大时, T ( n ) T(n) T(n) f ( n ) f(n) f(n) 处于相同的增长级别,仅相差一个常数项 c 的倍数。

推算方法

第一步:统计操作数量:
a.操作数量 𝑇(𝑛) 中的各种系数、常数项都可以忽略;
b.循环嵌套时使用乘法。总操作数量等于外层循环和内层循环操作数量之积。
第二步:判断渐近上界:
在 𝑛 趋于无穷大时,最高阶的项将发挥主导作用,其他项的影响都可以忽略。

常见类型

在这里插入图片描述
在这里插入图片描述
常数阶 𝑂(1): 常数阶的操作数量与输入数据大小 𝑛 无关,即不随着 𝑛 的变化而变化。

线性阶 𝑂(𝑛): 线性阶的操作数量相对于输入数据大小 𝑛 以线性级别增长。

遍历数组和遍历链表等操作的时间复杂度均为 𝑂(𝑛) ,其中 𝑛 为数组或链表的长度.

平方阶 𝑂(𝑛2): 平方阶的操作数量相对于输入数据大小 𝑛 以平方级别增长。平方阶通常出现在嵌套循环中。

指数阶 𝑂(2𝑛): 指数阶增长非常迅速,在穷举法(暴力搜索、回溯等)中比较常见。对于数据规模较大的问题,指数阶是不可接受的,通常需要使用动态规划或贪心算法等来解决。

对数阶 𝑂(log 𝑛): 与指数阶相反,对数阶反映了“每轮缩减到一半”的情况。设输入数据大小为 𝑛 ,由于每轮缩减到一半,因此循环次数是 log ⁡ 2 n \log_2 n log2n ,即 2 n 2^n 2n 的反函数。简记为 𝑂(log 𝑛).

线性对数阶 𝑂(𝑛 log ): 线性对数阶常出现于嵌套循环中,两层循环的时间复杂度分别为 𝑂(log 𝑛) 和 𝑂(𝑛)。
主流排序算法的时间复杂度通常为 𝑂(𝑛 log 𝑛) ,例如快速排序、归并排序、堆排序等。

阶乘阶 𝑂(𝑛!): 阶乘阶对应数学上的“全排列”问题。给定 𝑛 个互不重复的元素,求其所有可能的排列方案。
因为当 𝑛 ≥ 4 时恒有 𝑛! > 2𝑛 ,所以阶乘阶比指数阶增长得更快,在 𝑛 较大时也是不可接受的。

最差、最佳、平均时间复杂度

算法的时间效率往往不是固定的,而是与输入数据的分布有关。

实际中很少使用最佳时间复杂度,因为通常只有在很小概率下才能达到,可能会带来一定的误导性。而最差时间复杂度更为实用,因为它给出了一个效率安全值;
最差时间复杂度和最佳时间复杂度只出现于“特殊的数据分布”,这些情况的出现概率可能很小,并不能真实地反映算法运行效率。相比之下,平均时间复杂度可以体现算法在随机输入数据下的运行效率,用 Θ 记号来表示。

空间复杂度

空间复杂度(space complexity)用于衡量算法占用内存空间随着数据量变大时的增长趋势。

算法相关空间

输入空间:用于存储算法的输入数据。
暂存空间:用于存储算法在运行过程中的变量、对象、函数上下文等数据。
输出空间:用于存储算法的输出数据。
一般情况下,空间复杂度的统计范围是“暂存空间”加上“输出空间”。

暂存空间可以进一步划分为三个部分:
1.暂存数据:用于保存算法运行过程中的各种常量、变量、对象等。
2.栈帧空间:用于保存调用函数的上下文数据。系统在每次调用函数时都会在栈顶部创建一个栈帧,函数返回后,栈帧空间会被释放。
3.指令空间:用于保存编译后的程序指令,在实际统计中通常忽略不计。

在这里插入图片描述

推算方法

空间复杂度的推算方法与时间复杂度大致相同,只需将统计对象从“操作数量”转为“使用空间大小”。
通常只关注最差空间复杂度。 因为内存空间是一项硬性要求,必须确保在所有输入数据下都有足够的内存空间预留。

最差空间复杂度中的“最差”有两层含义:
1.以最差输入数据为准;
2.以算法运行中的峰值内存为准。

在递归函数中,需要注意统计栈帧空间。

常见类型

在这里插入图片描述
常数阶 𝑂(1): 常数阶常见于数量与输入数据大小 𝑛 无关的常量、变量、对象。
需要注意的是,在循环中初始化变量或调用函数而占用的内存,在进入下一循环后就会被释放,因此不会累积占用空间,空间复杂度仍为 𝑂(1) ;

线性阶 𝑂(𝑛): 线性阶常见于元素数量与 𝑛 成正比的数组、链表、栈、队列等。

平方阶 𝑂(𝑛2): 平方阶常见于矩阵和图,元素数量与 𝑛 成平方关系。

指数阶 𝑂(2𝑛): 指数阶常见于二叉树。

层数为 𝑛 的“满二叉树”的节点数量为 2^𝑛 − 1 ,占用 𝑂(2𝑛) 空间

对数阶 𝑂(log 𝑛): 对数阶常见于分治算法。例如归并排序,输入长度为 𝑛 的数组,每轮递归将数组从中点处划分为两半,形成高度为 log 𝑛 的递归树,使用 𝑂(log 𝑛) 栈帧空间。

权衡时间与空间

降低时间复杂度通常需要以提升空间复杂度为代价,反之亦然。我们将牺牲内存空间来提升算法运行速度的思路称为“以空间换时间”;反之,则称为“以时间换空间”。

学习地址

学习地址:https://github.com/krahets/hello-algo
重新复习数据结构,所有的内容都来自这里。

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

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

相关文章

第五十六回 徐宁教使钩镰枪 宋江大破连环马-飞桨图像分类套件PaddleClas初探

宋江等人学会了钩镰枪&#xff0c;大胜呼延灼。呼延灼损失了很多人马&#xff0c;不敢回京&#xff0c;一个人去青州找慕容知府。一天在路上住店&#xff0c;马被桃花山的人偷走了&#xff0c;于是到了青州&#xff0c;带领官兵去打莲花山。 莲花山的周通打不过呼延灼&#xf…

vivado 使用Design Runs窗口、

使用Design Runs窗口 “设计运行”窗口显示在项目中创建的所有合成和实现运行。它包括用于配置、管理和启动运行的命令。 打开Design Run窗口 选择窗口 →  Design Runs打开“Design Runs”窗口。 设计运行窗口功能 •每个实现运行都缩进显示在其子级的合成运行下面。 …

[Java、Android面试]_01_多线程: 重要参数、状态、优雅停止线程等

本人今年参加了很多面试&#xff0c;也有幸拿到了一些大厂的offer&#xff0c;整理了众多面试资料&#xff0c;后续还会分享众多面试资料&#xff0c;感兴趣的朋友可收藏关注&#xff0c; 现分享如下&#xff1a; 文章目录 1. 线程池重要参数2. 线程池状态3. 优雅停止线程4. 线…

【Qt学习笔记】(二)--第一个程序“Hello World”(学习Qt中程序的运行、发布、编译过程)

声明&#xff1a;本人水平有限&#xff0c;博客可能存在部分错误的地方&#xff0c;请广大读者谅解并向本人反馈错误。    因为我个人对Qt也是有一些需求&#xff0c;所以开设本专栏进行学习&#xff0c;希望大家可以一起学习&#xff0c;共同进步。   这篇博客将从一个 He…

HTML 学习笔记(十一)表单

一、分块 1.单行文本框控件–文本框和密码框 文本框控件通过单标签input实现&#xff0c;其具有必要属性type来控制输入控件的类型(默认为text即文本信息)&#xff0c;密码框的type为password(口令)。   表单的动作属性定义了目的文件的文件名。由动作属性定义的这个文件通常…

Qt QDateTime类使用

一.Qt datetime 介绍 Qt中的QDateTime类是用于处理日期和时间的组合的类&#xff0c;它提供了丰富的功能来操作和格式化日期时间数据。以下是其主要特点和用法&#xff1a; 构造函数&#xff1a;QDateTime可以通过组合QDate&#xff08;日期&#xff09;和QTime&#xff08;时…

C++感受2-逐字逐句,深入理解C++最小例程

以 “Hello World” 例程为载体、线索&#xff0c;在完成 “间接名字空间限定” 写法转换到“直接名字空间限定”的过程&#xff0c;同时掌握函数、主函数、函数调用、级联操作、声明、类型、int、字符串类型、头文件包含、行为数据、流输出操作符、标准输出流对象、标准库名字…

LeetCode.2129. 将标题首字母大写

&#x1f354;题目 2129. 将标题首字母大写 &#x1f35f;分析 这道题目描述的很清晰&#xff0c;我们只需要将给定的字符串按照空格划分成字符串数组 str&#xff0c;然后判断 str[i] 的长度如果 <2 &#xff0c;则将 str[i] 转为小写&#xff0c;如果 str[i] 的长度 &g…

Python批量提取Word文档表格数据

在大数据处理与信息抽取领域中&#xff0c;Word文档是各类机构和个人普遍采用的一种信息存储格式&#xff0c;其中包含了大量的结构化和半结构化数据&#xff0c;如各类报告、调查问卷结果、项目计划等。这些文档中的表格往往承载了关键的数据信息&#xff0c;如统计数据、项目…

CSS 用 flex 布局绘制骰子

<!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style>.box {height: 100px;width: 100px;border: 2px solid grey;border-radius: 10px;display: flex;justify-content: center; // 水平居中/* alig…

new-easy(pwn)

1.进行查壳 栈保护&#xff0c;三个保护都开了 NX保护 NX保护在Windows中也被成为称为DEP&#xff0c;是通过现代操作系统的内存单元&#xff08;Memory Protect Unit &#xff0c;MPU&#xff09;机制对程序内存页的粒度进行权限设置&#xff0c;其基本规则为可写权限与可执…

简述类与对象

一、两者关系 类是Java语言中最重要的数据类型&#xff0c;用于创建具体实例&#xff08;对象&#xff09; 抽象出一类事物共有的属性和行为&#xff0c;即数据以及数据上的操作 类是对现实事物的模拟&#xff0c;包含属性&#xff08;成员变量&#xff09;和行为&#xff0…

python读取大型csv文件,降低内存占用,提高程序处理速度

文章目录 简介读取前多少行读取属性列逐块读取整个文件总结参考资料 简介 遇到大型的csv文件时&#xff0c;pandas会把该文件全部加载进内存&#xff0c;从而导致程序运行速度变慢。 本文提供了批量读取csv文件、读取属性列的方法&#xff0c;减轻内存占用情况。 import pand…

2024.3.12 C++

1.思维导图 2.自己封装一个矩形类(Rect)&#xff0c;拥有私有属性:宽度(width)、高度(height),定义公有成员函数: 初始化函数:void init(int w, int h)更改宽度的函数:set_w(int w)更改高度的函数:set_h(int h) 输出该矩形的周长和面积函数:void show() #include <iostream…

python(ogr)处理geojson为本地shp文件

前言 本次所利用的geojson数据来自https://geo.datav.aliyun.com/areas_v3/bound/410000_full.json &#xff0c;如果觉得下方代码看起来不方便&#xff0c;可以来GitHub上来看&#xff0c;在这上面还有一些辅助内容便于理解 GISpjd/GIS-union-Python (github.com)https://gi…

【2024.03.12】定时执行专家 V7.2 发布 - TimingExecutor V7.2 Release

目录 ▉ 软件介绍 ▉ 新版本 V7.2 下载地址 ▉ V7.2 新功能 ▼2024-03-12 V7.2 - 更新日志 ▉ V7.x 新UI设计 ▉ 软件介绍 《定时执行专家》是一款制作精良、功能强大、毫秒精度、专业级的定时任务执行软件。软件具有 25 种【任务类型】、12 种【触发器】触发方式&#x…

Linux内核介绍and下载

Linux内核介绍and下载 介绍下载下载历史版本 我是将军我一直都在&#xff0c;。&#xff01; 介绍 ● Linux是c语言写成的 ● 符合POSIX标准 ● 作者是芬兰的Linus Torvalds ● 发展依赖于五个重要支柱: unix操作系统、minix操作系统、 GNU计划、POSIX标准和互联网 ● 2.6之后…

WebSocket:实现客户端与服务器实时通信的技术

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

CodeSys通过C函数接口调用Qt

文章目录 1.背景介绍2.修改makefile2.1.将编译器由c改成c2.2.使能opencv库2.3.使能Qt库 3.在代码中使用Qt库函数 1.背景介绍 建议先查看之前的文章【CodeSys中调用C语言写的动态库】&#xff0c;了解如何创建一个能够被codesys调用的动态库。 假如想要在函数中使用Qt或者第三方…

Vue3全家桶 - Vue3 - 【8】模板引用【ref】(访问模板引用 + v-for中的模板引用 + 组件上的ref)

模板引用【ref】 Vue3官网-模板引用&#xff1b;如果我们需要直接访问组件中的底层DOM元素&#xff0c;可使用vue提供特殊的ref属性来访问&#xff1b; 一、 访问模板引用 在视图元素上采用ref属性来设置需要访问的DOM元素&#xff1a; 该 ref 属性可采用 字符串 值的执行设…