八大数据结构——数组(一)
数据结构定义(百度解释): 数据结构(data structure)是带有结构特性的数据元素的集合,它研究的是数据的逻辑结构和数据的物理结构以及它们之间的相互关系,并对这种结构定义相适应的运算,设计出相应的算法,并确保经过这些运算以后所得到的新结构仍保持原来的结构类型。
(就是你打算以什么形式放数据,是铺开丢地板上,还是靠墙堆起来,大概这样的意思。)
常用的主要有八大类型:1.数组(Array)2.栈(Stack)3.链表(Linked List)4.图(Graph)5.散列表(哈希表)(Hash)6.队列(Queue)7.树(Tree)8.堆(Heap)。
数组定义(百度解释):
数组是在程序设计中,为了处理方便, 把具有相同类型的若干元素按有序的形式组织起来的一种形式。 这些有序排列的同类数据元素的集合称为数组。
(这里的有序,不要理解成数据是按从小到大,或某种规律给你排好序,想多了!数组作为最简单的数据结构,才不给你干那么多事。有序你可以理解为连续的意思。)
特性:
1.数组是连续分配的一段地址空间。
2.数组存储的是相同类型的数据。
3.初始化分配后,大小是固定的。
优点:
1.查询和修改的速度快,直接通过索引就完成,注意是修改,不是增加和删除。
缺点:
1.初始化后,分配的空间就固定了。所以超了就没法塞咯。
2.增加和删除的速度慢,因为要保持连续性,中间删除一个元素,后面的元素要往前移,就是不许有中断的意思。
3.只能保存相同数据类型,声明是什么类型数组,就只能保存什么类型。
适用场景:
频繁查询,对存储空间要求不大,很少增加和删除的情况。
java代码实现
下面通过Java来实现一个ArrayList,就是一个动态数组。基于jdk1.8.
首先,要有一个数组用来存储数据。其次要有一个指针来记录已使用的空间。再定义一个默认大小。这些属性应该都是私有的,不能被外部直接更改。
private Type[] elements;//存储数据单元
private int size;//当前指针位置
private static final int Default_size = 10;//默认大小
然后是构造方法。提供有参数和无参数两种,最好是使用有参数的,告诉系统你想要多大空间。容量不够时,要进行扩容操作,非常消耗资源。
public ArrayList() {//无大小参数的默认构造方法
elements = (Type[])new Object[Default_size];
size = 0;
}
public ArrayList(int sz) {//传入大小参数的构造方法
elements = (Type[])new Object[sz];
size = 0;
}
清空数组直接让指针变0就可以了,表示此时数组内无元素,但实际之前的数据还在,只是不给访问了。
public void clear() {//清空数组,实际是把指针调到初始位置,之前数据在未被覆盖前依然存在
size = 0;
}
查询操作,没啥特别,就是按照索引返回。
public Type get(int index) {//返回索引值为index的元素,index若大于等于size,或小于0,则抛出异常
if(index>=size||index<0) {
throw new ArrayIndexOutOfBoundsException();
}
return elements[index];
}
修改操作,也没啥特别的,就是按照索引去修改。
public Type set(int index,Type val) {//设置索引值为index的元素,返回该位置之前的value
if(index>=size||index<0) {
throw new ArrayIndexOutOfBoundsException();
}
Type t = elements[index];
elements[index]=val;
return t;
}
添加操作,当容量满了时,我们需要新声明一个更大的数组,然后将原数据复制到新数组上,然后再添加新数据,这就是扩容。把前面的都复制一遍是很大工作量的。
public void ensureCapacity(int newSize) {//(扩容)调整数组大小,若newSize小于size,则不需要做改变
if(newSize<size)return;
Type[] old = elements;
elements = (Type[])new Object[newSize];
for(int i=0; i<size; i++) {
elements[i]=old[i];
}
}
public void add(int index,Type val) {//在指定位置添加元素,index以后的元素以推箱子形式后移
if(index>size||index<0) {
throw new ArrayIndexOutOfBoundsException();
}
if(elements.length==size) {
ensureCapacity(size*2);
}
for (int i=size; i>index; i--)
elements[i]=elements[i-1];
elements[index]=val;
size++;
}
删除操作,删除数据后,因为数组必须保持连续,所以后面的元素都要往前挪。工作量也很大。
public Type remove(int index) {//删除指定位置元素,index以后的元素前移,返回这个被删除的元素
if(index>=size||index<0) {
throw new ArrayIndexOutOfBoundsException();
}
Type t = elements[index];
for(int i=index;i<size-1;i++) {
elements[i]=elements[i+1];
}
size--;
return t;
}
完整代码
//实现一个简单的ArrayList,一个动态数组
public class ArrayList<Type> {
private Type[] elements;//存储数据单元
private int size;//当前指针位置
private static final int Default_size = 10;//默认大小
public ArrayList() {//无大小参数的默认构造方法
elements = (Type[])new Object[Default_size];
size = 0;
}
public ArrayList(int sz) {//传入大小参数的构造方法
elements = (Type[])new Object[sz];
size = 0;
}
public void clear() {//清空数组,实际是把指针调到初始位置,之前数据在未被覆盖前依然存在
size = 0;
}
public int size() {//返回当前指针位置,可看做当前元素个数
return size;
}
public boolean isEmpty() {//判断是否为空,即判断当前指针位置是否在起始位置
return size==0;
}
public Type get(int index) {//返回索引值为index的元素,index若大于等于size,或小于0,则抛出异常
if(index>=size||index<0) {
throw new ArrayIndexOutOfBoundsException();
}
return elements[index];
}
public Type set(int index,Type val) {//设置索引值为index的元素,返回该位置之前的value
if(index>=size||index<0) {
throw new ArrayIndexOutOfBoundsException();
}
Type t = elements[index];
elements[index]=val;
return t;
}
public void ensureCapacity(int newSize) {//调整数组大小,若newSize小于size,则不需要做改变
if(newSize<size)return;
Type[] old = elements;
elements = (Type[])new Object[newSize];
for(int i=0; i<size; i++) {
elements[i]=old[i];
}
}
public void trimToSize() {//调整数组大小等于当前指针位置
ensureCapacity(size);
}
public void add(int index,Type val) {//在指定位置添加元素,index以后的元素以推箱子形式后移
if(index>size||index<0) {
throw new ArrayIndexOutOfBoundsException();
}
if(elements.length==size) {
ensureCapacity(size*2);
}
for (int i=size; i>index; i--)
elements[i]=elements[i-1];
elements[index]=val;
size++;
}
public void add(Type val) {//在末尾添加元素
add(size,val);
}
public Type remove(int index) {//删除指定位置元素,index以后的元素前移,返回这个被删除的元素
if(index>=size||index<0) {
throw new ArrayIndexOutOfBoundsException();
}
Type t = elements[index];
for(int i=index;i<size-1;i++) {
elements[i]=elements[i+1];
}
size--;
return t;
}
public boolean removeFirst(Type val) {//删除第一个val,如果无此元素则返回false
for(int i=0;i<size;i++) {
if(elements[i].equals(val)) {
remove(i);
return true;
}
}
return false;
}
public void removeAll(Type val) {//删除含有的所有val元素
for(int i=0;i<size;i++) {
if(elements[i].equals(val)) {
remove(i);
}
}
}
public int find(Type val) {//查找val第一次出现的位置,若无此元素则返回-1
if(val==null) {
for( int i=0; i<size; i++)
if(elements[i]==null)return i;
}else {
for(int i=0;i<size;i++)
if(elements[i].equals(val))return i;
}
return -1;
}
}