java顺序表——ArrayList详解

news2024/10/5 22:37:58

1.顺序表的概念

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

2.自己实现一个顺序表——MyArrayList

2.1 顺序表成员变量的定义

public class MyArrayList {

    public static int FEFAULT_MAX_SIZE = 10;//数组最大容量
    public int[] elem;//第一一个数组,用于存储数据
    public int useSize;//记录存储了多少数据
    }

2.2 顺序表成员方法的简单定义

// 新增元素,默认在数组最后新增
public void add(int data) { }
// 在 pos 位置新增元素
public void add(int pos, int data) { }
// 判定是否包含某个元素
public boolean contains(int toFind) { return true; }
// 查找某个元素对应的位置
public int indexOf(int toFind) { return -1; }
// 获取 pos 位置的元素
public int get(int pos) { return -1; }
// 给 pos 位置的元素设为 value
public void set(int pos, int value) { }
//删除第一次出现的关键字key
public void remove(int toRemove) { }
// 获取顺序表长度
public int size() { return 0; }
// 清空顺序表
public void clear() { }
// 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
public void display() { }
}

2.3.顺序表的完整定义(实现)

import java.util.Arrays;

public class MyArrayList {

    public static int FEFAULT_MAX_SIZE = 10;//数组最大容量
    public int[] elem;//第一一个数组,用于存储数据
    public int useSize;//记录存储了多少数据

    //初始化(构造方法)
    public MyArrayList() {
        this.elem = new int[FEFAULT_MAX_SIZE];//开辟存储空间
        this.useSize = 0;//一开始没有存数据,所以usesize为0
    }

    //该数据结构所需要的所有的方法

    // 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
    public void display() {
        for (int i = 0; i < this.useSize; i++) {
            System.out.print(this.elem[i] + " ");
        }
        System.out.println();
    }

    //判满
    public boolean isFull() {
        if (this.useSize == FEFAULT_MAX_SIZE) {
            return true;
        } else
            return false;
    }

    //扩容
    public void addDfaultSize() {
        this.elem = Arrays.copyOf(elem, FEFAULT_MAX_SIZE * 2);
        FEFAULT_MAX_SIZE = FEFAULT_MAX_SIZE * 2;
    }


    //检查位置合法性
    public void checkAddIsValid(int pos){
        if (pos < 0 || pos > useSize + 1 ) {
            throw  new AddIndexOutException("Addd的pos值非法!");
        }
    }

    // 新增元素,默认在数组最后新增
    public void add(int data) {
        //如果满了就扩容
        if (this.isFull()) {
            this.addDfaultSize();
        }

        this.elem[useSize] = data;
        this.useSize++;
    }

    // 在 pos 位置新增元素
    public void add(int pos, int data) {
        //判断插入位置的合法性
        try{
            checkAddIsValid(pos);
            //插入
            for (int i = useSize; i > pos ; i--) {
                this.elem[i] = this.elem[i-1];
            }
            useSize++;
        }catch (AddIndexOutException addIndexOutException){
            addIndexOutException.printStackTrace();
        }

    }

    // 判定是否包含某个元素
    public boolean contains(int toFind) {
        for (int i = 0; i < useSize; i++) {
            if (this.elem[i] == toFind) {
                return true;
            }
        }
        return false;
    }

    // 查找某个元素对应的位置
    public int indexOf(int toFind) {
        for (int i = 0; i < useSize; i++) {
            if (this.elem[i] == toFind) {
                return i;
            }
        }
        return -1;//数组么有-1下标
    }

    //检查Get位置合法性
    public void checkGetIsValid(int pos){
        if (pos < 0 || pos > useSize  ) {
            throw  new GetIndexOutException("Get的pos值非法!");
        }
    }

    // 获取 pos 位置的元素
    public int get(int pos) {
        try{
            checkGetIsValid(pos);

        }catch (GetIndexOutException getIndexOutException){
            getIndexOutException.printStackTrace();
        }
        return this.elem[pos];
    }

