【数据结构二】手撕顺序表与ArrayList源码详解

目录

顺序表与ArrayList

1. 手撕顺序表

2.ArrayList的使用

3.ArrayList的源码分析(扩容机制)

4.力扣题练习


顺序表与ArrayList

    线性表是在逻辑上具备线性结构的一种有序序列,包括顺序表和链表。其中顺序表的物理地址也连续,一般采用数组储存,在数组上完成对数据的增删改查。链表的物理地址不连续,通过记录下一个节点的地址来实现逻辑上的连续,通过对记录地址变量的修改来实现增删改查。

1. 手撕顺序表

对于任意一个继承list接口的数据结构我们都应该实现增删改查获取长度清空等方法,以及相应类的构造方法,我们知道Java中为了提高代码的复用,都是通过类继承接口的方式来进行代码试现,下面让我们写这样一个接口。

下面我们简单通过数组来实现下这个顺序表:

注意:我们自己的顺序表没有实现泛型机制,而java提供的ArrayList是实现了泛型的。

import java.util.Arrays;

public class MyArrayList implements MyList{
    private int[] array;
    private int size;
    MyArrayList(){
     array=new int[10];
     size=0;
    }
    //指定容量的构造器
    MyArrayList(int initcapacity){
       array=new int[initcapacity];
       size=0;
    }
    @Override
    public void add(int data) {
       if(size==array.length){
           Arrays.copyOf(array,array.length*2);
       }
       array[size]=data;
       size++;
    }

    @Override
    public void add(int pos, int data) {
    if (pos>size||pos<0){
        throw new posException();
    }
    if(size==array.length){
        Arrays.copyOf(array,array.length*2);
    }
    for(int i=size-1;i>=pos;i--){
        array[i+1]=array[i];
    }
    array[pos]=data;
    size++;
    }

    @Override
    public boolean contains(int toFind) {
        for(int i=0;i<size;i++){
            if(array[i]==toFind){
                return true;
            }
        }
        return false;
    }

    @Override
    public int indexOf(int toFind) {
        for (int i=0;i<size;i++){
            if(array[i]==toFind){
                return i;
            }
        }
        return -1;
    }

    @Override
    public int get(int pos) {
        if (pos>=size||pos<0){
            throw new posException();
        }
        return array[pos];
    }

    @Override
    public void set(int pos, int value) {
        if (pos>=size||pos<0){
            throw new posException();
        }
        array[pos]=value;
    }

    @Override
    public void remove(int toRemove) {
        int num=indexOf(toRemove);
       if(size==0){
           throw new emptyException();
       }
       for(int i=num;i<size-1;i++){
           array[i]=array[i+1];
       }
       size--;
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public void clear() {
      for (int i=0;i<size;i++){
          array[i]=0;
      }
      size=0;
    }
}

大家可以自己动手写一写这个代码实现。 

2.ArrayList的使用

ArrayList基本的增删改查操作与上述几乎一致,这里重点讲述ArrayList的遍历方法:

最常见的遍历方式有四种,分别是:

1.for循环+下标:

for(int i=0;i<list.length;i++){
System.out.print(list[i]+" ");
}

2.for-each遍历:

ArrayList<String> list = new ArrayList();
        for (String str:list) {
            System.out.print(str+" ");
        }

3.迭代器遍历:

ArrayList<String> list = new ArrayList();
        Iterator iterator=list.iterator();
        while (iterator.hasNext()){
            System.out.print(iterator.next()+" ");
}

4.集合对象的for-each方法(结合lambda表达式)

ArrayList<String> list = new ArrayList();
        list.add("awda");
        list.add("asdasd");
        list.forEach(str->{
            System.out.print(str+" ");
        });

 

3.ArrayList的源码分析(扩容机制)

ArrayList 是一个动态类型的顺序表,即:在插入元素的过程中会自动扩容。以下是 ArrayList 源码中扩容方式:
Object[] elementData; // 存放元素的空间
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; // 默认空间
private static final int DEFAULT_CAPACITY = 10; // 默认容量大小
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
// 获取旧空间大小
int oldCapacity = elementData.length;
// 预计按照1.5倍方式扩容
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果用户需要扩容大小 超过 原空间1.5倍,按照用户所需大小扩容
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 如果需要扩容大小超过MAX_ARRAY_SIZE,重新计算容量大小
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 调用copyOf扩容
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
// 如果minCapacity小于0,抛出OutOfMemoryError异常
if (minCapacity < 0)
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}

