Java数据结构(三)——顺序表

news2024/11/15 4:54:25

文章目录

  • 顺序表
    • 前置知识
    • ArrayList的构造
    • ArrayList的常用方法
    • ArrayList的遍历
    • ArrayList的扩容机制
    • ArrayList的模拟实现
    • ArrayList的相关练习

顺序表

前置知识

顺序表线性表的一种(底层是数组),另一种是链表,说到线性表,就得了解 List接口,站在数据结构的角度上,List接口就是线性表,即n个具有相同类型元素的有限序列,在该序列上可以执行增删查改以及变量等操作。

List接口继承自Collection接口,Collection接口规范了后序容器常用的一些方法,例如求元素个数size()、添加新元素add(E)/addAll(Collection<? extends E>)等等,如下图:

在这里插入图片描述

了解完Collection接口的方法,再来看一下List接口的方法,有很多,只截取一部分:
在这里插入图片描述

很多是吧,我们列举常用的,包括接下来要讲的ArrayList类,常用方法也是这几个:

  1. boolean add(E e):尾插e
  2. void add(int index, E element):将 e 插入到index位置
  3. boolean addAll(Collection<? extends E> c):尾插 c 中的所有元素(参数列表的形式我们会在泛型进阶讲解),这里的参数可以接受任何类型的集合,只要这个集合的元素类型是 E 或其子类。
  4. E remove(int index):删除 index 位置的元素
  5. boolean remove(Object o):删除遇到的第一个 o
  6. E get(int index):获取 index 下标位置元素,
  7. E set(int index, E element):将 index 下标位置元素设置为 element
  8. void clear():清空容器
  9. boolean contains(Object o):判断 o 是否在线性表中
  10. int indexOf(Object o):返回第一个 o 所在的下标
  11. int lastindexOf(Object o):返回最后一个 o 所在的下标
  12. List<E> subList(int fromIndex, int toIndex):截取下标区间 [fromIndex, int toIndex] 的元素

【List的使用】

List是一个接口,并不能直接用来实例化,使用时必须实例化List的实现类。 在集合框架中,ArrayListLinkedList都实现了List接口,而ArrayList就是本篇要介绍的主角。


顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。在集合框架中,对应 ArrayList。不过要注意的是,这个数组只能依次存储,不能跳跃式的存储,比如,添加新的元素,不能跳过一个下标,存储在后面,必须依次存储。

我们先看ArrayList类的部分源码:

在这里插入图片描述

  • ArrayList是以泛型方式实现的,是一个泛型类,注意实例化
  • ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问
  • ArrayList实现了Cloneable接口,表明ArrayList是可以clone
  • ArrayList实现了Serializable接口,表明ArrayList是支持序列化的
  • 另外,ArrayList不是线程安全的,在单线程下可以使用,在多线程中可以选择VectorCopyOnWriteArrayList
  • ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表

ArrayList的构造

ArrayList的构造方法有三个:

  1. ArrayList():无参数构造方法
  2. ArrayList(Collection<? extends E> c):利用其他实现了Collection接口的容器构造
  3. ArrayList(int initialCapacity):指定顺序表初始容量的构造方法
        public static void main(String[] args) {
            
            ArrayList<Integer> l1 = new ArrayList<>();//无参构造
            System.out.println(l1);
            
            ArrayList<Integer> l2 = new ArrayList<>(10);//指定初始容量构造
            l2.add(1);
            l2.add(2);
            System.out.println(l2);
            
            ArrayList<Integer> l3 = new ArrayList<>(l2);//使用l2构造
            System.out.println(l3);
        }

在这里插入图片描述

  • 如上代码,我们使用了其他ArrayList对象l2作为参数构造了l3,即将l2的所有元素作为l3初始数据

当然我们可以定义List接口的引用接收ArrayList对象:

            List<Integer> list = new ArrayList<>();
  • 优点:向上转型,从而可以实现多态
  • 缺点:无法调用ArrayList特有的方法,只能调用ArrayList中重写List接口的方法

ArrayList的常用方法

