数据结构之ArrayList与顺序表(有源码剖析)(一)

简介: 数据结构之ArrayList与顺序表(有源码剖析)(一)

💕"世事犹如书籍,一页页被翻过去。人要向前看,少翻历史旧账。"💕

作者:Mylvzi

文章主要内容:数据结构之顺序表的模拟实现

一.线性表

1.概念

线性表(liner list)是n个具有相同特性元素的有限序列的集合

相同特性指的是一个线性表内部存储的数据类型要都是相同的,可以都是Integer,String也可以是其他的引用类型

常见的线性表有:顺序表,链表,栈,队列

2.性质

 线性表最大特点在于他是一种连续存储数据的结构,其在逻辑上一定是连续的,但是物理上不一定连续,主要是因为线性表既可以通过数组表示,又可以通过链表实现

二.顺序表(ArrayList)

1.概念:

 顺序表是使用物理地址连续的内存存储数据的线性表

2.接口实现

ArrayList中有很多内置的接口,不过这里我们先模拟实现一下

1.顺序表的结构

顺序表最大的特点是它使用"物理地址连续"的内存进行数据的存储,在我们学习过的知识中,数组的存储刚好满足顺序表的特点

// 结构
    public int[] elem;// 使用数组来存储数据
    public int usedsize;// 有效数据个数
    // 初始化顺序表
    // 默认大小
    public static final int DEFAULT_SIZE = 10;
    public MyArrayList() {
        this.elem = new int[DEFAULT_SIZE];
    }
    // 用户指定数组大小
    public MyArrayList(int initCapacity) {
        this.elem = new int[initCapacity];
    }

2.顺序表的添加

 顺序表的添加就是在顺序表中新增一个数据,但是插入的位置要分类讨论,大致上可分为两类:

  • 默认插入:在 顺序表的末尾进行数据的插入
  • 在指定位置进行插入
1.默认插入

 注意在插入数据这样的操作中,要考虑你要插入的容器的容量是否达到最大值,如果达到最大值需要进行扩容,否则就会发生越界访问

// 默认插入
    public void add(int data) {
        // 插入之前要先检查是否需要扩容
        if(isFull()) {
            this.elem = Arrays.copyOf(this.elem,2*this.elem.length);
        }
        // 插入
        this.elem[usedsize] = data;
        this.usedsize++;
    }
    public boolean isFull() {
        // 如果有效的数据个数和数组的长度一致  扩容
        return this.elem.length == usedsize;
    }
2.在指定位置插入数据

要在指定位置插入数据需要考虑的是原有的位置已经存在数据了,要想插入新的数据,就要将插入位置之后的所有元素都往后挪动

图解:

代码实现:

// 在指定位置进行插入
    public void addPos(int pos,int data) {
        // 检查pos是否合法
        if(pos < 0 || pos > this.usedsize) {
            throw new posOutOfBoundException(pos + "位置不合法");
        }
        if(isFull()) {
            this.elem = Arrays.copyOf(this.elem,2*this.elem.length);
        }
        // 挪动数据
        for (int i = this.usedsize-1; i >= pos; i--) {
            this.elem[i+1] = this.elem[i];
        }
        // 插入数据
        this.elem[pos] = data;
        this.usedsize++;
    }

注意:在pos位置插入数据的时候要检查pos是否合法,即不能产生越界访问

3.判断顺序表中是否包含某个元素

 遍历顺序表,包含返回true;不包含,返回false

代码实现:

public boolean contains(int key) {
        for (int i = 0; i < this.usedsize; i++) {
            if (this.elem[i] == key) {
                return true;
            }
        }
        // 没找到
        return false;
    }

4.查找某个元素对应的位置

如果数组包含某个元素,则返回其对应的下标

代码实现:

 

public int indexOf(int key) {
        for (int i = 0; i < this.usedsize; i++) {
            if (this.elem[i] == key) {
                return i;
            }
        }
        System.out.println("数组不包含该元素");
        return -1;
    }

5.获取pos位置的元素

返回pos位置对应的元素

代码实现

public int get(int pos) {
        // 检查pos 的位置是否合法
        if(pos < 0 || pos >= this.usedsize) {
            throw new posOutOfBoundException(pos + "位置不合法");
        }
        return this.elem[pos];
    }

注意:此处要检查pos是否合法,这里的pos最大只能访问到usedSize-1的元素

6.给pos位置的元素设置为value

即更新pos位置的元素

代码实现

public void set(int pos,int value) {
        // 检查pos 的位置是否合法
        if(pos < 0 || pos >= this.usedsize) {
            throw new posOutOfBoundException(pos + "位置不合法");
        }
        this.elem[pos] = value;
    }

7.删除第一次出现的关键字key

遍历顺序表,找到值等于key的元素,删除他(只删除第一次出现的key)

但是该则么删除呢?将要删除的元素设置为0?这显然是行不通的,可以采用"数据覆盖"来进行数据的删除,即应该先找到要删除元素的位置,在从后往前进行数据的覆盖