    // 给 pos 位置的元素设为 value
    public void set(int pos, int value) {
        try{
            checkGetIsValid(pos);
            this.elem[pos] = value;
        }catch (GetIndexOutException getIndexOutException){
            getIndexOutException.printStackTrace();
        }

    }

    //删除第一次出现的关键字key
    public void remove(int toRemove) {
        for (int i = 0; i < useSize; i++) {
            if (this.elem[i] == toRemove) {
                for (int j = i; j < useSize - 1; j++) {
                    this.elem[j] = this.elem[j + 1];
                }
                this.elem[useSize] = 0;
                useSize--;
                return;
            }
        }
    }

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

    // 清空顺序表
    public void clear() {
        for (int i = 0; i < useSize; i++) {
            this.elem[i] = 0;
        }
        this.useSize = 0; 
    }
}

两个异常的定义与实现

public class AddIndexOutException extends RuntimeException{
    public AddIndexOutException() {
    }

    public AddIndexOutException(String message) {
        super(message);
    }
}
public class GetIndexOutException extends RuntimeException{
    public GetIndexOutException() {
    }

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

3.java原生顺序表——ArratList

在集合框架中,ArrayList是一个普通的类,实现了List接口,具体框架图如下:
在这里插入图片描述
注意:

  1. ArrayList是以泛型方式实现的,使用时必须要先实例化
  2. ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问
  3. ArrayList实现了Cloneable接口,表明ArrayList是可以clone的
  4. ArrayList实现了Serializable接口,表明ArrayList是支持序列化的(可以把一个对象变成字符串称之为序列化,字符串变成对象叫反序列化)
  5. 和Vector不同,ArrayList不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector或者CopyOnWriteArrayList
  6. ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表

3.1ArrayList的构造方法

//三种构造方法
ArrayList()// 无参构造
ArrayList(Collection<? extends E> c) //利用其他 Collection 构建 ArrayList
ArrayList(int initialCapacity) //指定顺序表初始容量

1.无参构造方法

在这里插入图片描述其中elementData是一个成员数组,类型是Object类,如下图
在这里插入图片描述DEFAULTCAPACITY_EMPTY_ELEMENTDATA
是一个Object数组类型的常量,并且为空在这里插入图片描述也就是说此时没有为elementData分配内存,也就是说当我们调用无参的构造方法实例化一个ArrayList对象时,开辟了一个空数组。如下代码

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList1 = new ArrayList<Integer>();//实例化一个整型的ArrayList,调用无参的构造方法
        arrayList1.add(1);
    }
}

那么在arrayList1.add(1);这一句里面又做了什么呢
下图是调用add方法后的代码执行过程

取自比特鹏哥

实际上在第一次add的时候才会为ArrayList底层分配内存,且大小为10
而且通过对于add方法的考察会知道ArrayList中的元素个数如果超出,需要扩容是按1.5倍的最大容量扩容的

2.ArrayList(Collection<? extends E> c)构造方法

ArrayList(Collection<? extends E> c) //利用其他 Collection 构建 ArrayList

先来解释一下形参Collection<? extends E> c,首先Conllection是java内置的一个原生接口,表示集合,而Collection<? extends E>表明c是一个泛型而且是一个实现connection接口的类,例如下图
在这里插入图片描述List、Set、ArrayList、LinkedList等都实现了connection接口,并且这个c指定的泛型参数一定是E或者E的子类,E是Element的缩写,一般在集合中使用,表示集合中的元素类型。而Connection表示集合。所以这个代码的意思就是定义了泛型c,ArrayList构造方法的形参是一个实现Connecion接口(也就是必须是一个集合)的类型,并且里面的泛型形参指代的是集合元素类型(是E本身或者E的子类)

例如下面这样

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList1 = new ArrayList<Integer>();
        arrayList1.add(1);
        ArrayList<Integer> arrayList12 = new ArrayList<Integer>(arrayList1);
    }
}