总结:

  1. ArrayList顺序表在无参构造时初始容量大小是10。
  2. 在添加元素时,检查是否需要扩容,如果是调用grow方法扩容。
  3. 初步预估按照 1.5 倍大小扩容
    如果用户所需大小超过预估 1.5 倍大小,则按照用户所需大小扩容
    真正扩容之前检测是否能扩容成功,防止太大导致扩容失败
  4. 用Arrays.copyOf()方法进行扩容。

4.力扣题练习

问题链接:杨辉三角

问题: 

思路: 通过泛型内在放一个顺序表类的方法实现二维列表,然后再利用循环先将每一层的数值填入numRows个顺序表中,再把这numRows个顺序表填入另一个顺序表中,最后这个顺序表就包含了我们想要的结果。

解题答案: 

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

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

相关文章

01_软件测试

01_软件测试 学习目标 1、能复述软件测试的定义 2、能说出7种测试分类的区别 3、能说出质量模型的重点5项 4、能说出测试流程的6个步骤 5、能说出测试模板8个要素 认识软件及测试 什么是软件 软件&#xff1a;控制计算机硬件工作的工具 软件的基本组成 软件生产过程 什么是软…

打地鼠游戏来了

主要利用js鼠标点击事件和window.setInterval&#xff08;&#xff09;回调函数来进行实现的. 源码获取方式&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1eW9qvX3zFH9qlH82-I4yOA 提取码&#xff1a;1233

配置代理解决跨域(CORS)问题

一、跨域 &#xff1f; 我们在完成前后端分离项目时&#xff08;VueSpringBoot&#xff09;&#xff0c;有很多人会遇到跨域问题&#xff08;CORS&#xff09;。 跨域&#xff08;Cross-Origin Resource Sharing&#xff0c;CORS&#xff09;是浏览器的一项安全功能&#xff…

Illustrator脚本 #015 自动角线

这是一个在画板上自动生成辅助线和角线的脚本,只要单击最右边按钮运行脚本即可。 绿色的为参考线及出血线。 #target "Illustrator" var settings = {addTrim : true,addBleedGuide : true,addCenterGuide : true,addCover : false,overlapAlert : false,trimma…

《数据库开发实践》之触发器

一、什么是触发器&#xff1f; 1.概念&#xff1a; 简单来说触发器就是一种特殊的存储过程&#xff0c;在数据库服务器触发事件的时候会自动执行其SQL语句集。 2.构成四要素&#xff1a; &#xff08;1&#xff09;名称&#xff1a;要符合标识符命名规则 &#xff08;2&am…

理解io/nio/netty

一、io io即input/output&#xff0c;输入和输出 1.1 分类 输入流、输出流&#xff08;按数据流向&#xff09; 字节流&#xff08;InputStream/OutputStream&#xff08;细分File/Buffered&#xff09;&#xff09;、字符流(Reader/Writer&#xff08;细分File/Buffered/pu…

How to Develop Word Embeddings in Python with Gensim

https://machinelearningmastery.com/develop-word-embeddings-python-gensim/ 本教程分为 6 个部分;他们是&#xff1a; 词嵌入 Gensim 库 开发 Word2Vec 嵌入 可视化单词嵌入 加载 Google 的 Word2Vec 嵌入 加载斯坦福大学的 GloVe 嵌入 词嵌入 单词嵌入是一种提供单词的…

git 如何将某个分支的某个提交复制到另外一个分支

请直接去看原文: 原文链接:git 如何将某个分支的某个提交复制到另外一个分支_gitlab里面的markdown文件可以复用其他分支的吗-CSDN博客 --------------------------------------------------------------------------------------------------------------------------------…

删除数据后, redis 内存占用还是很高怎么办?

现象&#xff1a; reids 做了数据删除&#xff0c;数据量不大&#xff0c;使用 top 命令看&#xff0c;发现还是占用大量内存 原因&#xff1a; 1.redis 底层内存根据内存分配器分配&#xff0c;不会立刻释放 2.redis 释放的内存空间不是连续的&#xff0c;存在碎片 内存碎…

