Java ArrayList 与顺序表:在编程海洋中把握数据结构的关键之锚

在这里插入图片描述

我的个人主页
我的专栏Java-数据结构,希望能帮助到大家!!!点赞❤ 收藏❤

前言:在 Java编程的广袤世界里,数据结构犹如精巧的建筑蓝图,决定着程序在数据处理与存储时的效率、灵活性以及可扩展性。其中,ArrayList和顺序表作为线性数据结构的典型代表,犹如两颗璀璨的明星,在众多数据处理场景中熠熠生辉。
顺序表,以其简洁而直观的连续内存存储方式,为数据的快速随机访问提供了可能。它犹如一位严谨的管家,将数据元素有条不紊地排列在连续的内存空间中,使得我们能够通过精确的索引迅速定位到所需的数据,就像在一本精心编排索引的书籍中快速找到特定章节一样高效。这种特性在一些对数据访问速度有严格要求且数据量相对固定或可预知的场景中,展现出了无与伦比的优势。
而 ArrayList,则是 Java 集合框架中备受瞩目的一员。它基于数组实现,却又巧妙地融入了动态扩容机制,如同一位富有弹性的艺术家,能够根据创作需求灵活调整画布的大小。这种动态性使得
ArrayList在应对数据量不确定、频繁增删元素的复杂情况时游刃有余。它为开发者提供了丰富便捷的方法库,极大地简化了数据操作的流程,仿佛一把瑞士军刀,在各种数据处理任务中都能发挥出色的作用。
在实际的编程旅程中,深入理解 ArrayList 和顺序表的特性、性能表现以及适用场景,就如同掌握了两门精湛的技艺。无论是构建高效的数据库管理系统、开发复杂的算法,还是打造用户友好的图形界面应用,都离不开对这两种数据结构的精准运用。本博客将深入剖析
Java ArrayList 和顺序表,从原理到实现,从性能对比到应用场景分析,为你揭开它们神秘的面纱,引领你在 Java编程的数据结构之路上稳步前行,帮助你在面对各种数据处理挑战时做出明智而高效的抉择。

一:线性表

二:顺序表

三:ArrayList的简介

四:ArrayList使用

五:ArrayList的扩容机制

一:线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列…
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。

Java 编程领域,线性表是一种极为基础且关键的数据结构,它犹如大厦的基石,支撑起众多复杂算法与程序功能的实现。线性表,从直观上理解,是由一系列具有相同类型的数据元素按照特定的顺序依次排列而成的集合,其元素之间存在着一对一的线性关系。
1.1线性表的基本特性:
(一)有限性
线性表中的元素数量是有限的。无论是空表(不包含任何元素),还是包含大量元素的表,其元素个数总能确定。例如,一个班级的学生名单,无论班级规模大小,学生人数总归是可以明确统计的。
(二)有序性
元素在表中的排列具有确定的顺序。每个元素都有其特定的位置,除了第一个元素无前驱,最后一个元素无后继外,其他元素都有且仅有一个直接前驱和一个直接后继。就像电影院里的座位号,每个座位都有其固定的前后顺序。
(三)同一性
表中的所有元素都属于同一数据类型。这一特性使得对线性表的操作能够具有一致性和规范性。例如,一个存储整数的线性表,其中所有元素都为整型,这样在进行数学运算或数据比较等操作时就可以按照统一的整型规则进行。
1.2线性表在 Java 中的常见实现方式
存储结构
顺序表利用数组来存储线性表中的元素。在 Java 中,可以声明一个数组来容纳这些元素,例如 Object[] data(或指定具体类型如 int[] data 等)。数组在内存中是连续分配空间的,这使得顺序表在随机访问元素时具有极高的效率。通过元素的索引,可以直接计算出其在内存中的存储地址,从而快速获取到该元素,时间复杂度为 O(1)。
操作实现
插入操作:当向顺序表中插入一个元素时,如果插入位置不是在表尾,需要将插入位置之后的所有元素依次向后移动一位,为新元素腾出空间,然后再将新元素放入指定位置。这种移动操作在元素数量较多时可能会耗费较多时间,平均时间复杂度为O(n) ,其中 为线性表的长度。例如,在一个长度为 100 的顺序表中,如果要在第 50 个位置插入一个元素,就需要将第 50 个到第 100 个元素向后移动一位。
删除操作:类似地,删除操作如果不是删除表尾元素,需要将删除位置之后的元素依次向前移动一位,以填补删除元素后留下的空位。其平均时间复杂度也为O(n) 。比如删除一个长度为 80 的顺序表中的第 30 个元素,就需要将第 31 个到第 80 个元素向前移动一位。
查询操作:由于可以直接通过索引访问数组元素,所以查询指定位置元素的时间复杂度为O(1) 。而查询某个特定值的元素时,可能需要遍历整个顺序表,在最坏情况下时间复杂度为O(n) 。例如,在一个存储学生成绩的顺序表中,如果要查找成绩为 90 分的学生,可能需要逐个比较所有学生的成绩。
二:顺序表
在这里插入图片描述
在这里插入图片描述

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