ArrayList类中的常用方法与上文列举的List接口中常用方法一致,这里仅给出演示代码,一些小的注意问题在注释给出:

    public static void main(String[] args) {
        ArrayList<Integer> list1 = new ArrayList<>();
        ArrayList<Integer> list2 = new ArrayList<>();

        list1.add(1);
        list1.add(2);
        list1.add(3);
        list1.add(4);
        list1.add(5);
        list1.remove(2);//删除下标为2位置的元素
        list1.remove(Integer.valueOf(5));//删除值为5的元素
        System.out.println(list1);//打印结果为[1, 2, 4]
        list2.add(6);
        list2.add(7);
        list2.add(8);
        list1.addAll(list2);//将list2中的所有元素尾插到list1中
        System.out.println(list1);//打印结果为[1, 2, 4, 6, 7, 8]
        list1.set(0, 100);//将0下标位置设置为100
        System.out.println(list1.get(0));//打印0下标位置的元素100
//        list1.add(100, 100);   error,报错!因为顺序表只允许连续存储,不允许跳跃式存储
        System.out.println(list1.contains(100));//100在表中,打印true
        List<Integer> list3 = list1.subList(0, 3);//截取[0, 3)下标位置的元素,返回一个List<Integer>的对象,用list3接收
        System.out.println(list3);//打印结果是[100, 2, 4]
    }

ArrayList的遍历

前面的演示代码中我们使用System.out.println(对象的引用);的方式打印表中的数据,这是因为ArrayList类中重写了toString方法

现在我们介绍三种ArrayList的遍历方法:forfor-each以及迭代器

直接看代码:

   public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);

        //for循环 + 下标遍历
        System.out.println("=====for循环=====");
        for (int i = 0; i < list.size(); i++) {
            System.out.print(list.get(i) + " ");
        }
        System.out.println();

        //for-each循环
        System.out.println("=====for-each循环=====");
        for (int x : list) {
            System.out.print(x + " ");
        }
        System.out.println();
        for(Integer x : list) {
            System.out.print(x + " ");
        }
        System.out.println();

        //使用迭代器
        System.out.println("=====使用迭代器=====");
        Iterator<Integer> it = list.iterator();
        while(it.hasNext()) {
            System.out.print(it.next() + " ");
        }
        System.out.println();

        ListIterator<Integer> lIt = list.listIterator();
        while(lIt.hasNext()) {
            System.out.print(lIt.next() + " ");
        }
        System.out.println();

        System.out.println("=====逆序输出=====");
        ListIterator<Integer> lIt1 = list.listIterator(list.size());
        while(lIt1.hasPrevious()) {
            System.out.print(lIt1.previous() + " ");
        }
    }

在这里插入图片描述

  • for循环:利用方法size()get()即可
  • for-each:以整型为例,:左边可以是Integer包装类也可以是int(自动拆箱)
  • 迭代器IteratorListIterator都是接口,ListIterator接口继承了Iterator接口,使用时调用指定方法即可
  • 对于拓展的逆序输出,ListIterator可以做到,但是Iterator没有相关的方法

ArrayList的扩容机制

抛出几个问题:使用ArrayList的空构造方法实例化的顺序表初始容量是多少?向顺序表中添加数据时,如果表满了,怎么扩容?

对于这几个问题,我们要观察ArrayList的源码:

在这里插入图片描述

对于ArrayList实现的接口以及表示的含义前面已经介绍过了,直接看定义的成员变量:

  • serialVersionUID是Java序列化机制中的一个特殊字段,用于标识类的版本

  • DEFAULT_CAPACITY是默认的初始化容量,为10

  • EMPTY_ELEMENTDATADEFAULTCAPACITY_EMPTY_ELEMENTDATA

    共同点

    • 它们都是用来表示空ArrayList实例的静态final常量。
    • 它们都是Object类型的数组。
    • 它们都被声明为private,只在ArrayList内部使用。

    区别

    • EMPTY_ELEMENTDATA是一个真正的空数组(长度为0),而DEFAULTCAPACITY_EMPTY_ELEMENTDATA的长度等于DEFAULT_CAPACITY
    • 当添加第一个元素时,如果使用的是EMPTY_ELEMENTDATA,则需要创建一个新的数组并设置其大小为DEFAULT_CAPACITY;如果使用的是DEFAULTCAPACITY_EMPTY_ELEMENTDATA,则可以直接在原数组上进行调整。
    • EMPTY_ELEMENTDATA用于普通的空ArrayList实例,而DEFAULTCAPACITY_EMPTY_ELEMENTDATA用于那些初始容量已经设置为默认容量的空ArrayList实例。
  • elementData:即顺序表,存储顺序表的元素

  • size:当前顺序表的有效数据数量


接着我们看一下三个构造方法:

在这里插入图片描述

  • 初始化顺序表容量的构造方法:当传入的初始化容量为0时,将EMPTY_ELEMENTDATA赋值给顺序表elementData
  • 无参构造方法:无参构造方法初始容量其实设置为了默认容量,所以赋值DEFAULTCAPACITY_EMPTY_ELEMENTDATA
  • 利用其他Collection的构造方法:先将集合c转化为Object类型的数组,如果数组不为空,判断c的类是否为ArrayList,为真,直接赋值;为假,则通过copyOf创建新数组并拷贝,用新数组赋值;如果数组为空,直接赋值EMPTY_ELEMENTDATA

到这里,我们解决了第一个问题并且拓展了一些,并考虑一个新的问题,这个问题将和最初的问题2一并解决:空构造方法实例化的表是个空数组,那么添加时怎么操作的?


add()方法入手:

在这里插入图片描述

如图第二个add调用了第一个add方法,而第一个和第三个add在表满时,均调用了一个grow()方法

在这里插入图片描述

然后,无参grow又调用了带有参数的grow方法

在这里插入图片描述

首先,将当前容量赋值给oldCapacity,如果if语句判断为假(oldCapacity <= 0 && elementData == DEFAULTCAPACITY_EMPTY_ELEMRNTDATA),执行else语句,即:当添加第一个元素时,如果使用的是无参构造方法,ArrayList会将内部数组的容量从0扩展到10,并赋值;如果if语句判断为真,则调用ArraysSupport.newLength方法计算新容量newCapacity,传入的第一个参数是旧容量,第二个参数是,增长的容量,即带参数的grow的参数与旧容量的差值(由于参数为size + 1,所以这里是1),第三个参数是旧容量的一半。

在这里插入图片描述

newLength方法接受三个参数:oldLength(旧数组长度)、minGrowth(最小增长量)和prefGrowth(首选增长量)。它首先计算首选长度prefLength,即旧数组长度加上minGrowthprefGrowth中的较大值。然后,如果首选长度在0到SOFT_MAX_ARRAY_LENGTH(数组的最大长度限制)之间,就返回这个首选长度;否则,调用hugeLength方法来处理较大的长度情况。

hugeLength方法也接受两个参数:oldLengthminGrowth。它首先计算最小所需长度minLength,即旧数组长度加上最小增长量。然后,如果minLength小于0(表示溢出),就抛出一个OutOfMemoryError异常,提示所需的数组长度过大。如果minLength小于等于SOFT_MAX_ARRAY_LENGTH,则返回SOFT_MAX_ARRAY_LENGTH;否则,返回minLength


【总结】

回归到最初的grow方法:

  1. 检测是否真正需要扩容,如果是调用grow准备扩容
  2. 预估需要库容的大小 初步预估按照1.5倍大小扩容 如果用户所需大小超过预估1.5倍大小,则按照用户所=需大小扩容,真正扩容之前检测是否能扩容成功,防止太大导致扩容失败
  3. 使用copyOf进行扩容
  4. 另外,如果使用的是无参构造方法,当添加第一个元素时,ArrayList会将内部数组的容量从0扩展到10,此后按照上3步

ArrayList的模拟实现

模拟实现一个ArrayList类是比较简单的,只需要掌握对数组的增删查改即可。

实现方式多种多样,能实现增删查改等业务即可,这里给出模拟实现的代码,感兴趣的可以看一下:

import java.util.Arrays;

public class MyArrayList {
    public int[] elem;
    public int capacity;
    public int usedSize;//0
    //默认容量
    private static final int DEFAULT_SIZE = 10;

    public MyArrayList() {
        this.elem = new int[DEFAULT_SIZE];
        this.capacity = 10;
    }

    /**
     * 打印顺序表:
     *   根据usedSize判断即可
     */
    public void display() {
        if(this.isEmpty()) {
            return;
        }
        for(int i = 0; i < this.usedSize; i++) {
            System.out.print(elem[i] + " ");
        }
        System.out.println();
    }

//     新增元素,默认在数组最后新增
    public void add(int data) {
        if(isFull()) {
            this.elem = Arrays.copyOf(this.elem, 2 * this.capacity);
        }
        this.elem[this.usedSize] = data;
        this.usedSize++;
    }

    /**
     * 判断当前的顺序表是不是满的!
     * @return true:满   false代表空
     */
    private boolean isFull() {
        if(this.usedSize == this.capacity) {
            return true;
        }else {
            return false;
        }
    }


