【数据结构】_3.List接口实现类ArrayList与线性表

news2024/11/25 0:49:33

目录

1.List接口

1.1 List接口的集合关系网络

1.2 List的使用

2. ArrayList与顺序表

2.1 线性表

2.2 顺序表

2.3 ArrayList

2.3.1 ArrayList的集合关系网络

2.3.2  ArrayList的使用

2.3.2.1 ArrayList的构造方法

2.3.2.2 ArrayList的扩容机制逻辑示图如下:

2.3.2.3 常用方法

2.3.2.4 ArrayList的遍历

2.3.3 ArrayList的具体使用

2.3.3.1 字符串处理问题

2.3.3.2 杨辉三角

2.3.3.3 简单的洗牌算法

 2.3.4 ArrayList特点


1.List接口

1.1 List接口的集合关系网络

在集合中,List是一个接口,继承自Collection,Collection也是一个接口;

在数据结构中,List是一个线性表,即n个具有想同类型元素的有限序列,在该序列上可以执行增删查改等操作;

1.2 List的使用

List是一个接口,并不能直接用来实例化,如果要使用就必须实例化List的实现类,在集合框架中,ArrayList和LinkedList都实现了List接口;

接下来将依次展示List的实现类使用方法,本篇为ArrayList;

2. ArrayList与顺序表

2.1 线性表

线性表是n个具有相同特性的数据元素的有限序列,线性表是一种在实际中广泛使用的数据结构,常见的线性表有:顺序表、链表、栈、队列等等;

线性表在逻辑上是线性结构,即连续的一条直线,但在物理结构上不一定连续。

线性表在物理存储时通常以数组和链式的形式存储;

2.2 顺序表

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储,在数组上完成数据的增删查改;

下面展示顺序表常用接口的模拟实现:

(1)包类示图:

 (2)MyArrayList:

package TestMyArrayList;
import java.util.Arrays;
public class MyArrayList {
    public int[] elem;
    public int useSize;     // 记录顺序表存储的有效数据个数
    public static final int DEFAULT_SIZE=10;

    public MyArrayList(){
        this.elem = new int[DEFAULT_SIZE];
    }
    // 成员方法1:打印顺序表
    public void display(){
        for(int i=0;i<this.useSize;i++){
            System.out.print(this.elem[i]+" ");
        }
    }
    // 成员方法2:获取顺序表长度
    public int size(){
        return this.useSize;
    }
    // 成员方法3:判定是否包含某个元素
    public boolean contains(int toFind){
        for(int i=0;i<this.useSize;i++){
            if(elem[i]==toFind){
                return true;
            }
        }
        return false;
    }
    // 成员方法4:查找某个元素对应的位置
    public int indexOf(int toFind){
        for(int i=0;i<this.useSize;i++){
            if(elem[i]==toFind){
                return i;
            }
        }
        return -1;   // 数组没有负数下标
    }
    // 成员方法5:新增元素(默认放在数组最后位置)
    public void add(int data){
        // 判满
        if(this.isFull()){
            //扩容
            this.resize();
        }
        elem[this.useSize]=data;
        this.useSize++;
    }
    // 成员方法6:判满
    public boolean isFull(){
        // 写法1:
//        if(this.useSize==this.elem.length){
//            return true;
//        }
//        return false;
        // 写法2:
        return this.useSize==this.elem.length;
    }
    // 成员方法7:扩容
    private void resize(){ // 扩容只针对当前顺序表,可以进行封装
       this.elem= Arrays.copyOf(this.elem,2*this.elem.length);
    }
    // 成员方法8:在pos位置新增元素
    public void add(int pos, int data){
        // 判pos是否合法
        checkAddIndex(pos);
        // 判满
        if(isFull()){
            this.resize();
        }

        for(int i=useSize-1;i>=pos;i--){
            elem[i+1]=elem[i];
        }
        this.elem[pos]=data;
        this.useSize++;
    }
    // 成员方法9:判插入数据时,pos是否合法
    private void checkAddIndex(int pos){
        if(pos<0||pos>this.useSize){
            throw new AddIndexOutOfException("pos is illegal!");
        }

    }
    // 成员方法10:获取pos位置的元素
    public int get(int pos){
        checkAddIndex(pos);
        return this.elem[pos];
    }
    // 成员方法11:判获取数据时,pos是否合法
    private void checkGetIndex(int pos){
        if(pos<0||pos>=this.useSize){
            throw new AddIndexOutOfException("pos is illegal!");
        }
    }
    // 成员方法12:将pos位置的数据设置为value
    public void set(int pos, int value){
        checkGetIndex(pos);
        this.elem[pos]=value;
    }
    // 成员方法13:删除第一次出现的关键字key
    public boolean remove(int toRemove){
        int index=indexOf(toRemove);
        if(index==-1){
            System.out.println("data is non existent!");
            return false;
        }
        for(int i=index;i<this.useSize-1;i++){
            // useSize-1可保证不越界
            elem[i]=elem[i+1];
        }
        this.useSize--;
        this.elem[this.useSize]=0; // 若是引用类型则置为null
        return true;
    }
    // 成员方法14:清空顺序表
    public void clear(){
        for(int i=0;i<this.useSize;i++){
            this.elem[i]=0;
        }
        this.useSize=0;
    }
}