1.1定义一个类来表示顺序表:

class ArrayList<E> {
    // 存储数据的数组
    private E[] data;
    // 记录当前顺序表中元素的个数
    private int size;

    // 构造函数,初始化数组容量
    public ArrayList(int capacity) {
        data = (E[]) new Object[capacity];
        size = 0;
    }
}

这里的 data 数组就是用来存放顺序表元素的核心容器,而 size 则用于追踪实际存储的元素数量。
2.1 接口的实现

public class SeqList {
private int[] array;
private int size;
// 默认构造方法
SeqList(){ }
// 将顺序表的底层容量设置为initcapacity
SeqList(int initcapacity){ }
// 新增元素,默认在数组最后新增
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() { }
}

插入操作
当向顺序表中插入一个元素时,情况会相对复杂一些。如果是在顺序表的末尾插入元素,操作较为简单,只需将元素放入 data[size] 的位置,并将 size 加 1 即可。但如果是在中间位置插入,例如在索引 k 处插入元素 e,则需要将索引 k 及之后的元素依次向后移动一位,为新元素腾出空间,然后再将新元素放入索引 k 处。

public void add(int index, E e) {
    if (index < 0 || index > size) {
        throw new IllegalArgumentException("Add failed. Illegal index.");
    }
    if (size == data.length) {
        resize(2 * data.length);
    }
    for (int i = size - 1; i >= index; i--) {
        data[i + 1] = data[i];
    }
    data[index] = e;
    size++;
}

删除操作
删除顺序表中的元素同样需要考虑多种情况。如果删除的是末尾元素,直接将 size 减 1 即可。若删除索引为 k 的元素,则需要将索引 k 之后的元素依次向前移动一位,覆盖掉要删除的元素。

public E remove(int index) {
    if (index < 0 || index >= size) {
        throw new IllegalArgumentException("Remove failed. Illegal index.");
    }
    E ret = data[index];
    for (int i = index + 1; i < size; i++) {
        data[i - 1] = data[i];
    }
    size--;
    data[size] = null;
    if (size == data.length / 4 && data.length / 2!= 0) {
        resize(data.length / 2);
    }
    return ret;
}

三:ArrayList的简介

ArrayList是 Java 集合框架中的一个重要类,它位于java.util包中。它实现了List接口,这意味着它是一个有序的集合,允许存储重复的元素。它的底层数据结构是一个动态大小的数组,这使得它可以根据需要自动调整大小。
与普通数组相比,ArrayList更加灵活。普通数组在创建时就确定了大小,之后很难改变其容量,而ArrayList可以方便地添加或删除元素,并且会自动处理数组容量的扩展和收缩。

在这里插入图片描述