图解

代码实现

public void remove(int key) {
        // 1.获取key的pos
        int pos = indexOf(key);
        if (pos == -1) {
            System.out.println("没有你要删除的数据!");
            return;
        }
        // 2.挪动数据 进行删除    注意范围
        for (int i = pos; i < this.usedsize-1; i++) {
            this.elem[i] = this.elem[i+1];
        }
        this.usedsize--;
    }

8.获取顺序表的长度

代码实现

public int size() {
        return this.usedsize;
    }

9.清空顺序表

代码实现

// 清空顺序表
    public void clear() {
        // 如果是引用类型 要一一置空
//        for (int i = 0; i < this.usedsize; i++) {
//            this.elem[i] = null;
//        }
        this.usedsize = 0;
    }

10.自定义异常

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 绿字
 */
public class posOutOfBoundException extends RuntimeException{
    public posOutOfBoundException() {
    }
    public posOutOfBoundException(String message) {
        super(message);
    }
}

三.ArrayList简介

在集合框架中,ArrayList是一个普通的类,实现了List接口,具体框架图如下:

源码:


数据结构之ArrayList与顺序表(有源码剖析)(二)+https://developer.aliyun.com/article/1413529

目录
相关文章
|
1月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
137 9
|
1月前
|
存储 搜索推荐 算法
【数据结构】树型结构详解 + 堆的实现(c语言)(附源码)
本文介绍了树和二叉树的基本概念及结构,重点讲解了堆这一重要的数据结构。堆是一种特殊的完全二叉树,常用于实现优先队列和高效的排序算法(如堆排序)。文章详细描述了堆的性质、存储方式及其实现方法,包括插入、删除和取堆顶数据等操作的具体实现。通过这些内容,读者可以全面了解堆的原理和应用。
67 16
|
1月前
|
C语言
【数据结构】二叉树(c语言)(附源码)
本文介绍了如何使用链式结构实现二叉树的基本功能,包括前序、中序、后序和层序遍历,统计节点个数和树的高度,查找节点,判断是否为完全二叉树,以及销毁二叉树。通过手动创建一棵二叉树,详细讲解了每个功能的实现方法和代码示例,帮助读者深入理解递归和数据结构的应用。
107 8
|
1月前
|
存储 Java 索引
Java中的数据结构:ArrayList和LinkedList的比较
【10月更文挑战第28天】在Java编程世界中,数据结构是构建复杂程序的基石。本文将深入探讨两种常用的数据结构:ArrayList和LinkedList,通过直观的比喻和实例分析,揭示它们各自的优势与局限,帮助你在面对不同的编程挑战时做出明智的选择。
|
1月前
|
存储 C语言
【数据结构】手把手教你单链表(c语言)(附源码)
本文介绍了单链表的基本概念、结构定义及其实现方法。单链表是一种内存地址不连续但逻辑顺序连续的数据结构,每个节点包含数据域和指针域。文章详细讲解了单链表的常见操作,如头插、尾插、头删、尾删、查找、指定位置插入和删除等,并提供了完整的C语言代码示例。通过学习单链表,可以更好地理解数据结构的底层逻辑,提高编程能力。
62 4
|
1月前
|
存储 算法 安全
2024重生之回溯数据结构与算法系列学习之顺序表【无论是王道考研人还真爱粉都能包会的;不然别给我家鸽鸽丢脸好嘛?】
顺序表的定义和基本操作之插入;删除;按值查找;按位查找等具体详解步骤以及举例说明
|
1月前
|
存储 C语言
【数据结构】顺序表(c语言实现)(附源码)
本文介绍了线性表和顺序表的基本概念及其实现。线性表是一种有限序列,常见的线性表有顺序表、链表、栈、队列等。顺序表是一种基于连续内存地址存储数据的数据结构,其底层逻辑是数组。文章详细讲解了静态顺序表和动态顺序表的区别,并重点介绍了动态顺序表的实现,包括初始化、销毁、打印、增删查改等操作。最后,文章总结了顺序表的时间复杂度和局限性,并预告了后续关于链表的内容。
65 3
|
1月前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之顺序表习题精讲【无论是王道考研人还真爱粉都能包会的;不然别给我家鸽鸽丢脸好嘛?】
顺序表的定义和基本操作之插入;删除;按值查找;按位查找习题精讲等具体详解步骤以及举例说明
|
1月前
|
C语言
【数据结构】双向带头循环链表(c语言)(附源码)
本文介绍了双向带头循环链表的概念和实现。双向带头循环链表具有三个关键点:双向、带头和循环。与单链表相比,它的头插、尾插、头删、尾删等操作的时间复杂度均为O(1),提高了运行效率。文章详细讲解了链表的结构定义、方法声明和实现,包括创建新节点、初始化、打印、判断是否为空、插入和删除节点等操作。最后提供了完整的代码示例。
43 0
|
2月前
|
存储
数据结构(顺序表)
数据结构(顺序表)
28 0