数组--java--动态数组--有序数组--底层

news2025/1/15 19:45:17

java数组

  • 基础--java中的数组
    • 创建数组
    • 空间占用
    • 初始化数组
    • 访问元素
    • 插入查找
    • 删除元素
  • 动态数组
    • 扩容
    • 插入和添加
    • 重写toString
    • 删除
  • 二维数组
    • 二维数组注意点
  • 有序数组
    • 实现
    • 测试


写在开头:


这篇文章包括数组的基础、一点底层的内容和一些稍微深入的东西。
作为第一个深入学习的数据结构,现在还不太知道怎么样了。有缺点请指出。
还有内容之后在补充。
本来是想和ArrayList源码一起来写进来的,但是发现实在不好插入进来了。还是到时候换一篇文章写了。

基础–java中的数组

数组是应用最广泛的数据存储结构。

因为里面元素是连续存储的,所以数组中的元素的地址可以用索引计算出来。
i i i个元素的地址: a d d r e s s = b a s e A d d r e s s ( 起始索引 ) + i ∗ s i z e address = baseAddress(起始索引) + i*size address=baseAddress(起始索引)+isize
size是每一个元素所占的字节大小,如int占4,double占8

在许多语言中都把数组当作基本数据类型,但是在java中是把他们当作对象来对待的,所以在创建数组的时候使用new关键字。

创建数组

我们一般会把[]放在类型后面,清晰的代表着数据类型的一部分

int[] arr = new int[n];

像大部分的对象一样,arr只是作为存储这个对象的地址值。且大小固定,一旦创建就不可修改

空间占用

用int来介绍

  • 8字节的markword:记录对象的hash码等状态信息。这个具体会在java类介绍中。
  • 4字节的类指针:指定这个对象的类型,数据指向类的字节码文件。
  • 4字节的数组大小:所以最高 2 32 2^{32} 232的容量
  • 数据元素+对其字节:内存对齐

初始化数组

创建数组后

  • 如果是基本数据类型会自动初始化数组

  • 如果是引用类型,则他们会是特殊的null对象

     如果尝试访问null的数据项,会出现Null Point Assignment(空指针赋值错误)
    

对于基本数据类型我们还可以通过{}来初始并创建数组

int[] arr= {1,2,3};

访问元素

第一个元素下标为0,所以容量为10的数组,下标为0-9.
越界访问会出现Array Index Out Of Bounds(数组越界错误)错误

插入查找

在n位置设置为num

arr[n]=num;

查询n位置的数

System.out.println(arr[n]);

删除元素

删除第n个元素
想要删除的话,将n后面的元素全部往前一个就可以了。

for(int i = n-1;i<arr.length-1;i++{
	arr[i]=arr[i+1]
}
arr[arr.length-1]=0;

动态数组

因为普通数组,大小是写死的。很不方便,所以我们需要动态数组。
在java中有ArrayList类是已经实现了动态数组了。

这里介绍的是手写动态数组,但是不考虑泛型,只用整形数字

想要实现动态数组,那么我们需要一些属性来标记

  • 数组:我们需要一个基本数组来存储。
  • 大小:我们需要记录数组已经存储了的大小。
  • 容量:记录数组的大小,在不够用的时候进行扩容处理。
public class Array{
	private int size = 0;
	private int capacity = 8;
	private int[] array = new int[capacity];
}

添加
这个应该是用的最多的,所以我们先设计这个。
在不考虑扩容的情况下,在最后设置成element,大小加一就可以了。

public void add(int element){
	array[size] = element;
	size++;
}

插入
实现在index位置插入element:
我们需要将index之后的元素往后移动一位就可以实现了

public void insert(int index,int element){
	System.arraycopy(array,index,array,index+1,size-index);
	array[index]=element;
}	

我们需要对其进行容量判断,并实现扩容。

扩容

为了节省空间,在需要使用的时候在给数组空间。

private int[] array={};

对于扩容我们首先判断容量是否是0。

public void grow(){
	if(array.length > 0){
		capacity += capacity>>1;
		array = Arrays.copyOf(array,capacity);
	}else{
		capacity = 8;
		array = new int[capacity];
	}
}

插入和添加

然后我们可以改进我们的代码了。
是否满

private boolean isFull(){
	return size == capacity;
}

在index位置插入元素

public void insert(int index, int element){
    if (isFull()){//判断是否需要扩容
        grow();
    }
    if (index < 0 || index > size){//判断index是否合法
        throw new IndexOutOfBoundsException("Index: " + index + ", Size " + size);
    }
    System.arraycopy(array, index, array, index + 1, size - index);//将index后面的元素往后移动
    array[index] = element;
    size++;
}

在最后位置添加就可以复用代码了。

public void add(int element){
   insert(size,element);
}

测试:
测试代码中重写了toString方法,在下一节有。
在这里插入图片描述

重写toString

我们需要toString方法输出的只是我们的数组就可以了,所以这里需要重写toString方法。
这里建议使用append字符,而不是字符串,效率高。

@Override
public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append('[');
    for (int i = 0; i < size-1; i++) {
        sb.append(array[i]).append(',').append(' ');
    }
    sb.append(array[size-1]);
    sb.append(']');
    return sb.toString();
}