说明:
1. ArrayList是以泛型⽅式实现的,使⽤时必须要先实例化
2. ArrayList实现了RandomAccess接⼝,表明ArrayList⽀持随机访问
3. ArrayList实现了Cloneable接⼝,表明ArrayList是可以clone的
4. ArrayList实现了Serializable接⼝,表明ArrayList是⽀持序列化的
5. 和Vector不同,ArrayList不是线程安全的,在单线程下可以使⽤,在多线程中可以选择Vector或者 CopyOnWriteArrayList
6. ArrayList底层是⼀段连续的空间,并且可以动态扩容,是⼀个动态类型的顺序表

创建ArrayList对象
要使用ArrayList,首先需要导入java.util.ArrayList类。

import java.util.ArrayList;
public class ArrayListExample {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<String>();
    }
}
创建了一个可以存储String类型元素的ArrayList。其中是泛型参数,用于指定列表中元素的类型。除了String,还可以是其他基本数据类型对应的包装类(如Integer、Double等)或自定义的类类型。

四:ArrayList使用
4.1 ArrayList的构造
在这里插入图片描述

public static void main(String[] args) {
// ArrayList创建,推荐写法
// 构造⼀个空的列表
List<Integer> list1 = new ArrayList<>();
// 构造⼀个具有10个容量的列表
List<Integer> list2 = new ArrayList<>(10);
list2.add(1);
list2.add(2);
list2.add(3);
// list2.add("hello"); // 编译失败,List<Integer>已经限定了,list2中只能存储整
形元素
// list3构造好之后,与list中的元素⼀致
ArrayList<Integer> list3 = new ArrayList<>(list2);
// 避免省略类型,否则:任意类型的元素都可以存放,使⽤时将是⼀场灾难
List list4 = new ArrayList();
list4.add("111");
list4.add(100);
}

4.2 ArrayList常⻅操作
在这里插入图片描述

4.2.1添加元素

add(E e)方法:用于在ArrayList末尾添加元素。
import java.util.ArrayList;
public class ArrayListAddExample {
    public static void main(String[] args) {
        ArrayList<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Banana");
        System.out.println(fruits); 
    }
}

首先创建了一个ArrayList对象fruits,用于存储String类型的元素。然后通过add方法添加了两个水果名称,最后打印出ArrayList,输出结果为[Apple, Banana]。

add(int index, E e)方法:用于在指定索引index处插入元素e。
import java.util.ArrayList;
public class ArrayListAddAtIndexExample {
    public static void main(String[] args) {
        ArrayList<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add(1, "Cherry");
        System.out.println(fruits); 
    }
}

这里在索引为1的位置插入了"Cherry",原来索引为1(即"Banana")及其后面的元素会向后移动一位。输出结果为[Apple, Cherry, Banana]。

4.2.2获取元素

get(int index)方法:用于获取ArrayList中指定索引index处的元素。
import java.util.ArrayList;
public class ArrayListGetExample {
    public static void main(String[] args) {
        ArrayList<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Banana");
        String secondFruit = fruits.get(1);
        System.out.println(secondFruit); 
    }
}

通过get(1)获取了索引为1的元素,即"Banana",并将其存储在secondFruit变量中,最后打印输出。

4.2.3修改元素

直接通过索引赋值:可以像操作数组一样,通过指定索引来修改ArrayList中的元素。
import java.util.ArrayList;
public class ArrayListSetExample {
    public static void main(String[] args) {
        ArrayList<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.set(1, "Orange");
        System.out.println(fruits); 
    }
}

通过set(1, “Orange”)将索引为1的元素(原来为"Banana")修改为"Orange",输出结果为[Apple, Orange]。

4.2.4删除元素

remove(int index)方法:用于删除指定索引index处的元素。
import java.util.ArrayList;
public class ArrayListRemoveByIndexExample {
    public static void main(String[] args) {
        ArrayList<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.remove(0);
        System.out.println(fruits); 
    }
}

