前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >数据结构与算法系列1之数组介绍与动态数组实现

数据结构与算法系列1之数组介绍与动态数组实现

作者头像
一只胡说八道的猴子
修改2021-02-25 16:14:20
修改2021-02-25 16:14:20
48800
代码可运行
举报
文章被收录于专栏:Java系列学习与数据结构算法
运行总次数:0
代码可运行

数据结构与算法系列1之数组介绍与动态数组实现

数组基本概念介绍

本节讲解顺序

1数组的概念 2数组的定义 2.1动态初始化 2.2静态初始化 3数组中的内存划分 4两个数组指向一个地址 5两个常见问题

1数组的概念

数组是用来存储固定大小的同类型元素。

2数组的定义

2.1动态初始化

代码语言:javascript
代码运行次数:0
复制
1 public class Test {
2     public static void main(String[] args) {
3         int[] arr=new int[100];
4     }
5 }

arr是数组名称 100是数组的大小

2.2 静态初始化

代码语言:javascript
代码运行次数:0
复制
public class Test {
    public static void main(String[] args) {
        int[] arr=new int[] {1,2};
    }
}

该数组大小即为2

3内存角度解析数组

首先简单等等介绍一下java中的内存划分

Java内存主要划分为五部分

1栈(stack):

存放的都是方法中的局部变量,方法的运行一定要在栈中运行, 局部变量:方法的参数,或者是方法{}内部的变量 作用域:一旦超出作用域,立刻从内存中消失

2堆(Heap):

凡是new 出来的东西都在堆里 堆中的东西都有地址值:地址值为16进制 0x开头 堆中的数据都有默认值,规则: 如果是整数 0 如果是布尔 false 如果是浮点数 0.0 如果是引用数据类型 null 如果是字符 “\u000”

3方法区(Method Area):

存储.class相关的信息,包含方法信息

4本地方法栈(Natice Method Stack):

与操作系统相关

5 寄存器(pc Register):

与cpu相关

6.下面用一张图来讲解 java中new一个数组的步骤
代码语言:javascript
代码运行次数:0
复制
1 public class Test {
2     public static void main(String[] args) {
3         int[] arr=new int[3] ;
4         arr[0]=10;
5         arr[1]=20;
6         System.out.println(arr[0]);
7         System.out.println(arr[1]);
8     }
9 }

第一步 int[ ] arr=new int[2]; 数组名称相当于一个存储地址值的变量,指向存储在堆中的int [3] 记住凡是new出来的都在堆里

第二步 arr[0]=10

代码语言:javascript
代码运行次数:0
复制
arr[1]=20

首先通过地址值去堆中找到该数组 在通过下标来判断这是第几个

) 第三步输出

第三步与第二步同理这里就不继续叙述

7. 两个数组指向一个变量

两个数组指向同一个变量,即栈中两个变量存储的值相同

代码语言:javascript
代码运行次数:0
复制
1 public class Test {
2     public static void main(String[] args) {
3         int[] arr=new int[2] ;
4         int[] arr2=arr;
5         System.out.println(arr);
6         System.out.println(arr2);
7     }
8 }

运行结果

内存图解

8.两个常见问题

8.1数组索引越界

代码语言:javascript
代码运行次数:0
复制
public class Test {
    public static void main(String[] args) {
        int[] arr=new int[2] ;
        System.out.println(arr[3]);
    }
}

抛出异常

为了防止越界我们可以引用length方法来解决一些问题方法

代码语言:javascript
代码运行次数:0
复制
public class Test {
    public static void main(String[] args) {
        int[] arr=new int[2] ;
        System.out.println(arr.length);
    }
}

运行结果

8.2 空指针异常

所有的引用类型变量都可以可以赋值为null,这就会导致空指针异常

代码语言:javascript
代码运行次数:0
复制
1 public class Test {
2     public static void main(String[] args) {
3         int[] arr=null ;
4         System.out.println(arr[0]);
5 
6     }
7 }

