程序界流传一种说法:程序 = 数据结构 + 算法。 虽然这种说法过于简洁,但也从某种角度说明了程序的本质,指明了数据结构的重要性。
算法代表了程序的逻辑,数据结构代表了数据的组织形式。
什么是数据结构?
百度百科:数据结构是指相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成。
简单的讲就是能将一批具有业务相关性的数据元素存储在一块的容器。
java中的主要的数据结构有哪些?
数组、集合、Map。
数组:
概念:数组是指一组数据的集合,数组中的每个数据称为元素。
目的:存储一批数据元素,这些数据元素可以是任何数据类型。
原理:在内存中开辟一块固定长度的连续的内存块,这块内存初分成指定份数,每份保存一个业务数据。就像一个连续的格子,每个格子有一个下标值(相当于内存起始位置的偏移量),通过这个下标快速查询到指定的格式。
示例:
/**
* 创建一个容量为5的数组,并存储:100,22,40,9,87 5个数字
*/
int[] nums = new int[5];
nums[0] = 100;
nums[1] = 22;
nums[2] = 40;
nums[3] = 9;
nums[4] = 87;
大概如下:
A:从内存中找到一块连续的空间
B:根据数据类型,创建一个指定长度(此处为5),且每个“格子”为数据类型大小(此处为int的长度)的内存。
C:从申请的内存起始位置,为每个“格式” “标注”一个下标(偏移量)
D:把数据按下标编号,存入到指定的格式子中
数组中数据元素的数据类型
听起来很拗口,其实就是数组中存储的元素的数据类型。
数组的目是是存储数据,但是并未说清楚到底存储什么类型的数据。是存储字符串还是存储数字还是对象?
既然数组没有指明存储什么类型的数据,说明数组可以存储任何类型的数据。事实上也确实如此,数组可以存储任何数据类型,具体如下:
8种基本类型: byte、short、int、long、float 、double、char、boolean
字符串类型:String
对象:Object(任何对象:字符串、自定义对象、数组等)
数组中每个元素的长度
通过上面的分析知道,数组是提前分配空间的,而数组存储的数据类型又不定,那么数组中的每个元素应该提前分配多长呢?
分配的太长,浪费空间,分配的太短又存储不下。
int[] nums = new int[5];
String[] names = new String[10];
Double[] a = new Double[2];
Object[] b = new Object[5];
上面创建了基本类型数组,字符串类型数组,Double封装类型数组,Object类型数组。
大家会发现每种类型的数组都指明了数组的数据类型,即数组必须知道自己将存储什么类型的数据,以方便分配指定大小的空间。
总结来说,只有两种类型:基本类型和对象两种数据类型。
基本类型:基本类型数组存储的是最终的数值,因此元素“格子”的大小即基本类型的大小。
对象类型:存储的是对象的引用(相当于其它语言中的“指针”),而任何对象的引用长度是固定的,因此元素“格子”的大小即对象引用的大小。
这样,数组就解决了提前分配置空间时每个元素“格子”大小的问题。
数组初始化
数组也是对象,创建数组时,数组中的元素会自动初始化初,那么不动类型的的元素如何初始化?
数组元素有两种类型:基本类型和对象;
对象:存储的是引用,与普通对象初始化一样:初始值为 null;
基本类型:与普通的基本类型初始一样,不同类型值不太一样,具体如下:
byte/short/int/long 0
float 0.0f
double 0.0d
char '\u0000'
boolean false
数组的边界
数组在声明时已指定了长度,这个长度即数组的最大边界,数组的边办为:0-N。超过或小于这个下标即超过了数组的边界,会报ArrayIndexOutOfBoundsException异常。
数组的扩容
数组在声明时已指定了长度,但在实际业务中可能会不够,此时就要扩容数组。 我们知道数组是一开始就提前分配好空间的,而且这个空间必段是连续的,这些导致很难在原有数组后面继续开辟一块连续的数组,因此java中数组是不能扩容的,只能重新声明一个新数组,再把原来的值复制到新数组中。
数组的操作
数组是用来存储数据的,但如果仅仅存储不使用,那么存储也就没有意义。因此在实际业务中我们使用数组存储数据,同时会对存储的元素进行操作,主要的操作如下:
增:向数组中添加元素。如:a[2] = 5; 如果不覆盖原来的值,需要a[2]及后面的值先向后移动空出位置,再设置值。否则为覆盖。
删:删除元素;如:a[2]=0; a[3]=null;
改: 更改指定下标元素的值;如:a[2] = 2; a[2]=3;覆盖原来的值。
查:获取指定下标的元素值;如:int age = a[2];
数组的优缺点
优点:
由于数组是连续的内存块,可以通过下标精确定位,因此查询速度非常高。
缺点:
由于数组是连续的内存块,因此无法直接在原数组上扩容。
现数组中插入元素(不覆盖原有数)速度较慢(因为需要移动数据),同理删除也一样。
如下图:向下标为1的数组中插入数字8,需要3次移动和1次赋值才完成整个插入操作。如果赋值位置后面数据量越大,复杂度越大