通过remove(0)删除了索引为0的元素(即"Apple"),输出结果为[Banana]。

remove(Object o)方法:用于删除指定的对象o。
import java.util.ArrayList;
public class ArrayListRemoveByObjectExample {
    public static void main(String[] args) {
        ArrayList<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.remove("Apple");
        System.out.println(fruits); 
    }
}

通过remove(“Apple”)删除了ArrayList中值为"Apple"的元素,输出结果为[Banana]。

4.2.5遍历ArrayList

使用普通for循环
import java.util.ArrayList;
public class ArrayListForLoopExample {
    public static void main(String[] args) {
        ArrayList<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Banana");
        for (int i = 0; i < fruits.size(); i++) {
            System.out.println(fruits.get(i));
        }
    }
}

在这个循环中,i从0开始,每次循环增加1,直到i小于ArrayList的大小(通过size()方法获取)。在循环体内部,通过get(i)方法获取当前索引的元素并打印输出。

使用增强for循环(for - each循环)
import java.util.ArrayList;
public class ArrayListForEachLoopExample {
    public static void main(String[] args) {
        ArrayList<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Banana");
        for (String fruit : fruits) {
            System.out.println(fruit);
        }
    }
}

fruit变量会依次获取ArrayList中的每个元素,循环会自动遍历整个ArrayList,直到所有元素都被访问。

使用迭代器(Iterator):
import java.util.ArrayList;
import java.util.Iterator;
public class ArrayListIteratorExample {
    public static void main(String[] args) {
        ArrayList<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Banana");
        Iterator<String> iterator = fruits.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

通过iterator()方法获取ArrayList的迭代器。然后通过hasNext()方法检查是否还有下一个元素,如果有,则通过next()方法获取并打印下一个元素,直到没有更多元素为止。

五:ArrayList的扩容机制

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

public boolean add(E e) {
	modCount++;
	add(e, elementData, size);
	return true;
}
private void add(E e, Object[] elementData, int s) {
	if (s == elementData.length) //第⼀次存储的时候 elementData.length=0,s = 0
	elementData = grow();
	elementData[s] = e;
	size = s + 1;
}
private Object[] grow() {
	return grow(size + 1);
}
private Object[] grow(int minCapacity) {
	int oldCapacity = elementData.length;
	if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
		int newCapacity = ArraysSupport.newLength(oldCapacity,
		minCapacity - oldCapacity, /* minimum growth */
		oldCapacity >> 1 /* preferred growth */);
	return elementData = Arrays.copyOf(elementData, newCapacity);
	} else {
		return elementData = new Object[Math.max(DEFAULT_CAPACITY,minCapacity)];
	}
}
//oldLength: 当前数组的⻓度
//minGrowth: 最⼩需要增加的⻓度
//prefGrowth: ⾸选的增⻓ 度(通常是当前⼤⼩的⼀半)
public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
	// preconditions not checked because of inlining
	// assert oldLength >= 0
	// assert minGrowth > 0
	//当前⻓度加上 minGrowth 和 prefGrowth 中的较⼤值。
	int prefLength = oldLength + Math.max(minGrowth, prefGrowth); // might overflow
	if (0 < prefLength && prefLength <= SOFT_MAX_ARRAY_LENGTH) {
		return prefLength;
	} else {
		// put code cold in a separate method
			return hugeLength(oldLength, minGrowth);
		}
}
private static int hugeLength(int oldLength, int minGrowth) {
	int minLength = oldLength + minGrowth;
	if (minLength < 0) { // overflow
		throw new OutOfMemoryError("Required array length " + oldLength + " + " + minGrowth + " is too large");
	} else if (minLength <= SOFT_MAX_ARRAY_LENGTH) {
		return SOFT_MAX_ARRAY_LENGTH;
	} else {
		return minLength;
			}
}