为什么arrayList1可以作为实参传入。
因为arrayList的类型是ArrayList,其中ArrayList类实现了Connection接口,并且泛型的类型实参Integer,表面ArrayList集合中的元素类型为Integer,符合形参定义。

ArrayList<Integer> arrayList12 = new ArrayList<Integer>(arrayList1);

这个实例化就是调用带参数的构造方法,将传入的集合的所有元素复制一份,作为自己的集合元素并开辟相应的内存空间

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList1 = new ArrayList<Integer>();
        arrayList1.add(1);
        System.out.println(arrayList1);
        ArrayList<Integer> arrayList2 = new ArrayList<Integer>(arrayList1);
        System.out.println(arrayList2);
        arrayList2.add(2);
        System.out.println(arrayList2);
    }
}

在这里插入图片描述

3.ArrayList(int initialCapacity)构造方法

这是一个指定顺序表初始容量的构造方法,细节就不多说了

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList1 = new ArrayList<Integer>();
        arrayList1.add(1);
        System.out.println(arrayList1);
        ArrayList<Integer> arrayList2 = new ArrayList<Integer>(arrayList1);
        System.out.println(arrayList2);
        arrayList2.add(2);
        System.out.println(arrayList2);
        ArrayList<Integer> arrayList3 = new ArrayList<Integer>(2);
        arrayList3.add(1);
        arrayList3.add(2);
        System.out.println(arrayList3);
    }
}

在这里插入图片描述

3.2ArrayList常见操作

1.插入操作

尾插 e

`boolean add(E e)` 

将 e 插入到 index 位置(指定位置插入)

`void add(int index, E element)` 

尾插 c 中的元素(直接插入一个集合)

`boolean addAll(Collection<? extends E> c)` 

将c插入到index位置(插入一个集合)

boolean addAll(int index, Collection<? extends E> c)

如下面这个例子

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList1 = new ArrayList<>();
        arrayList1.add(1);//尾插入1
        System.out.println(arrayList1);
        arrayList1.add(1, 2);//下标为1为位置插入2
        System.out.println(arrayList1);
        ArrayList<Integer> arrayList2 = new ArrayList<>();
        arrayList2.addAll(arrayList1);//arrayList2尾插arrayList1的全部元素
        System.out.println(arrayList2);
        arrayList2.addAll(1, arrayList1);//从arrayList2下标为2的位置插入arrayList1的全部元素
        System.out.println(arrayList2);
    }
}

2.删除操作

删除 index 位置元素

E remove(int index) 

删除遇到的第一个 o

boolean remove(Object o) 

注意当我们元素类型是Integer时,代码remove(0)会识别将0识别为Int,而不是Integer类型,remove(0)中的这个0会认为是indexd的实参而不是Object实参,所以我们在删除存有Integer类型的元素时,需要进行装箱操作。
例如:

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList1 = new ArrayList<>();
        arrayList1.add(0);
        arrayList1.add(1);
        arrayList1.add(2);
        System.out.println(arrayList1);
        arrayList1.remove(new Integer(0));
        System.out.println(arrayList1);
        arrayList1.remove(0);
        System.out.println(arrayList1);
    }
}

在这里插入图片描述

3.获取操作

获取下标 index 位置元素

E get(int index) 

例如

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList1 = new ArrayList<>();
        arrayList1.add(0);
        arrayList1.add(1);
        arrayList1.add(2);
        System.out.println(arrayList1);
        System.out.println(arrayList1.get(0));
    }
}

在这里插入图片描述

4.更新操作

将下标 index 位置元素设置为 element

E set(int index, E element) 
import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList1 = new ArrayList<>();
        arrayList1.add(0);
        arrayList1.add(1);
        arrayList1.add(2);
        System.out.println(arrayList1);
        System.out.println(arrayList1.set(0,1));
        System.out.println(arrayList1);
    }
}

在这里插入图片描述

5.清空操作

void clear() //清空