(3)GetIndexOutOfException

package TestMyArrayList;

public class GetIndexOutOfException extends RuntimeException{
    public GetIndexOutOfException(){

    }
    public GetIndexOutOfException(String message){
        super(message);
    }
}

(4)AddIndexOutOfException

package TestMyArrayList;

public class AddIndexOutOfException extends RuntimeException{
    public AddIndexOutOfException(){

    }
    public AddIndexOutOfException(String message){
        super(message);
    }
}

2.3 ArrayList

2.3.1 ArrayList的集合关系网络

说明:

(1)ArrayList是以泛型方式实现的,使用时必须实例化;

(2)ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问;

(3)ArrayList实现了Clone接口,表明ArrayList是可以clone的;

(4)ArrayList实现了Serializable接口,表明ArrayList是支持序列化的;

(对象->字符串:序列化;字符串->对象:反序列化)

(5)相比于Vector,ArrayList不是线程安全的,在单线程下可使用,在多线程中可以选择Vector或者CopyOnWriteArrayList;

(6)ArrayList底层是一段连续空间,并且可以动态扩容,是一个动态类型的顺序表;

2.3.2  ArrayList的使用

2.3.2.1 ArrayList的构造方法

ArrayList的构造方法有以下三种:

示例代码如下:

(1)构造方法1:(无参构造器)

        // 构造方法1:
        ArrayList<Integer> arrayList1 = new ArrayList<>();
        arrayList1.add(97);
        arrayList1.add(8);
        arrayList1.add(5);
        System.out.println(arrayList1);

输出结果为:

(2)构造方法2:(带有初始容量的构造方法)

        // 构造方法2:
        ArrayList<Integer> arrayList2 = new ArrayList<>(20);
        arrayList2.add(1997);
        arrayList2.add(85);
        arrayList2.add(25);
        System.out.println(arrayList2);

 输出结果为:

(3)构造方法3:

        // 构造方法3:
        LinkedList<Integer> list = new LinkedList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        ArrayList<Integer> arrayList3 = new ArrayList<>(list);
        ArrayList<Number> arrayList4 = new ArrayList<>(list);
        System.out.println(arrayList3);
        System.out.println(arrayList4);

输出结果为:

第三种构造方法的含义为:将另外一个实现了Collection接口的具体类作为构造ArrayList的具体参数,

且满足:该具体类的泛型参数是ArrayList实例化对象的泛型参数本身或其子类,

即可将该类中的所有元素添加至ArrayList实例化的该对象中来;

2.3.2.2 ArrayList的扩容机制逻辑示图如下:

简而言之:

在实例化ArrayList对象进行new操作时,其实并没有为该对象分配内存,但在第一次进行add时,会调用grow方法为其分配长度为10的内存大小;

且扩容方式为1.5倍扩容法;

2.3.2.3 常用方法

方法解释
boolean add(E e)

尾插e