异常抛出

二维数组

在内存中的存放

二维数组在概念上是二维的,而存储器单元是按一维线性排列的。 如何在一维存储器中存放二维数组,可有两种方式:一种是按行排列, 即放完一行之后顺次放入第二行。另一种是按列排列, 即放完一列之后再顺次放入第二列

以C语言为例 ** 在C语言中,二维数组是按行排列的

例如: int [3][4];

其二维数组示意图如图1所示:

图1 a[3][4]二维数组示意图

在图1中,按行顺次存放,先存放a[0]行,再存放a[1]行,最后存放a[2]行。每行中有四个元素也是依次存放。由于数组a说明为int类型,该类型占4个字节的内存空间,所以每个数组元素均占有4个字节。 假设数组a的起始地址为2000,则该二维数组在内存在的存放方式如图2所示。

图2 a[3][4]二维数组的存放方式

动态数组的实现

什么是动态数组?

动态数组

顾名思义,动态数组即可以动态扩容的数组,一般的数组是不能扩容的,及在创建数组对象的时候就规定了数组的大小,规定数组是多大就是多大,后期不可以存储多余的元素

动态数组的优点

动态数组的好处也显而易见: 1.动态的增加和减少元素 2.实现collection和list接口 3.灵活设置数组的大小 java中已经给我们封装好了一个动态数组Arraylist的类,我们可以直接使用,其内部有许多方法,我们先来看看有什么方法,下面仅仅讲我们经常使用到的方法那些不怎么使用的我们在这就不讲了:

代码语言:javascript
代码运行次数:0
复制
int size();元素的数量
boolean isEmpty();是否为空
boolean contains(E element); 判断是否包含某个元素
void add(E element) ;添加元素到最后
E get(int index);返回index对应位置的元素
E set(int index,E element);往index位置添加元素
void add(int index,E element);往index位置添加元素
E remove(int index); 删除index位置对应的元素
int indexOf(E element); 查看元素的位置
void clear();清除所有元素

接下来我们逐一讲解这些方法

定义的变量

代码语言:javascript
代码运行次数:0
复制
//元素的数量
    private int size;
    //存储元素
    private E[] elements;
    //初始化大小
    private static  final int DEFAULT_CAPACITY=16;
    //元素没有找到时的放回值
    private static  final int ELEMENT_NOT_FOUND=-1;

构造方法

代码语言:javascript
代码运行次数:0
复制
//自定义大小
    public ArrayList(int capacity){
        //如果传入的大小小于默认数组的大小,则使用默认的大下
        capacity= (capacity<DEFAULT_CAPACITY)?DEFAULT_CAPACITY:capacity;
        elements=(E[])new Object[capacity];
    }
    //默认大小的构造方法
    public  ArrayList(){
        this(DEFAULT_CAPACITY);
    }

判断index的范围有没有越界

代码语言:javascript
代码运行次数:0
复制
public void rangeCheak(int index){
        if (index<0||index>size){
            outofBounds(index);
        }
    }

获取指定位置的元素

代码语言:javascript
代码运行次数:0
复制
public E get(int index){
        rangeCheak(index);
        return  elements[index];
    }

重新设定指定位置的元素

代码语言:javascript
代码运行次数:0
复制
public E set(int index,E element){
        //检查插入位置是否合法
        rangeCheak(index);
        //返回原来的元素
        E oldelement1 = elements[index];
        //插入新的元素
        elements[index]=element;
        return oldelement1;
    }

判断是否为空

代码语言:javascript
代码运行次数:0
复制
public boolean isEmpty(){
        return size==0;
    }

返回元素的数量

代码语言:javascript
代码运行次数:0
复制
public int size(){
        return  size;
    }

判断是否包含某个指定元素

代码语言:javascript
代码运行次数:0
复制
public boolean contains(E element){
        return indexOf(element)!=ELEMENT_NOT_FOUND;
    }