    private boolean checkPosInAdd(int pos) {
        //在0位置添加可以,同时在最后位置也可以添加,但是不可以跳着增加
        if(pos >= 0 && pos <= this.usedSize) {
            return true;
        }else {
            throw new PosIllegalException("位置不合法!");
        }
    }

    // 在 pos 位置新增元素
    public void add(int pos, int data) throws PosIllegalException {
        if(isFull()) {
            this.elem = Arrays.copyOf(this.elem, 2 * this.capacity);
        }
        try{
            checkPosInAdd(pos);
            for(int i = this.usedSize; i > pos; i--) {
                this.elem[i] = this.elem[i - 1];
            }
            this.elem[pos] = data;
        }catch (PosIllegalException e) {
            System.out.println("输入的位置不合法!插入失败");
            e.printStackTrace();
        }
    }

    // 判定是否包含某个元素
    public boolean contains(int toFind) {
        if(isEmpty()) {
            return false;
        }
        for(int i = 0; i < this.usedSize; i++) {
            if(toFind == this.elem[i]) {
                return true;
            }
        }
        return false;
    }
    // 查找某个元素对应的位置
    public int indexOf(int toFind) {
        if(isEmpty()) {
            System.out.println("表为空!");
            return -1;
        }
        for (int i = 0; i < this.usedSize; i++) {
            if(toFind == this.elem[i]) {
                return i;
            }
        }
        return -1;
    }

    // 获取 pos 位置的元素
    public int get(int pos) throws PosIllegalException {
        if(isEmpty()) {
            System.out.println("表为空!返回值无效!");
            return -1;
        }
        try {
            checkPosInAdd(pos);
            return this.elem[pos];
        }catch (PosIllegalException e) {
            System.out.println("查找的位置不合法,返回值无效!");
            e.printStackTrace();
        }
        return -1;
    }

    private boolean isEmpty() {
        if(this.usedSize == 0) {
            return true;
        }else {
            return false;
        }
    }
    // 给 pos 位置的元素设为【更新为】 value
    public void set(int pos, int value) {
        if(isEmpty()) {
            System.out.println("表为空!");
            return;
        }else {
            try {
                checkPosInAdd(pos);
                this.elem[pos] = value;
            }catch (PosIllegalException e) {
                System.out.println("位置不合法!");
                e.printStackTrace();
            }
        }
    }

    /**
     * 删除第一次出现的关键字key
     * @param key
     */
    public void remove(int key) {
        if(isEmpty()) {
            System.out.println("表为空");
        }
        for(int i = 0; i < this.usedSize; i++) {
            if(this.elem[i] == key) {
                for(int j = i; j < this.usedSize - 1; j++) {
                    this.elem[j] = this.elem[j + 1];
                }
                this.usedSize--;
                return;
            }
        }
        System.out.println("没有找到关键字!");
        return;
    }

    // 获取顺序表长度
    public int size() {
        return this.usedSize;
    }

    // 清空顺序表
    public void clear() {
        this.usedSize = 0;
    }
}
public class PosIllegalException extends RuntimeException {
    public PosIllegalException() {

    }

    public PosIllegalException(String mes) {
        super(mes);
    }
}

ArrayList的相关练习

给定一个非负整数 numRows 生成「杨辉三角」的前 numRows 行。

class Solution {
    public List<List<Integer>> generate(int numRows) {
        //补充代码
    }
}

杨辉三角大家应该不陌生,如下:

1
1 1
1 2 1
1 3 3 1
… …

题目最大的特点是返回值类型:List<List<Integer>>,即返回一个实现了List接口的集合,其每一个元素也是这个集合的类型,这意味着集合中的每个元素代表杨辉三角的一行,每个元素又是一个集合,这个集合的每个元素是杨辉三角每一行的每个元素。我们刚刚学习了ArrayList,所以我们会使用ArrayList完成。

杨辉三角的第一行一定是一个1,每一行的第一个和最后一个元素一定是1,基于这一点,我们直接实现:

class Solution {
    public List<List<Integer>> generate(int numRows) {
        ArrayList<List<Integer>> list = new ArrayList<>(numRows);
        //第一行的1
        ArrayList<Integer> l1 = new ArrayList<>();
        l1.add(1);
        list.add(l1);
        //后续行
        for(int i = 1; i < numRows; i++) {
            ArrayList<Integer> lTmp = new ArrayList<>();
            lTmp.add(1);//第一个元素一定是1
            for(int j = 1; j < i; j++) {
                lTmp.add(list.get(i - 1).get(j - 1) + list.get(i - 1).get(j));
            }//每一行的中间元素
            lTmp.add(1);//最后一个元素一定是1
            list.add(lTmp);
        }
        return list;
    }
}