void add(int index,E element)将e尾插到index位置
boolean addAll(Collection<? extends E>c)尾插c中的元素
E remove(int index)删除index位置元素
boolean remove(Object o)删除遇到的第一个o
E get(int index)获取下标index位置元素
E set(int index,E element)将下标index位置元素设置为element
void clear()清空
boolean contains(Object o)判断o是否在线性表中
int indexOf(Object o)返回第一个o所在下标
int lastIndexOf(Object o)返回最后一个o的下标
List<E> subList(int fromIndex,int toIndex)截取部分list

方法示例:

(1)E remove(int index) 与 boolean remove(Object o):

        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(2);
        arrayList.add(3);
        System.out.println(arrayList);
        arrayList.add(0,1);
        System.out.println(arrayList);
        arrayList.remove(2);
        System.out.println(arrayList);
        arrayList.remove(new Integer(1));
        System.out.println(arrayList);

输出结果为:

 (2)List<E> subList(int fromIndex,int toIndex):(注意接收类型为List而非ArrayList

        ArrayList<Integer> arrayList1 = new ArrayList<>();
        for(int i=0;i<10;i++){
            arrayList1.add(i*2+1);
        }
        System.out.println(arrayList1);
        List<Integer> arrayList2 = arrayList1.subList(3,6);
        System.out.println(arrayList2);

输出结果为:

注:原ArrayList对象arrayList1和截取的子串arrayList2共用一个elemData数组,修改元素时二者相互影响

        ArrayList<Integer> arrayList1 = new ArrayList<>();
        for(int i=0;i<10;i++){
            arrayList1.add(i*2+1);
        }
        System.out.println("Before modify: ");
        System.out.println("arrayList1: "+arrayList1);
        List<Integer> arrayList2 = arrayList1.subList(3,6);
        System.out.println("arrayList2: "+arrayList2);
        arrayList2.set(0,999);
        System.out.println("After modify: ");
        System.out.println("arrayList1: "+arrayList1);
        System.out.println("arrayList2: "+arrayList2);

输出结果为:

2.3.2.4 ArrayList的遍历

方法1:直接输出:

ArrayList类并没有重写toString方法,其父类AbstractList也没有重写toString方法,但是List接口有toString方法,故而可以直接使用System.out.println()方法输出ArrayList对象;

上文代码已有示例,此处不再赘述;

方法2:for循环:

        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(1997);
        arrayList.add(8);
        arrayList.add(5);
        arrayList.add(25);
        for(int i=0;i<arrayList.size();i++){
            System.out.print(arrayList.get(i)+"  ");
        }

输出结果为:

  

方法:3:for-each:

        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(1997);
        arrayList.add(8);
        arrayList.add(5);
        arrayList.add(25);
        for(Integer x:arrayList){
            System.out.print(x+"  ");
        }

输出结果为:

  

方法4:迭代器:

迭代器方法源码如下:

试运行以下代码:

        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(1997);
        arrayList.add(8);
        arrayList.add(5);
        arrayList.add(25);
        ListIterator<Integer> it = arrayList.listIterator();
        while(it.hasNext()){
            System.out.print(it.next()+"  ");
            // 打印it的同时令it前行一步
        }

输出结果为:

2.3.3 ArrayList的具体使用

2.3.3.1 字符串处理问题

题目描述:现有字符串s1:"Welcome to java"和字符串s2:"come",试将s1中包含的s2的字符删去后的结果;

思路:遍历字符串s1,当s2不包含s1当前的字符则添加至一个ArrayList对象中,输出该对象结果即可;

代码如下:

    public static void main(String[] args) {
        List<Character> list = new ArrayList<>();
        String s1 = "Welcome to java";
        String s2 = "come";
        for(int i=0;i<s1.length();i++){
            char ch = s1.charAt(i);
            if(!s2.contains(ch+"")){
                // 字符串的包含操作参数为CharSequence,String类也实现了CharSequence接口
                // 故而需要将获取到的s1中的字符处理为字符串
                list.add(ch);
            }
        }
        for(Character x:list){
            System.out.print(x);
        }
    }

输出结果为:

2.3.3.2 杨辉三角

题目描述:

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

代码如下:

class Solution {
    public List<List<Integer>> generate(int numRows) {
        //List嵌套List即二维数组
        List<List<Integer>> ret = new ArrayList<>();
        List<Integer> row = new ArrayList<>();
        row.add(1);   // 初始化第一行(只有一个元素,为1)
        ret.add(row); // 创建二维数组
        for(int i=1;i<numRows;i++){
            List<Integer> previousRow = ret.get(i-1);  //获取上一行元素
            List<Integer> currentRow = new ArrayList<>();
            currentRow.add(1);  // 每一行第一个元素为1
            // 每一行非两端位置元素赋值
            for(int j=1;j<i;j++){
                int x = previousRow.get(j)+previousRow.get(j-1);
                currentRow.add(x);
            }
            currentRow.add(1);  // 每一行最后一个元素也为1
            ret.add(currentRow);
        }
        return ret;
    }
}

 通过用例测试,参考输出示例如下:

2.3.3.3 简单的洗牌算法

(1)创建包类关系如下:

(2)Poker类:

package TestDemo1;
public class Poker {
    private String suit; // 花色
    private int rank;    //数字

    public Poker(String suit, int rank) {
        this.suit = suit;
        this.rank = rank;
    }

    public String getSuit() {
        return suit;
    }

    public void setSuit(String suit) {
        this.suit = suit;
    }

    public int getRank() {
        return rank;
    }

    public void setRank(int rank) {
        this.rank = rank;
    }

    @Override
    public String toString() {
        return "{" + suit+" "+ rank+ "}";
    }
}

(3) Game类:

package TestDemo1;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Game {
    private static final String[] suits = {"♥","♣","♦","♠"};
    public List<Poker> buyPoker(){
        List<Poker> pokers = new ArrayList<>();

        for(int i=0;i<4;i++){
            for(int j=1;j<=13;j++){
                String suit = suits[i]; // 花色
                int rank = j;    // 数字
                Poker poker = new Poker(suit,j);
                pokers.add(poker);
            }
        }
        return pokers;
    }
    // 洗牌
    public void shuffle(List<Poker> pokers){
        for(int i=pokers.size()-1; i>0;i--){
            Random random = new Random();
            int index = random.nextInt(i);
            Swap(pokers,i,index);
        }

    }
    private void Swap(List<Poker> pokers,int i,int j){
        Poker tmp = pokers.get(i);
        pokers.set(i,pokers.get(j));
        pokers.set(j,tmp);
    }
    // 揭牌:三个人轮流揭5张牌
    // 每次删除pokers的0下标的元素,并依次添加至3个ArrayList对象中
    public List<List<Poker>> game(List<Poker> pokers){
        // 创建玩家List
        List<List<Poker>> players = new ArrayList<>();
        List<Poker> player1 = new ArrayList<>();
        List<Poker> player2 = new ArrayList<>();
        List<Poker> player3 = new ArrayList<>();
        players.add(player1);
        players.add(player2);
        players.add(player3);
        for(int i=0;i<5;i++){   // 控制揭牌揭5轮
            for(int j=0;j<3;j++){    // 控制每个玩家每次揭牌揭一张
                Poker currentPoker = pokers.remove(0);
                // ArrayList的remove方法会将查找下标对应的元素返回
                players.get(j).add(currentPoker);
            }
        }
        return players;
    }
}

(4)Test类:

package TestDemo1;
import java.util.List;
public class Test {
    public static void main(String[] args) {
        Game game = new Game();
        List<Poker> pokers = game.buyPoker();
        int count=1;
        for(Poker x:pokers){
            System.out.print(x+"  ");
            count++;
            if(count%10==0){
                System.out.println();
            }
        }
        game.shuffle(pokers);
        System.out.println();
        System.out.println("------------------------------------------------------------------");
        System.out.println("洗牌:");
        count=1;
        for(Poker x:pokers){
            System.out.print(x+" ");
            count++;
            if(count%10==0){
                System.out.println();
            }
        }
        System.out.println();
        System.out.println("------------------------------------------------------------------");
        System.out.println("揭牌:");
        List<List<Poker>> players = game.game(pokers);
        for(int i=0;i<players.size();i++){
            System.out.println("第"+(i+1)+"位玩家牌面:");
            System.out.println(players.get(i));
        }
        System.out.println("------------------------------------------------------------------");
        System.out.println("余牌牌面:");
        count=1;
        for(Poker x:pokers){
            System.out.print(x+" ");
            count++;
            if(count%10==0){
                System.out.println();
            }
        }
    }
}

 (5)输出结果为:

 注:ArrayList类的remove方法源码:

可见其逻辑为:删除哪个下标的值,就将该下标的元素作为返回值进行返回;

 2.3.4 ArrayList特点

优点:(1)当给定下标时,ArrayList的查找速度非常快。故而ArrayList适合给定下标的查找,复杂度为O(1);

缺点:(1)任意位置插入或删除元素时,需要大量挪动元素,故而ArrayList不适合应用于任意位置插入和删除较为频繁的场景;

(2)每次扩容时也面临着资源浪费的问题,同时申请新空间,拷贝数据再释放旧空间也有不小的消耗;

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

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

相关文章

企业如何通过CRM提高客户转化?

现如今&#xff0c;企业想要给潜在客户留下深刻的印象&#xff0c;那么就需要一系列的措施和手段。通过CRM管理系统让潜在客户信任企业&#xff0c;更好地进行客户培育&#xff0c;从而提高潜在客户转化。下面来说说&#xff0c;企业提高潜在客户转化的7个做法。 1、永远不要让…

input模糊搜索

input模糊搜索 getList() {let dicthis.queryParameters()let val this.queryParams["userName"]if (null ! val && ! val) {dic["userName"]*val*;}listPamsArchiveSearch(dic).then(response > {this.nameinfo response.data;});},主要问…

Spring Batch之读数据库——JdbcCursorItemReader之使用框架提供的BeanPropertyRowMapper(三十六)

一、BeanPropertyRowMapper介绍 参考我的另一篇博客&#xff1a; Spring Batch之读数据库——JdbcCursorItemReader&#xff08;三十五&#xff09;_人……杰的博客-CSDN博客 二、项目实例 1.项目框架 2.代码实现 BatchMain.java: package com.xj.demo27;import org.spri…

Echarts环形饼状图设置内外边框

上班快一个月了&#xff0c;最近再写echarts的项目&#xff0c;亚历山大啊 记录一下饼状图设置内外边框的代码 series: [{name: 项目分数,type: pie,radius: [50%, 70%],avoidLabelOverlap: false,labelLine: {show: true},data: [{value: 335, name: 970分以上},{value: 310…

python用playwright自动化测试程序打包exe

playwright自动化测试代码写好后&#xff0c;打包为exe运行在目标PC上可能出现错误。 原因&#xff1a; 1、运行的PC没有响应的浏览器。 2、playwright没有打包到代码中。 所以本例用AutoPytoExe为例来制作exe程序解决问题。 1、安装&#xff1a; 2、安装完成之后&#xff0c;…

CUDA并行归约算法(二)

CUDA并行归约算法&#xff08;二&#xff09; 文章目录 CUDA并行归约算法&#xff08;二&#xff09;前情回顾线程束分化内存组织Reference>>>>> 欢迎关注公众号【三戒纪元】 <<<<< 前情回顾 首先看下上节设计的核函数&#xff0c;如何进行并行…

基于FPGA的视频接口之HDMI1.4(以下)编码

简介 为什么要特别说明HDMI的版本,是因为HDMI的版本众多,代表的HDMI速度同样不同,当前版本在HDMI2.1速度达到48Gbps,可以传输4K及以上图像,但我们当前还停留在1080P@60部分,且使用的芯片和硬件结构有很大差别,故将HDMI分为两个部分说明1080@60以下分辨率和4K以上分辨率(…

docker运行redis容器

参考文章 Redis从入门到精通&#xff08;4&#xff09;&#xff1a;docker运行redis容器详解 问题及总结 docker 命令 拉取镜像&#xff1a;docker pull redis 或者 docker pull redis:bullseye&#xff1b;查看镜像&#xff1a;docker image ls&#xff1b;直接运行 redis…

Flask SQLAlchemy_Serializer ORM模型序列化

在前后端分离项目中&#xff0c;经常需要把ORM模型转化为字典&#xff0c;再将字典转化为JSON格式的字符串。在遇到sqlalchemy_serializer之前&#xff0c;我都是通过类似Java中的反射原理&#xff0c;获取当前ORM模型的所有字段&#xff0c;然后写一个to_dict方法来将字段以及…

Golang假共享(false sharing)详解

多核处理器(SMP)系统中, 每一个处理器都有一个本地高速缓存。内存系统必须保证高速缓存的一致性。当不同处理器上的线程修改驻留再同一高速缓存中的变量时就会发生假共享(false sharing),结果导致高速缓存无效,并强制更新,进而影响系统性能。 什么是假共享(false sharin…

论文解读|VoxelNet:基于点云的3D物体检测的端到端学习

原创 | 文 BFT机器人 01 摘要 论文提出了表述了一个新的基于点云的3D检测方法&#xff0c;名为VoxelNet&#xff0c;该方法是一个端到端可训练的深度学习架构&#xff0c;利用了稀疏点云的结构特性&#xff0c;直接在稀疏的3D点上进行操作&#xff0c;并通过高效的并行处理体素…

Stable Diffusion - ChatGPT4 与 Stable Diffusion 结合提供无限创意构图

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/131782672 ChatGPT 和 StableDiffusion 结合使用的优势&#xff1a; 高效率&#xff1a;ChatGPT 可以在很短的时间内完成复杂的语言任务&#xf…

Kotlin基础(六) 枚举类和扩展

前言 本文主要讲解kotlin枚举类和扩展 Kotlin文章列表 Kotlin文章列表: 点击此处跳转查看 目录 1.1 枚举类 1.1.1 枚举类的基本用法 Kotlin中的枚举类&#xff08;enum class&#xff09;用于定义一组具有预定义值的常量。它们在许多情况下都很有用&#xff0c;例如表示一组…

介绍性能压力测试的重要性

在当今数字化时代&#xff0c;软件和应用程序的性能对于用户体验和业务成功至关重要。为了确保系统在面临高负载和压力时能够正常运行&#xff0c;性能压力测试成为一项不可或缺的活动。本文将介绍性能压力测试的重要性。 性能压力测试是一种通过模拟实际场景中的负荷和用户访问…

Echarts中饼状图,图例显示value而不是name

直接上代码 formatter(name) {var tarValue;for (var i 0; i < data.length; i) {if (data[i].name name) {tarValue data[i].value;}}var v tarValue;return [tarValue]} 效果图

spring boot 多模块项目搭建Knife4j文档,swagger-ui x2

介绍: knife4j jeecg-boot用的就是这个&#xff0c;我之前要搭过swagger-ui&#xff0c;但外观&#xff0c;体验都没有knife4j好&#xff0c;我没记错的话已经停止发布版本了&#xff0c;所以我的多模块项目就用到了这个&#xff0c;还搭建了jwt token获取我也是在网上找的…

260道2023最新网络安全工程师面试题(附答案)

2023年过去了一大半&#xff0c;先来灵魂三连问&#xff0c;年初定的目标完成多少了&#xff1f;薪资涨了吗&#xff1f;女朋友找到了吗&#xff1f; ​好了&#xff0c;不扎大家的心了&#xff0c;接下来进入正文。 由于我之前写了不少网络安全技术相关的文章和回答&#xff…

pdf文件如何生成长图?分享两个免费的方法给大家!

在某些情况下&#xff0c;我们可能需要将长图转换为PDF文件&#xff0c;以便更方便地分享和存档。本文将介绍两种免费的方法&#xff0c;帮助您实现这一目标。方法一是使用记灵在线工具的PDF转长图功能&#xff0c;方法二是利用PDF24工具进行转换。让我们一起来了解具体操作步骤…

blender 叶片制作

圆润叶片 效果展示 shift a 新建矩形&#xff0c;s y 延 y 轴方向压扁&#xff0c;ctrl r 循环切割&#xff0c;滚动滚轮&#xff0c;延 y 轴方向切两条循环线&#xff0c;框选点&#xff0c;s 缩放&#xff0c;调整到叶片造型&#xff0c;添加细分修改器&#xff1b;给叶片…

构建数据中台的三要素:方法论、组织和技术

知道要转型&#xff0c;要建设数据中台&#xff0c;却不知咋做&#xff0c;咋办&#xff1f; 现在有很多讲“如何建设数据中台”文章&#xff0c;观点各不相同&#xff1a; 数据中台是数据建设方法论&#xff0c;按照数据中台设计方法和规范实施就可建成数据中台数据中台背后…