返回指定元素的位置

代码语言:javascript
代码运行次数:0
复制
public int indexOf(E element){
     if (element==null){
         for (int i = 0; i < size; i++) {
             if (elements[i]==null){
                 return  i;
             }
         }
     }else{
         for (int i = 0; i < size; i++) {
             if (element.equals(elements[i])){
                 return i;
             }
         }
     }
     return  ELEMENT_NOT_FOUND;
    }

在末尾插入元素

代码语言:javascript
代码运行次数:0
复制
public void add(E element){
        add(size,element);}

在指定位置插入元素

代码语言:javascript
代码运行次数:0
复制
public void   add(int index,E element){
        //检查范围
        rangeCheakForadd(index);
        //判断容量是否足够
        ensureCapacity(size+1);
        for (int i = size; i > index; i--) {
            elements[i]=elements[i-1];
        }
        elements[index]=element;
        size++;
    }

检查插入范围

代码语言:javascript
代码运行次数:0
复制
public void rangeCheakForadd(int index){
        if (index<0||index>size){
            outofBounds(index);
        }
    }

移除指定位置的元素

代码语言:javascript
代码运行次数:0
复制
public  E remove(int index){
        //检查范围
        rangeCheak(index);
        E removeElement = elements[index];
        for (int i=index+1;i<size;i++) {
            elements[i-1]=elements[i];
        }
        elements[--size]=null;
        return removeElement;
    }

清除所有元素

代码语言:javascript
代码运行次数:0
复制
public void clear(){
 for (int i = 0; i < size; i++) {
 elements[i]=null;
 }
 }

其实动态数组最重要的一个方法就是扩容,下面来重点讲解

代码语言:javascript
代码运行次数:0
复制
public void ensureCapacity(int capacity){
        int oldcapacity = elements.length;
        //如果比原来小则不做改变
        if (oldcapacity>= capacity){
            return;
        }
        //使用位运算,速度更快
        //我这里用的是二倍扩容,这里的扩容大小可以自己来设置,以达到最高的使用率
        int newCapacity=oldcapacity+(oldcapacity>>1);
        E[] newElements = (E[]) new Object[newCapacity];
        for (int i = 0; i < size; i++) {
            newElements[i]=elements[i];
        }
        //将elements的地址赋值新的地址
        elements=newElements;
        System.out.println(oldcapacity+"扩容为:"+newCapacity);
    }

复写toString()方法

代码语言:javascript
代码运行次数:0
复制
@Override
    public String toString(){
        //使用StringBuilder
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append('[');
        for (int i = 0; i < size; i++) {
            if (i!=0){
                stringBuilder.append(",");
            }
            stringBuilder.append(elements[i]);
        }
        stringBuilder.append(']');
        return  stringBuilder.toString();
    }
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-02-16 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 数据结构与算法系列1之数组介绍与动态数组实现
  • 数组基本概念介绍
    • 本节讲解顺序
    • 1数组的概念
    • 2数组的定义
      • 2.1动态初始化
      • 2.2 静态初始化
    • 3内存角度解析数组
      • 首先简单等等介绍一下java中的内存划分
  • 二维数组
    • 在内存中的存放
  • 动态数组的实现
    • 什么是动态数组?
      • 动态数组
      • 动态数组的优点
    • 定义的变量
    • 构造方法
    • 判断index的范围有没有越界
    • 获取指定位置的元素
    • 重新设定指定位置的元素
    • 判断是否为空
    • 返回元素的数量
    • 判断是否包含某个指定元素
    • 返回指定元素的位置
    • 在末尾插入元素
    • 在指定位置插入元素
    • 检查插入范围
    • 移除指定位置的元素
    • 清除所有元素
    • 其实动态数组最重要的一个方法就是扩容,下面来重点讲解
    • 复写toString()方法
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档