删除

将index索引位置元素删除:

  • 去除index索引元素
  • 后面元素前移
public int remove(int index){
    //判断index是否合法
    if (index < 0 || index >= size) {
        throw new IndexOutOfBoundsException("Index: " + index + ", Size " + size);
    }
    int oldValue = array[index];//去除元素
    int numMoved = size - index - 1;//查看后面元素的数量
    if (numMoved > 0)
        System.arraycopy(array, index+1, array, index,
                numMoved);//将后面的元素往前移动
    array[--size] = 0; // clear to let GC do its work
    return oldValue;//返回删除的元素
}

二维数组

创建数组

int[][] array = new int[2][2];

初始化

int[][] arry = {
	{1,2,3},
	{2,3,4}
};

二位数组的实现:
起始就是一个数组存储着各种数组的地址值。
二维数组的实现

二维数组注意点

因为有缓存机制的影响,所以我们尽量在遍历的时候同一层的使用如:
int[x][y]

for(int i = 0;i<x;i++)
	for(int j = 0;j<y;j++)
		。。。

这样子速度会更快。

有序数组

在有序数组中,因为查询位置则会成为重点。所以我们会选择二分查询来加快速度。但不会书写二分查询的代码,而是直接调用API,不过需要学习的可以点击链接去看看。而动态数组中的内容也不在重复。
有序数组需要在动态数组的基础上实现。
很多也是复用了代码。
下面是不同点:

  • 对于给定位置插入和删除,我们不再对外公开所以权限给位private
  • 查询使用的Arrays的二分查询的api
  • 不用在判断位置是否合法了

实现

private int size = 0;
private int capacity = 0;
private int[] array = {};

//扩容
public void grow() {
    if (array.length > 0) {
        capacity += capacity >> 1;
        array = Arrays.copyOf(array, capacity);
    } else {
        capacity = 8;
        array = new int[capacity];
    }
}

//插入数据
private void insert(int index, int element) {
    if (isFull()) {//判断是否需要扩容
        grow();
    }
    if (index < 0 || index > size) {//判断index是否合法
        throw new IndexOutOfBoundsException("Index: " + index + ", Size " + size);
    }
    System.arraycopy(array, index, array, index + 1, size - index);//将index后面的元素往后移动
    array[index] = element;//插入元素
    size++;
}

public void add(int element) {
    if (isFull()) {//判断是否需要扩容
        grow();
    }
    //二分查找元素应该插入的位置
    int i = Arrays.binarySearch(array, 0, size, element);
    if (i < 0) {
        i = -i - 1;
    }
    insert(i, element);
}

private boolean isFull() {
    return size == capacity;
}

public boolean delete(int index) {
    int i = Arrays.binarySearch(array, 0, size, index);
    if (i<0){
        return false;
    }
    remove(i);
    return true;
}
private void remove(int index) {
    int numMoved = size - index - 1;//查看后面元素的数量
    if (numMoved > 0)
        System.arraycopy(array, index + 1, array, index,
                numMoved);//将后面的元素往前移动
    array[--size] = 0; // clear to let GC do its work
}