例子

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList1 = new ArrayList<>();
        arrayList1.add(0);
        arrayList1.add(1);
        arrayList1.add(2);
        System.out.println(arrayList1);
        arrayList1.clear();
        System.out.println(arrayList1);
    }
}

在这里插入图片描述

6.其他操作

判断 o 是否在线性表中

boolean contains(Object o) 

返回第一个 o 所在下标

int indexOf(Object o) 

返回最后一个 o 的下标

int lastIndexOf(Object o) 

截取部分 list

List<E> subList(int fromIndex, int toIndex) 

例子

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

public class Test {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList1 = new ArrayList<>();
        arrayList1.add(0);
        arrayList1.add(1);
        arrayList1.add(0);
        System.out.println(arrayList1);
        System.out.println(arrayList1.contains(new Integer(0)));
        System.out.println(arrayList1.indexOf(new Integer(0)));
        System.out.println(arrayList1.lastIndexOf(new Integer(0)));
        List <Integer> arrayList2 = arrayList1.subList(0, 2);//必须用List类型承接,同时下标范围依旧是左闭右开
        System.out.println(arrayList2);
    }
}

在这里插入图片描述
但是
subList方法需要注意一下,看下面这个代码

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

public class Test {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList1 = new ArrayList<>();
        arrayList1.add(0);
        arrayList1.add(1);
        arrayList1.add(0);
        System.out.println(arrayList1);
        List <Integer> subList = arrayList1.subList(0, 2);
        System.out.println(subList);
        subList.set(0, 1);//更新subList下标为0的元素值为1
        System.out.println(subList);
        System.out.println(arrayList1);//arrayList下标为0的元素也会变化
    }
}

在这里插入图片描述
这是因为subList与arrayList共用一个value数组,注意subList方法并不是通过copy实现的,所以这不是浅拷贝。

3.3ArrayList的遍历

ArrayList有三种常见的遍历方式
第一种for循环+下标,这就不过多赘述了。
第二种是用for each

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList1 = new ArrayList<>();
        arrayList1.add(0);
        arrayList1.add(1);
        arrayList1.add(2);
        for (Integer x:arrayList1) {
            System.out.print(x+" ");
        }
    }
}

在这里插入图片描述
第三种是使用迭代器

