您的位置:首页 > 汽车 > 新车 > 图片在线制作二维码_深圳燃气公司有哪些_武汉关键词排名提升_建站abc

图片在线制作二维码_深圳燃气公司有哪些_武汉关键词排名提升_建站abc

2024/10/22 17:33:56 来源:https://blog.csdn.net/weixin_43860260/article/details/143024110  浏览:    关键词:图片在线制作二维码_深圳燃气公司有哪些_武汉关键词排名提升_建站abc
图片在线制作二维码_深圳燃气公司有哪些_武汉关键词排名提升_建站abc

1.概述

在计算机科学中,数组是由一组元素(值或变量)组成的数据结构,每个元素有至少一个索引或键来标识

因为数组内的元素是连续存储的,所以数组中元素的地址,可以通过其索引计算出来,例如:

int[] array = {1,2,3,4,5}

知道了数组的数据起始地址 B a s e A d d r e s s BaseAddress BaseAddress,就可以由公式 B a s e A d d r e s s + i ∗ s i z e BaseAddress + i * size BaseAddress+isize 计算出索引 i i i 元素的地址

  • i i i 即索引,在 Java、C 等语言都是从 0 开始
  • s i z e size size 是每个元素占用字节,例如 i n t int int 4 4 4 d o u b l e double double 8 8 8
空间占用

Java 中数组结构为

  • 8 字节 markword(记录了这个对象的 HashCode,分代年龄,锁信息等等)
  • 4 字节 class 指针(压缩 class 指针的情况)
  • 4 字节 数组大小(决定了数组最大容量是 2 32 2^{32} 232
  • 数组元素 + 对齐字节(java 中所有对象大小都是 8 字节的整数倍[^12],不足的要用对齐字节补足)
  • 在这里插入图片描述
随机访问性能

即根据索引查找元素,时间复杂度是 O ( 1 ) O(1) O(1)

2.动态数组

package com.lemon.demo.array;import java.util.Arrays;
import java.util.Iterator;
import java.util.function.Consumer;
import java.util.stream.IntStream;/*** @author 李猛* @datetime 2024/10/17 17:41* @description 动态数组*/
public class DynamicArray implements Iterable<Integer> {private int capacity = 8;//容量,初始容量8private int size = 0;//有效的元素个数,初始个数0private int[] array = new int[capacity];//数组信息/*** 向数组末尾添加元素** @param element*/public void addLast(int element) {add(size, element);}/*** 根据索引位置添加元素** @param index* @param element*/public void add(int index, int element) {if (index < 0 || index > size) {throw new IndexOutOfBoundsException("index:" + index + " error");}//扩容checkAddExpand();System.arraycopy(array, index, array, index + 1, size - index);array[index] = element;size++;}/*** 根据索引获取元素** @param index* @return*/public int get(int index) {if (index < 0 || index >= size) {throw new IndexOutOfBoundsException("index:" + index + " error");}return array[index];}public int remove(int index) {if (index < 0 || index >= size) {throw new IndexOutOfBoundsException("index:" + index + " error");}int element = array[index];if (index == size - 1) {//如果是删除最后一个元素/*** 数组copy* 1.原数组* 2.原数组起始位置* 3.目标数组* 4.目标数组起始位置* 5.要复制的数组元素的数量*/System.arraycopy(array, index + 1, array, index, size - index - 1);}size--;return element;}/*** 扩容*/private void checkAddExpand() {if (capacity == size) {/*** 扩容1.5倍*///capacity = capacity + capacity >> 1;capacity += capacity >> 1;int[] newArray = new int[capacity];System.arraycopy(array, 0, newArray, 0, size);array = newArray;}}/*** 循环遍历** @param consumer*/public void foreach(Consumer<Integer> consumer) {for (int i = 0; i < size; i++) {consumer.accept(array[i]);}}/*** 流遍历** @return*/public IntStream stream() {int[] range = Arrays.copyOfRange(array, 0, size - 1);return IntStream.of(range);}/*** 迭代器** @return*/@Overridepublic Iterator<Integer> iterator() {return new Iterator<>() {int pointer = 0;@Overridepublic boolean hasNext() {return pointer < size;}@Overridepublic Integer next() {return array[pointer++];}};}
}

3.二维数组

int[][] arr = {{11, 12, 13, 14, 15},{21, 22, 23, 24, 25},{31, 32, 33, 34, 35},
};

在这里插入图片描述

  • 二维数组占 32 个字节,其中 array[0],array[1],array[2] 三个元素分别保存了指向三个一维数组的引用

  • 三个一维数组各占 40 个字节

  • 它们在内层布局上是连续

更一般的,对一个二维数组 A r r a y [ m ] [ n ] Array[m][n] Array[m][n]

  • m m m 是外层数组的长度,可以看作 row 行
  • n n n 是内层数组的长度,可以看作 column 列
  • 当访问 A r r a y [ i ] [ j ] Array[i][j] Array[i][j] 0 ≤ i < m , 0 ≤ j < n 0\leq i \lt m, 0\leq j \lt n 0i<m,0j<n时,就相当于
    • 先找到第 i i i 个内层数组(行)
    • 再找到此内层数组中第 j j j 个元素(列)

4.缓存与局部性原理

这里只讨论空间局部性

  • cpu 读取内存(速度慢)数据后,会将其放入高速缓存(速度快)当中,如果后来的计算再用到此数据,在缓存中能读到的话,就不必读内存了
  • 缓存的最小存储单位是缓存行(cache line),一般是 64 bytes,一次读的数据少了不划算啊,因此最少读 64 bytes 填满一个缓存行,因此读入某个数据时也会读取其临近的数据,这就是所谓空间局部性
定义两个求和方法
public static void sum1(int[][] arr, int rows, int columns) {long sum = 0;for (int i = 0; i < rows; i++) {for (int j = 0; j < columns; j++) {sum += arr[i][j];}}System.out.println("sum1:" + sum);
}
public static void sum2(int[][] arr, int rows, int columns) {long sum = 0;for (int j = 0; j < columns; j++) {for (int i = 0; i < rows; i++) {sum += arr[i][j];}}System.out.println("sum2:" + sum);
}

比较下面 s u m 1 sum1 sum1 s u m 2 sum2 sum2 两个方法的执行效率

int rows = 1000000;
int columns = 14;
int[][] a = new int[rows][columns];StopWatch sw = new StopWatch();sw.start("sum1");
sum1(a, rows, columns);
sw.stop();sw.start("sum2");
sum2(a, rows, columns);
sw.stop();System.out.println(sw.prettyPrint());

执行结果
在这里插入图片描述
可以看到 s u m 1 sum1 sum1 的效率比 s u m 2 sum2 sum2 快很多,为什么呢?

  • 缓存是有限的,当新数据来了后,一些旧的缓存行数据就会被覆盖
  • 如果不能充分利用缓存的数据,就会造成效率低下

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com