@Override
public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append('[');
    for (int i = 0; i < size - 1; i++) {
        sb.append(array[i]).append(',').append(' ');
    }
    sb.append(array[size - 1]);
    sb.append(']');
    return sb.toString();
}

测试

在这里插入图片描述

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

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

相关文章

【2021.12.25】ctf逆向中常见加密算法和编码识别

【2021.12.25】ctf逆向中常见加密算法和编码识别&#xff08;含exe及wp&#xff09; 文章目录【2021.12.25】ctf逆向中常见加密算法和编码识别&#xff08;含exe及wp&#xff09;0、前言1、基础加密手法2、base64&#xff08;1&#xff09;原理&#xff1a;&#xff08;2&#…

利用出厂状态下的闲置主机配置HP M1136打印机

利用出厂状态下的闲置主机配置HP M1136打印机 打印机型号&#xff1a;LaserJet M1136 MFP 主机状态&#xff1a;出厂状态&#xff0c;C盘及储存盘被分成了5片 网络环境&#xff1a;与打印机相连的主机全程无Internet连接&#xff0c;主机处于离线状态。打印机驱动及一些相关软…

Splunk 成功获取Salesforce 数据

1: 先说一下Splunk server 上要安装Splunk Add-on for Salesforce : (https://splunkbase.splunk.com/) 去下载: https://splunkbase.splunk.com/app/3549 2: 下载安装后,看到如下界面: 3: 官方的指导文档: Configure your Salesforce account to collect data…

0301_对应的南京比特物联网

0301_对应的南京比特物联网目录概述需求&#xff1a;设计思路实现思路分析1.流程拓展实现性能参数测试&#xff1a;参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better …

C#的Version类型值与SQL Server中二进制binary类型转换

使用C#语言编写的应用程序可以通过.NET Framework框架提供的Version类来控制每次发布的版本号&#xff0c;以便更好控制每次版本更新迭代。 版本号由两到四个组件组成&#xff1a;主要、次要、内部版本和修订。 版本号的格式如下所示&#xff0c; 可选组件显示在方括号 ([ 和…

UML 时序图

时序图&#xff08;Sequence Diagram&#xff09;是显示对象之间交互的图&#xff0c;是按时间顺序排列的。 时序图中显示的是参与交互的对象及其对象之间消息交互的顺序。 时序图包括的建模元素主要有&#xff1a;对象&#xff08;Actor&#xff09;、生命线&#xff08;Lif…

项目实战典型案例19——临时解决方案和最终解决方案

临时解决方案和最终解决方案一&#xff1a;背景介绍二&#xff1a;思路&方案四&#xff1a;总结五&#xff1a;升华一&#xff1a;背景介绍 本篇博客是对项目开发中出现的临时解决方案和最终解决方案进行的总结和改进。目的是将经历转变为自己的经验。通过博客的方式分享给…

(蓝桥真题)最长不下降子序列(权值线段树)

样例输入&#xff1a; 5 1 1 4 2 8 5 样例输出&#xff1a; 4 分析&#xff1a;看到这种对其中连续k个数进行修改的我们就应该想到答案是由三部分组成&#xff0c;因为求的是最长不下降子序列&#xff0c;那么我们可以找到一个最合适的断点i&#xff0c;使得答案是由区间[1…

【信息安全案例】——网络信息面临的安全威胁

&#x1f4d6; 前言&#xff1a;2010年&#xff0c;震网病毒&#xff08;Stuxnet&#xff09;席卷全球工业界。其目标是从物理上摧毁一个军事目标&#xff0c;这使得网络武器不仅仅只存在于那个人类创造的空间。网络武器的潘多拉魔盒已经打开。 目录&#x1f552; 1. 信息、信息…

28个精品Python爬虫实战项目

先来说说Python的优势&#xff01;然后给大家看下这28个实战项目的实用性&#xff01;Python跟其他语言相比&#xff0c;有以下优点&#xff1a;1. 简单Python是所有编程语言里面&#xff0c;代码量最低&#xff0c;非常易于读写&#xff0c;遇到问题时&#xff0c;程序员可以把…

学习 Python 之 Pygame 开发魂斗罗(八)

学习 Python 之 Pygame 开发魂斗罗&#xff08;八&#xff09;继续编写魂斗罗1. 创建敌人类2. 增加敌人移动和显示函数3. 敌人开火4. 修改主函数5. 产生敌人6. 使敌人移动继续编写魂斗罗 在上次的博客学习 Python 之 Pygame 开发魂斗罗&#xff08;七&#xff09;中&#xff0…

通信网络-Socket、Java中的网络支持、多线程服务器

前言 通信网络-Socket、Java中的网络支持、多线程服务器 场景&#xff1a;使用java网络创建一个聊天室 博客地址&#xff1a;芒果橙的个人博客 文章目录前言通信网络-SocketTCP/IPTCP/IP 模型端口Java中的网络支持概念1. InetAddress2. URL3. Socket4. Datagram多线程服务器应用…

使用ECharts打造一个数据可视化面板

使用ECharts打造一个数据可视化面板1. 使用技术2. 案例适配方案3. 基础设置4. header 布局5. mainbox 主体模块6. 公共面板模块 panel7. 柱形图 bar 模块&#xff08;布局&#xff09;8. 中间布局9. ECharts 介绍10. ECharts 体验11. ECharts 基础配置12. 柱状图图表&#xff0…

MDK软件使用技巧

本文主要汇总MDK软件使用技巧 一、字体大小及颜色修改 第一步点击工具栏的这个小扳手图标 进去后显示如下&#xff0c;先设置 Encoding 为&#xff1a;Chinese GB2312(Simplified)&#xff0c;然后设置 Tab size 为&#xff1a;4 以更好的支持简体中文&#xff0c;否则&…

Java 多线程 --- 线程协作 wait/notify

Java 多线程 --- 线程协作 wait/notifywait / notifyObject.wait() , Object.notify() / notifyAll()notify 和 wait 的原理notify会导致死锁的问题wait / notify的开销以及问题wait / notify 在多线程中, 如果程序拿到锁之后, 但是没有满足指定条件而不能继续往下执行, 我们可…

外网用户打不开公司的网站?web服务器端口映射到公网

我们经常会遇到这样的情景&#xff0c;在公司内部可以打开公司的网站&#xff0c;在家里或者外网却打不开&#xff0c;按照网上的做法&#xff0c;重新启动了服务器和iis&#xff0c;还是不行。许多用户设置了路由器端口映射功能&#xff0c;但是端口映射不成功怎么办&#xff…

2023河南新乡市第二届职业技能大赛“网络安全”项目B模块比赛任务书

2023河南新乡市第二届职业技能大赛“网络安全”项目 比赛任务书一、竞赛时间二、竞赛阶段及内容B-1 Windows操作系统渗透测试B-2 Wireshark数据包分析B-3 CMS网站渗透B-4 未公开B-5 未公开一、竞赛时间 总计&#xff1a;180分钟 二、竞赛阶段及内容 &#xff08;一&#xff…

嵌入式系统实验——【玄武F103开发板】实现两个LED小灯闪烁

目录一、实验文件main.cstm32f10x.h二、实验思路&#xff08;一&#xff09;打开两个LED小灯1.在玄武F103开发板上找到LED0、LED1对应的GPIO控制寄存器2.找到GPIOB、GPIOE的地址3.打开APB2外设时钟的使能寄存器4.对GPIO寄存器进行设置对端口输出寄存器进行设置&#xff08;二&a…

Go语言基准测试(benchmark)三部曲之三:提高篇

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos 本篇概览 -《Go语言基准测试(benchmark)三部曲》已近尾声&#xff0c;经历了《基础篇》和《内存篇》的实战演练&#xff0c;相信您已熟练掌握了基准测试的常…

Spring Security 实现自定义登录和认证(1)

1 SpringSecurity 1.1 导入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId> </dependency>1.2 编写配置类 在spring最新版中禁用了WebSecurityConfigurerAdapter…