可能会出现以下报错(也是裤儿出现的问题):

Line 16: error: incompatible types: ArrayList<ArrayList<Integer>> cannot be converted to List<List<Integer>> return list;

因为:

ArrayList<ArrayList>ArrayList<List>之间的类型不兼容,不能直接进行互相转换。

在Java泛型中,类型擦除会导致泛型类型的具体信息在编译时被擦除,因此在运行时,泛型类型的实例并不知道它们的类型参数的具体类型。这意味着,尽管ArrayListList的子类,但在泛型类型中,它们被视为不同的类型。

原题链接:118. 杨辉三角 - 力扣(LeetCode)


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

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

相关文章

Three.JS飞入定位模型的位置。

源码 flyTo(object, gltfthis) {if (object undefined || object null) {return;}const box3 new THREE.Box3();box3.expandByObject(object); // 计算模型包围盒const size new THREE.Vector3();box3.getSize(size); // 计算包围盒尺寸const center new THREE.Vector3();…

【stm32项目】基于stm32智能宠物喂养(完整工程资料源码)

基于STM32宠物喂养系统 前言&#xff1a; 随着人们生活幸福指数的提高&#xff0c;越来越多的家庭选择养宠物来为生活增添乐趣。然而&#xff0c;由于工作等原因&#xff0c;许多主人无法及时为宠物提供充足的食物与水。为了解决这一问题&#xff0c;我设计了一款便捷的宠物喂…

如何搭建一个RADIUS服务器?

1. 系统环境 1.1.操作系统 Ubuntu-20.04.1 &#xff08;kernel: 5.15.0-58-generic&#xff09; 1.2.所需软件 FreeRADIUS MariaDB 1.3.注意事项 本文提到的所有操作&#xff0c;都是以root 身份执行&#xff1b; 2. FreeRADIUS的安装 2.1. 安装FreeRADIUS服务器程序 以…

fMATLAB中fill函数填充不同区域

只需获取填充区域的边缘信息&#xff0c;函数边缘越详细越好&#xff0c;然后调用fill函数。 fill函数能够根据指定的顶点坐标和填充颜色来绘制多边形或曲线形状&#xff0c;并在其内部填充指定的颜色。这使得在MATLAB中创建具有视觉吸引力的图形变得简单而高效。 fill函数的…

TCP滑动窗口和流量控制详解

1. 什么是滑动窗口 TCP 每发送⼀个数据&#xff0c;都需要⼀次应答&#xff0c;然后继续发送&#xff0c;这样为每个数据包都进⾏确认应答&#xff0c;缺点是&#xff1a;数据往返时间越⻓&#xff0c;⽹络吞吐量越低。为了解决这个问题&#xff0c;TCP 引⼊了 窗⼝ 这个概念。…

MISRA C2012学习笔记(7)-Rules 8.12

文章目录 8.12 表达式(Expressions)Rule 12.1 表达式中运算符的优先级应明确Rule 12.2 移位运算符的右操作数应在零到比左操作数基本类型的位宽度小一的范围内Rule 12.3 不得使用逗号(,)运算符Rule 12.4 常量表达式的求值不应导致无符号整数的回绕 8.12 表达式(Expressions) R…

Netty技术全解析:EventLoopGroup类详解

❃博主首页 &#xff1a; 「码到三十五」 &#xff0c;同名公众号 :「码到三十五」&#xff0c;wx号 : 「liwu0213」 ☠博主专栏 &#xff1a; <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关> ♝博主的话 &#xff1a…

VBA技术资料MF174:利用文本框和列表框录入数据

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

Ubuntu网络连接图标消失了,没网!!!

文章目录 前言Step1&#xff1a;停止网络管理服务Step2&#xff1a;删除网络管理状态文件Step3&#xff1a;打开网络管理 前言 本次记录的事&#xff0c;有一天心血来潮想烧录一下开发板&#xff0c;却发现自己的Ubuntu系统的网络连接图标消失了&#xff0c;也没网了&#xff…

DEBUG:inpyb无法引用本地的py文件

问题 无法import 解决 暂时合并为一个文件 直接执行且测试简单模块可以引用&#xff08;部分复杂文件无法引用&#xff09;结合本程序 应该需要修改不规则的正则表达式 发现部分警告导致程序无法引用&#xff08;而且和环境有关 linux不会&#xff09;

医联体信息平台建设方案PPT(54页)

文章摘要&#xff1a; 医联体信息平台现状当前医联体信息平台存在脱离医疗业务建设的倾向&#xff0c;导致信息孤岛&#xff0c;业务协同困难。 建设存在的问题主要问题包括健康档案无法动态更新和共享&#xff0c;信息系统之间信息共享和协同不足。 医联体信息平台建设方案方…

【Linux】进程间通信及管道详细介绍(上)

前言 本节我们开始学习进程间通信相关的知识&#xff0c;并详细探讨一下管道&#xff0c;学习匿名管道和命名管道的原理和代码实现等相关操作… 目录 1. 进程间通信背景1.1 进程通信的目的&#xff1a; 2 管道的引入&#xff1a;2.1 匿名管道&#xff1a;2.1.1 匿名管道的原理&…

LATEX模板支持中文、目录和段落

\documentclass{ctexart} \usepackage{amsmath,amssymb,amsfonts,hyperref} \usepackage{CJKutf8} \usepackage{enumitem} % 引入宏包 \usepackage [colorlinkstrue] {} \begin{document}\begin{CJK}{UTF8}{gkai}%正文放在此行下与\end{CJK}之间就行\tableofcontents\newpage\s…

【Python】从基础到进阶(四):深入了解Python中的控制流

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、引言二、条件语句1. if 语句2. if-else 语句3. if-elif-else 语句4. 嵌套条件语句5. 三元运算符 三、循环语句1. for 循环基本语法使用range() 函数遍历列表、字典和字符串 2. while 循环基本语法无限循环与终止条件 3.…

Python 实现股票指标计算——BBI

BBI (Bull And Bear lndex) - 多空指标 1 公式 3日均价 3日收盘价之和 / 36日均价 6日收盘价之和 / 612日均价 12日收盘价之和 / 1224日均价 24日收盘价之和 / 24BBI (3日均价 6日均价 12日均价 24日均价) / 4 2 数据准备 我们以科创50指数 000688 为例&#xff0c…

使用Vue实现点击页面触发特效

效果描述 在页面上的指定区域内进行点击&#xff0c;则会在页面上显示设置好的随机文本&#xff0c;此文本出现后会执行动画&#xff0c;动画效果为节点在1s之内向右上方移动并在移动的过程中完成180翻转&#xff0c;最后消失。 效果展示 完整代码 <template><div…

Windows 11 Visual Studio 2022 cmake 3.29 CUDA12.5 构建VTK

The Visualization Toolkit (VTK)是一个用于操作和展示科学数据的开源软件&#xff0c;包括了二三维渲染功能。 下载VTK 从官网Download | VTK下载VTK版本&#xff0c;我下载的是9.3.1源代码&#xff0c;在Windows 11上安装。 CMake构建VTK的VS2022工程 生成与安装 分别生成De…

AI智能名片小程序:跨界融合,重塑品牌与顾客的“三度情缘”

在这个信息爆炸、竞争白热化的时代&#xff0c;品牌如何突破重围&#xff0c;与顾客建立超越常规的情感链接&#xff1f;答案或许就藏在那个看似不起眼&#xff0c;实则暗藏玄机的AI智能名片小程序里&#xff01;它不仅是技术的结晶&#xff0c;更是品牌与顾客之间“三度情缘”…

Redis持久化(AOF和RDB)

目录 前言 一.RDB 1.1手动执行 1.2自动执行 二.AOF 2.1重写机制 三.混合持久化 Redis的学习专栏&#xff1a;http://t.csdnimg.cn/a8cvV 前言 持久化&#xff0c;在之前&#xff0c;我们接触这个词汇是在mysql数据库当中的事务四大特性里。 持久性&#xff1a;指一旦事…

探索免费隧道服务:为本地开发提供自定义子域名的解决方案

目录 引言 使用Ngrok进行本地开发 免费替代方案 Localtunnel Serveo Ngrok付费计划&#xff08;有限的免费试用&#xff09; 开源替代方案 SISH 总结 引言 在Web开发中&#xff0c;将本地服务器暴露给互联网进行测试或演示是常见需求。Ngrok等工具因其便捷性而广受欢迎…