如果调⽤不带参数的构造⽅法,第⼀次分配数组⼤⼩为10
后续扩容为1.5倍扩容

这次的ArrayList的学习就到的了,剩下的叙述下一篇中
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【笔记】自动驾驶预测与决策规划_Part8_数据驱动的规划方法

文章目录 0. 前言1.生成模型1.1 Diffusion-ES1. Diffusion-ES算法介绍2. Diffusion-ES算法具体流程Diffusion Model 是什么&#xff1f;Diffusion-ES: Evolutionary StrategiesDiffusion-ES MethodDiffusion-ES Mapping Language instructions to reward functions with LLM pr…

React中事件处理和合成事件:理解与使用

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

Redis设计与实现第14章 -- 服务器 总结(命令执行器 serverCron函数 初始化)

14.1 命令请求的执行过程 一个命令请求从发送到获得回复的过程中&#xff0c;客户端和服务器都需要完成一系列操作。 14.1.1 发送命令请求 当用户在客户端中输入一个命令请求的时候&#xff0c;客户端会把这个命令请求转换为协议格式&#xff0c;然后通过连接到服务器的套接字…

【C语言】字符串左旋的三种解题方法详细分析

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C语言 文章目录 &#x1f4af;前言&#x1f4af;题目描述&#x1f4af;方法一&#xff1a;逐字符移动法&#x1f4af;方法二&#xff1a;使用辅助空间法&#x1f4af;方法三&#xff1a;三次反转法&#x1f4af;方法对…

【AI绘画】Midjourney进阶:色调详解(上)

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: AI绘画 | Midjourney 文章目录 &#x1f4af;前言&#x1f4af;Midjourney中的色彩控制为什么要控制色彩&#xff1f;为什么要在Midjourney中控制色彩&#xff1f; &#x1f4af;色调白色调淡色调明色调 &#x1f4af…

零基础学安全--云技术基础

目录 学习连接 前言 云技术历史 云服务 公有云服务商 云分类 基础设施即服务&#xff08;IaaS&#xff09; 平台即服务&#xff08;PaaS&#xff09; 软件即服务&#xff08;SaaS&#xff09; 云架构 虚拟化 容器 云架构设计 组件选择 基础设施即代码 集成部署…

【Linux】网络通信

TCP协议是一个安全的、面向连接的、流式传输协议&#xff0c;所谓的面向连接就是三次握手&#xff0c;对于程序猿来说只需要在客户端调用connect()函数&#xff0c;三次握手就自动进行了。先通过下图看一下TCP协议的格式&#xff0c;然后再介绍三次握手的具体流程。 TCP的三次握…

Pgsql:json字段查询与更新

1.查询json字段的值 SELECT attribute_data->>设施类别 mycol, * FROM gis_coord_data WHERE attribute_data->>设施类别阀门井 查询结果如下&#xff1a; 2.更新json字段中的某个属性值 UPDATE gis_coord_data SET attribute_data(attribute_data::jsonb ||{&quo…

对于GC方面,在使用Elasticsearch时要注意什么?

大家好&#xff0c;我是锋哥。今天分享关于【对于GC方面&#xff0c;在使用Elasticsearch时要注意什么&#xff1f;】面试题。希望对大家有帮助&#xff1b; 对于GC方面&#xff0c;在使用Elasticsearch时要注意什么&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java…

基于Netty实现聊天室

前言 了解了Netty的基本功能和相关概念&#xff0c;使用基于Netty实现多人聊天的功能。 需求 1.服务端能够接收客户端的注册&#xff0c;并且接受用户的信息注册 2.服务端能够处理客户端发送的消息&#xff0c;并且根据消息类型进行私发或者广播发送消 3.服务端能够私发消…

Linux -日志 | 线程池 | 线程安全 | 死锁

