1. 数组的定义
- 数组Array是一种 线性表 数据结构。 它用一组 连续的内存空间,来存储一组具有 相同类型的数据。 数组支持随机访问,根据下标随机访问的时间复杂度为 O(1)。
2. 低效的“插入”和“删除”
-
假设数组的长度为n, 讲一个数据插入到数组的第k个位置
- 最优时间复杂度 O(1)
- 最坏时间复杂度 O(n)
- 平均时间复杂度 O(n)
-
如果数组中存储的数据没有任何规律, 可以把要插入位置的元素和最后一个(指定位置)元素互换,时间复杂度为O(1)
-
数组的删除和插入类似, 最后时间复杂度为O(1), 最坏时间复杂度为O(n), 平均时间复杂度为O(n)
-
JVM 标记清除垃圾回收算法的核心思想
-
大多数主流虚拟机采用可达性分析算法来判断对象是否存活,在标记阶段,会遍历所有 GC ROOTS,将所有 GC ROOTS 可达的对象标记为存活。只有当标记工作完成后,清理工作才会开始。
-
不足:1.效率问题。标记和清理效率都不高,但是当知道只有少量垃圾产生时会很高效。2.空间问题。会产生不连续的内存空间碎片。
-
3. 警惕数组访问越界问题
4. 用数组什么情况更合适
- Java ArrayList 无法存储基本类型,比如 int、long,需要封装为 Integer、Long 类,而 Autoboxing、Unboxing 则有一定的性能消耗,如果特别关注性能,或者希望使用基本类型,就可以选用数组
- 如果数据大小事先已知, 并且对数据的操作非常简单, 用不到ArrayList提供的大部分方法, 也可以直接使用数组
- 当要表示多维数组时,用数组往往会更加直观
5. 二维数组内存寻址:
- 对于 m * n 的数组,a [ i ][ j ] (i < m,j < n)的地址为:address = base_address + ( i * n + j) * type_size
int main(int argc, char* argv[]){
int i = 0;
int arr[3] = {0};
for(; i<=3; i++){
arr[i] = 0;
printf("hello world\n");
}
return 0;
}
对于死循环那个问题,要了解栈这个东西。栈是向下增长的,首先压栈的i,a[2],a[1],a[0],这是我在我vc上调试查看汇编的时候看到的压栈顺序。相当于访问a[3]的时候,是在访问i变量,而此时i变量的地址是数组当前进程的,所以进行修改的时候,操作系统并不会终止进程。
6. 代码部分
6.1. Array的基本操作
- Java版本
/**
* @author xiaofan
* 1.数组的插入、删除、按照下标随机访问操作
* 2.数组中的数据时int类型的
*/
public class ArrayJavaDemo {
// 定义整形数据data保存类型
public int data[];
// 定义数组中元素实际个数
private int size;
// 构造方法定义数组大小
public ArrayJavaDemo(int capacity) {
this.data = new int[capacity];
this.size = 0;
}
// 根据索引找到指定的元素并返回
public int find(int index) {
if(index < 0 || index >= size) return -1;
return data[index];
}
// 插入元素,头部插入,尾部插入
public boolean insert(int index, int value) {
// 数组空间已满
if(size == data.length) {
System.out.println("没有可以插入的位置");
return false;
}
// 位置不合法
if(index < 0 || index > size) {
System.out.println("位置不合法");
return false;
}
// 位置合法
for(int i = size; i > index; --i) {
data[i] = data[i - 1];
}
data[index] = value;
++size;
return true;
}
// 根据索引删除数组中的元素
public boolean delete(int index) {
if(index < 0 || index >= size) return false;
for(int i = index + 1; i < size; i++) {
data[i - 1] = data[i];
}
--size;
return true;
}
// 打印数组
public void printAll() {
for (int i = 0; i < size; ++i) {
System.out.print(data[i] + " ");
}
System.out.println();
}
public static void main(String[] args) {
ArrayJavaDemo array = new ArrayJavaDemo(5);
array.printAll();
array.insert(0, 3);
array.insert(0, 4);
array.insert(1, 5);
array.insert(3, 9);
array.insert(3, 10);
int res = array.find(5);
System.out.println(res);
array.printAll();
}
}
- Scala版本
class ArrayDemo(capacity: Int) {
var data: Array[Char] = new Array[Char](capacity)
// 数组中元素的实际个数
var length: Int = 0
def find(index: Int): Char = {
if(index < 0 || index >= length) {
return (-1).toChar
}
data(index)
}
def insert(index: Int, value: Char): Boolean = {
if(length == capacity) {
return false
}
if(index < 0 || index >= capacity) {
return false
}
// 注意: 取不到until后面的值,可以指定步长
for(i <- length until index by -1) {
data(i) = data(i - 1)
}
data(index) = value
length += 1
true
}
def delete(index: Int): Char = {
if(length == 0) {
throw new IllegalStateException("array is empty")
}
if(index >= length) {
throw new IllegalStateException("index out of range, current data length is" + length)
}
val result = data(index)
for(i <- index until length - 1) {
data(i) = data(i + 1)
}
length -= 1
result
}
def print: Unit = {
println(data.subSequence(0, length).toString)
}
}
object ArrayDemo {
def main(args: Array[String]): Unit = {
val arrDemo = new ArrayDemo(5)
arrDemo.insert(0, 'a')
arrDemo.insert(1, 'b')
arrDemo.insert(2, 'c')
arrDemo.insert(3, 'd')
arrDemo.insert(4, 'e')
arrDemo.print
}
}
- Python版本
class MyArray:
def __init__(self, capacity: int):
self._data = []
self._capacity = capacity
def __getitem__(self, item, position: int) -> object:
return self._data[position]
def __setitem__(self, index: int, value: object):
self._data[index] = value
def __len__(self) -> int:
return len(self._data)
def __iter__(self):
for item in self._data:
yield item
def find(self, index: int) -> object:
try:
return self._data[index]
except IndexError:
return None
def delete(self, index: int) -> bool:
try:
self._data.pop(index)
return True
except IndexError:
return False
def insert(self, index: int, value: int) -> bool:
if len(self) >= self._capacity:
return False
else:
return self._data.insert(index, value)
def print_all(self):
for item in self:
print(item)
if __name__ == '__main__':
array = MyArray(5)
array.insert(0, 3)
array.insert(0, 4)
array.insert(1, 5)
array.insert(3, 9)
array.insert(3, 10)
assert array.insert(0, 100) is False
assert len(array) == 5
assert array.find(1) == 5
assert array.delete(4) is True
array.print_all()
6.2. GenericArray
- Java版本
public class GenericArray<T> {
private T[] data;
private int size;
public GenericArray(int capacity) {
this.data = (T[]) new Object[capacity];
this.size = 0;
}
public GenericArray() {
this(10);
}
// 数组容量
public int getCapacity() {
return this.data.length;
}
// 当前元素个数
public int count() {
return this.size;
}
// 判断数组是否为空
public boolean isEmpty() {
return size == 0;
}
// 修改index位置的元素
public void set(int index, T e) {
checkIndex(index);
data[index] = e;
}
// 获取对应index位置的元素
public T get(int index) {
checkIndex(index);
return data[index];
}
// 查看数组是否包含元素
public boolean contains(T e) {
for (int i = 0;i < size; i ++) {
if (data[i].equals(e)) {
return true;
}
}
return false;
}
// 获取对应元素的下标,未找到, 返回-1
public int find(T e) {
for ( int i = 0; i < size; i++) {
if (data[i].equals(e)) {
return i;
}
}
return -1;
}
// 在index位置, 插入元素e,时间复杂度为O(m+n)
public void add(int index, T e) {
checkIndex(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 ++;
}
// 向数组头插入元素
public void addFirst(T e) {
add(0, e);
}
// 向数组头插入元素
public void addLast(T e) {
add(size, e);
}
// 删除index位置的元素,并返回
public T remove(int index) {
checkIndexForRemove(index);
T 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;
}
// 删除第一个元素
public T removeFirst() {
return remove(0);
}
// 从数组中删除指定元素
public void removeElement(T e) {
int index = find(e);
if (index != -1) {
remove(index);
}
}
// 删除末尾元素
public T removeLast() {
return remove(size - 1);
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(String.format("Array size = %d, capacity = %d \n", size, data.length));
builder.append('[');
for (int i = 0; i < size; i++) {
builder.append(data[i]);
if (i != size - 1) {
builder.append(", ");
}
}
builder.append(']');
return builder.toString();
}
// 扩容方法,时间复杂度O(n)
private void resize(int capacity) {
T[] newData = (T[]) new Object[capacity];
for (int i = 0;i < size;i ++) {
newData[i] = data[i];
}
data = newData;
}
private void checkIndex(int index) {
if(index < 0 || index > size) {
throw new IllegalArgumentException("Add failed! Require index >=0 and index <= size.");
}
}
private void checkIndexForRemove(int index) {
if(index < 0 || index >= size) {
throw new IllegalArgumentException("remove failed! Require index >=0 and index < size.");
}
}
public static void main(String[] args) {
GenericArray<String> arr = new GenericArray<String>();
arr.add(0, "100");
arr.add(0, "200");
arr.add(0, "300");
arr.add(0, "400");
arr.addFirst("e");
System.out.println(arr);
}
}