```java
import java.util.ArrayList;
import java.util.ListIterator;

public class Test {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList1 = new ArrayList<>();
        arrayList1.add(0);
        arrayList1.add(1);
        arrayList1.add(2);
        for (Integer x:arrayList1) {
            System.out.print(x+" ");
        }
        System.out.println();

        //创建一个arrayList1的迭代器
        ListIterator<Integer> it = arrayList1.listIterator();//it会指向集合受元素的前一个单位的位置
        while(it.hasNext()){//it.hasNext()判断it的下一个位置是否有元素,有返回true,没有返回false
            System.out.print(it.next()+" ");//回去it所指位置的下一个单位位置的元素内容并将next指向下一个元素
            //这个it有点像C里面栈的头指针的含义
        }
    }
}

在这里插入图片描述
关于迭代器,可以去看这篇博客
https://blog.csdn.net/rbx508780/article/details/126980386

3.4ArrayList的扩容机制

ArrayList是一个动态类型的顺序表,即:在插入元素的过程中会自动扩容。

ArrayList的扩容机制这样的:

  1. 检测是否真正需要扩容,如果是,调用grow准备扩容

  2. 预估需要库容的大小

  3. 初步预估按照1.5倍大小扩容 如果用户所需大小超过预估1.5倍大小,则按照用户所需大小扩容

  4. 真正扩容之前检测是否能扩容成功,防止太大导致扩容失败

  5. 使用copyOf进行扩容

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

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

相关文章

优思学院|什么是精益生产?企业如何实现精益生产?

简介 在现代工业社会中&#xff0c;企业的生产效率和质量管理是其生存和发展的关键因素之一。而精益生产作为一种高效的生产管理模式&#xff0c;已经成为了众多企业提升效率和质量的首选。优思学院[1]在本文将对精益生产进行详细的介绍&#xff0c;并提供企业实现精益生产的实…

【Java零基础入门篇】第 ④ 期 - 继承(二)

博主&#xff1a;命运之光 专栏&#xff1a;JAVA入门 学习目标 1.掌握继承性的主要作用、实现、使用限制&#xff1b; 2.掌握this和super的含义及其用法&#xff1b; 3.掌握方法覆写的操作&#xff1b; 4.掌握final关键字的使用&#xff1b; 5.掌握类变量、实例变量和局部变量的…

【应用场景详解】Web自动化测试适用于哪些场景?看完这篇文章你就知道了

【从入门到实战】WEB自动化测试基础教程&#xff0c;手把手教你封装自己的测试框架&#xff01; 目录 前言&#xff1a; 一、什么是web自动化测试&#xff1f; 二、Web自动化测试的应用场景 三、Web自动化测试的实现方法 1.安装Selenium 2.编写测试用例 四、Web自动自动…

第十二章 使用DHCP动态管理主机地址

文章目录 第十二章 使用DHCP动态管理主机地址一、动态主机地址管理协议1、DHCP简介2、DHCP常见术语 二、部署DHCP服务程序1、安装DHCP服务程序2、配置文件参考模板3、dhcpd服务程序配置文件中常见参数及作用 三、自动管理IP地址1、机房所用的网络地址以及参数信息2、关闭虚拟网…

原装二手Anritsu S331E安立S331L 手持式电缆和天线分析仪

Anritsu S331E Site Master 手持式电缆和天线分析仪涵盖 2 MHz 至 4 GHz 频谱&#xff0c;是无线基站电缆和天线系统安装、配置、维护和故障排除的行业标准。Site Master 准确、多功能、价格合理、坚固耐用&#xff0c;是真正的手持设备&#xff0c;重量不到 5 磅&#xff08;包…

跨越式升级,敏感数据动态脱敏系统全新而来!

“ 2020年 某医院疫情名单遭工作人员外泄至微信群&#xff0c;涉及6000余人个人身份信息&#xff0c;三人被拘 2021年 某银行未经客户本人授权查询并向第三方提供其个人银行帐户交易信息&#xff0c;被罚450万元 2022年 某银行未落实个人银行账户实名制管理规定&#xff…

民宿企业数字化最佳实践 :我终于跟线下表格和解了

“不由感叹&#xff0c;技术就是生产力啊&#xff01;” 这是偶来民宿店长在使用了腾讯轻联后不由得发出的感慨。 偶来民宿是一家管理超过100套城市民宿和公寓房源的民宿运营公司&#xff0c;以经营特色化、年轻化、个性化民宿、公寓为主营业务。IF HOUSE为该公司旗下高端民宿…

github copilot如何帮助写代码

Github Copilot是一个基于人工智能的代码助手&#xff0c;可以帮助程序员在编写代码时提供自动补全和建议功能。使用Github Copilot需要以下步骤&#xff1a; 1.注册Github账号并安装Github Copilot插件 首先你需要注册一个Github账号&#xff0c;然后在你使用的代码编辑器中安…

基于netty框架不使用SSL证书,实现websocket数据加密传输

文章目录 简介实现方式主要代码调用方法 1、简介 2、实现方式 3、服务端主要代码 4、客户端主要代码 5、调用方式 简介 为什么不使用SSL证书&#xff1f; 1、服务器运行在专网环境&#xff0c;不能访问互联网。证书有有效期&#xff0c;CA机构规定&#xff0c;证书有效期…

vue3【使用axios并封装axios请求】

第一步&#xff1a;安装axios npm install axios 第二步&#xff1a;编写请求文件 新建request.js 简单的axios封装&#xff0c;里面相关提示信息&#xff0c;自己可以引入element-plus去添加 /**axios封装* 请求拦截、相应拦截、错误统一处理*/ import axios from axios; i…

Linux入门篇-安装CentOS

一、先组织硬件 先把“买”一台空白的电脑&#xff0c;再进行操作系统的安装。 windows中&#xff0c;处理器&#xff1a; 本机 实际运行的时候能当多少个CPU来使呢&#xff1f;16个 处理器的数量是CPU的数量&#xff1b;&#xff08;本机上一个插槽&#xff0c;就只有一个CP…

同城跑腿能赚多少钱?“爱折腾”的创业者是否值得入局一试?

跑腿服务兴起的最大特点是节省时间和成本。现在城市发展越来越快&#xff0c;真的应该是“时间就是金钱”的道理。帮助人们排队购物、送外卖、送文件、买花、叫醒服务……“跑腿”在生活中无处不在。 同城跑腿系统的前景有多大&#xff1f; 一方面&#xff0c;外卖和网上购物…

深入学习MYSQL-使用触发器

触发器 每个表最多支持6个触发器&#xff0c;&#xff08;insert&#xff0c;update&#xff0c;delete&#xff09;之前和之后。 删除触发器 drop trigger trigger_name;insert 触发器  在INSERT触发器代码内&#xff0c;可引用一个名为NEW的虚拟表&#xff0c;访问被插入…

第一章--Java语言概述

一 Java知识脉络图 1.1 Java基础全程脉络图 1.2 本章专题与脉络 二 计算机的硬件与软件 2.1 计算机组成&#xff1a;硬件软件 2.2 CPU、内存与硬盘 CPU&#xff08;Central Processing Unit&#xff0c;中央处理器&#xff09; 人靠大脑思考&#xff0c;电脑靠CPU来运算、控…

【beego】bee工具安装使用

bee 工具是一个为了协助快速开发 beego 项目而创建的项目&#xff0c;通过 bee 您可以很容易的进行 beego 项目的创建、热编译、开发、测试、和部署。 1、安装 go get github.com/beego/bee2、配置bee.exe 运行完以上指令后&#xff0c;打开$GOPATH/bin &#xff0c;我的路径…

刷完这个笔记,17K不能再少了....

大家好&#xff0c;最近有不少小伙伴在后台留言&#xff0c;得准备面试了&#xff0c;又不知道从何下手&#xff01;为了帮大家节约时间&#xff0c;特意准备了一份面试相关的资料&#xff0c;内容非常的全面&#xff0c;真的可以好好补一补&#xff0c;希望大家在都能拿到理想…

2直接连接的网络与VLAN划分-2.1【实验】【计算机网络】

2直接连接的网络与VLAN划分【实验】【计算机网络】 前言推荐2直接连接的网络与VLAN划分2.1共享式以太网和交换式以太网实验目的实验内容及实验环境实验原理共享式以太网交换式以太网 实验过程搭建实验环境初始化序训练操作共享式以太网-操作交换式以太网查看共享式以太网冲突查…

java中ArrayList顺序表的常见操作

ArrayList常见操作 1.插入操作 尾插 e boolean add(E e) 将 e 插入到 index 位置&#xff08;指定位置插入&#xff09; void add(int index, E element) 尾插 c 中的元素(直接插入一个集合) boolean addAll(Collection<? extends E> c) 将c插入到index位置&#x…

java基础--(一)创建对象在内存中的理解

1、代码 package demo; public class Car {String color;int num;public Car() {}public void run(){System.out.println("color " color);System.out.println("num " num);}public Car(String color, int num) {this.color color;this.num num;} …

2022年美国大学生数学建模竞赛D题数据瘫痪? 使用我们的分析!解题全过程文档及程序

2022年美国大学生数学建模竞赛 D题数据瘫痪? 使用我们的分析! 原题再现&#xff1a; 背景   很多公司将数据视为战略资产&#xff0c;但却很难从中获益。妥善管理这一资源(数据)可以带来竞争优势。因此&#xff0c;公司需要建立一一个集成的数据和分析(D&A) 系统&…