文章目录 1.日志1.1日志介绍1.2策略模式1.3实现日志类 2.线程池2.1线程池介绍2.2线程池的应用场景2.3线程池的设计2.4代码实现2.5修改为单例模式 3.线程安全和函数重入问题3.1线程安全和函数重入的概念3.2总结 4.死锁4.1什么是死锁4.2产生死锁的必要条件4.3避免死锁 1.日志 1.…

【博主推荐】C#的winfrom应用中datagridview常见问题及解决方案汇总

文章目录 1.datagridview绘制出现鼠标悬浮数据变空白2.datagridview在每列前动态添加序号2.1 加载数据集完成后绘制序号2.2 RowPostPaint事件绘制 3.datagridview改变行样式4.datagridview后台修改指定列数据5.datagridview固定某个列宽6.datagridview某个列的显示隐藏7.datagr…

【设计模式】创建型模式之单例模式(饿汉式 懒汉式 Golang实现)

定义 一个类只允许创建一个对象或实例&#xff0c;而且自行实例化并向整个系统提供该实例&#xff0c;这个类就是一个单例类&#xff0c;它提供全局访问的方法。这种设计模式叫单例设计模式&#xff0c;简称单例模式。 单例模式的要点&#xff1a; 某个类只能有一个实例必须…

Vivado程序固化到Flash

在上板调试FPGA时&#xff0c;通常使用JTAG接口下载程序到FPGA芯片中&#xff0c;FPGA本身是基于RAM工艺的器件&#xff0c;因此掉电后会丢失芯片内的程序&#xff0c;需要重新烧写程序。但是当程序需要投入使用时不能每一次都使用JTAG接口下载程序&#xff0c;一般FPGA的外围会…

技术文档,they are my collection!

工作 今天这篇文章&#xff0c;献给一直撰写技术文档的自己。我自认为是公司中最爱写文档的人了&#xff0c;我们是一个不到40人的小公司&#xff0c;公司作风没有多么严谨&#xff0c;领导也不会要求我们写技术文档。但是从入职初至今&#xff0c;我一直保持着写技术文档…

微信小程序学习指南从入门到精通

&#x1f5fd;微信小程序学习指南从入门到精通&#x1f5fd; &#x1f51d;微信小程序学习指南从入门到精通&#x1f51d;✍前言✍&#x1f4bb;微信小程序学习指南前言&#x1f4bb;一、&#x1f680;文章列表&#x1f680;二、&#x1f52f;教程文章的好处&#x1f52f;1. ✅…

JavaWeb——SpringBoot原理

10.1. 配置优先级 10.1.1. 配置文件 properties > yml(推荐) > yaml 10.1.2. Java系统属性、命令行参数 命令行参数 > Java系统属性 > 配置文件 10.2. Bean管理 10.2.1. 手动获取bean ApplicationContext&#xff0c;IOC容器对象 10.2.2. bean作用域 10.2.3.…

如何在Python中进行数学建模?

数学建模是数据科学中使用的强大工具&#xff0c;通过数学方程和算法来表示真实世界的系统和现象。Python拥有丰富的库生态系统&#xff0c;为开发和实现数学模型提供了一个很好的平台。本文将指导您完成Python中的数学建模过程&#xff0c;重点关注数据科学中的应用。 数学建…

OCR技术详解:从基础到应用

OCR技术详解&#xff1a;从基础到应用 引言 OCR技术的定义 OCR&#xff08;Optical Character Recognition&#xff0c;光学字符识别&#xff09;是一种将印刷或手写文本转换为机器可读文本的技术。通过OCR技术&#xff0c;计算机可以自动识别图像中的文字&#xff0c;并将其…

webrtc视频会议学习(三)

文章目录 关联&#xff1a;源码搭建coturn服务器nginx配置ice配置需服务器要开放的端口 效果 关联&#xff1a; webrtcP2P音视频通话&#xff08;一&#xff09; webrtcP2P音视频通话&#xff08;二&#xff09; webrtc视频会议学习&#xff08;三&#xff09; 源码 WebRTC…