算法基础day2

前缀和 #include <iostream> using namespace std; const int N100010; int n,m; int a[N],s[N]; int main() {scanf("%d%d",&n,&m);for(int i1;i<n;i) scanf("%d",&a[i]);for(int i1;i<n;i) s[i]s[i-1]a[i];while(m--){int l,r;s…

HTML-基础知识-基本结构,注释,文档说明,字符编码(一)

1.超文本标记语言不分大小写。 2.超文本标签属性名和属性值不区分大小写。 3.超文本标签属性值重复&#xff0c;听取第一个。 4.html结构 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"vi…

19个Python语法糖和9个内置装饰器

19 个Sweet的 Python Syntax Sugar&#xff0c;用于改善您的编码体验 文章目录 19 个Sweet的 Python Syntax Sugar&#xff0c;用于改善您的编码体验1. 联合运算符Union Operators&#xff1a;合并 Python 字典的最优雅方式2. 类型提示Type Hints&#xff1a;使您的 Python 程序…

常用的几款性能测试软件

&#xff1a; Apache JMeter是一款免费、开源的性能测试工具&#xff0c;广泛应用于Web应用程序和服务的性能测试。它支持模拟多种不同类型的负载&#xff0c;可以测试应用程序在不同压力下的性能表现&#xff0c;并提供丰富的图表和报告来分析测试结果。 优点&#xff1a; …

Python新年炫酷烟花秀代码

新年马上就要到来&#xff0c;烟花秀必须得安排上&#xff01; Pygame 绘制烟花的基本原理 1&#xff0c;发射阶段&#xff1a;在这一阶段烟花的形状是线性向上&#xff0c;通过设定一组大小不同、颜色不同的点来模拟“向上发射” 的运动运动&#xff0c;运动过程中 5个点被赋…

使用pytorch搭建ResNeXt并基于迁移学习训练

冻结除最后全连接层以外的所有权重&#xff0c;只去单独训练它最后一层的的权重&#xff0c;这个方法&#xff0c;冻结了所有网络的权重。 for param in net.parameters():param.requires_grad False

vue+element+springboot实现多张图片上传

1.需求说明 2.实现思路 3.el-upload组件主要属性说明 4.前端传递MultipartFile数组与服务端接收说明 5.完整代码 1.需求说明 动态模块新增添加动态功能,支持多张图片上传.实现过程中对el-upload组件不是很熟悉,踩了很多坑,当然也参考过别的文章,发现处理很…

使用c语言实现DH秘钥分配算法

使用c语言实现DH秘钥分配算法 DH算法原理 密钥分配 选择一个大素数p&#xff0c; 选择一个整数g(g < p)&#xff1b;通信方A选择一个随机数a&#xff0c;并发送 mod p 给 通信方B&#xff1b;通信方B选择一个随机数b&#xff0c;并发送 mod p 给 通信方A&#xff1b;通信…

日常中msvcp120.dll丢失五种解决方法

在日常使用电脑的过程中&#xff0c;我们可能会遇到一些错误提示&#xff0c;其中之一就是“msvcp120.dll丢失”。那么&#xff0c;msvcp120.dll到底是什么&#xff1f;它的作用又是什么呢&#xff1f;为什么会出现丢失的情况呢&#xff1f;本文将为您详细介绍msvcp120.dll的相…

数据结构初阶之顺序表(C语言实现)

数据结构初阶之线性表&#xff08;C语言实现&#xff09; &#x1f34f;前言&#xff1a;&#x1f34f;顺序表和数组的区别&#x1f34f;动态顺序表的模拟实现&#x1f340;动态顺序表的基本结构设计&#x1f340;动态顺序表的各种功能模拟实现&#x1f432; 初始化&#xff08…

兔子目标检测数据集VOC格式3900张

兔子是一类可爱的哺乳动物&#xff0c;拥有圆润的脸庞和长长的耳朵&#xff0c;身体轻盈柔软。它们通常是以温和和友善的形象出现在人们的视野中&#xff0c;因此常常成为童话故事和卡通形象中的角色。 兔子是草食性动物&#xff0c;主要以各种草本植物为食&#xff0c;包括草…
最新文章