一.线性表
线性表的定义
线性表是具有相同数据类型的 n(n>=0)个数据元素的有限序列,其中n为表长,当 n=0时,是一个空表。若用L命名线性表,则其一般表示为:L = (a1,a2,a3…ai,… an),在该式子中,a1是唯一的“第 一个”数据元素,又称表头元素;an是唯一的“最后一 个”数据元素,又称表尾元素。除第一个元素外,每个元素有且仅有 一个直接前驱。除最后一个元素外,每个元素有且仅有一个直接后驱。
由此,我么得出线性表特点如下:
- 表中元素的个数有限。
- 表中元素具有逻辑上的顺序性 表中元素有其先后次序。
- 表中元素都是数据元素,每个元素都是单个元素。
- 表中元素的数据类型都相同,这意味着每个元素占有相同大 的存储空间。
- 表中元素具有抽象性,即仅讨论元素之间的逻辑关系,并不考虑元素究竟表示什么内容。
线性表(List)划分为顺序表(ArrayList)和链表(LinkList),需要强调的是,在数据结构中,线性表被设计成一个接口,顺序表和链表都继承实现了该接口内的方法,而且顺序表和链表都是可变对象,也就是说我们可以直接对里面的内容进行修改。
二.顺序表
顺序表的定义:
线性表的顺序存储称顺序表。它是用一组地址连续的存储单元依次存储线性表中的数据元素,从而使得逻辑上相邻的两个元素在物理位置上也相邻。第 1个元素存储在线 的起始位置,第i个元素的存储位置后面紧接着存储的是第 i+1 个元素,称 i为元素ai在线性表中的位序。因此,顺序表的特点是表中元素的逻辑顺序与其物理顺序相同。
假设线性表L存储的起始位置为LOC(A),sizeof(ElemType)是每个数据元素所占用的存储空间的大小,则L所对应的顺序存储如下图所示:
注意:
- 顺序表中一定要区分两个概念 容量(capacity) vs 元素个数(size);线性表的所有下标只和元素个 数相关,和容量无关。
- 线性表中的元素的位序是从1开始的,而数组中元素的下标是0开始的。(需要强调的是:java的数组只提供了最基础的功能,如取长度,取下标对应的元素。而顺序表在这个基础上新增了增删改查等诸多功能。)
一个线性表要提供的典型操作,可以参考List接口里面的方法。下面代码是顺序表中提供的一些方法测试:
import java.util.ArrayList;
import java.util.Iterator;
public class testArrayList {
public static void main(String[] args) {
ArrayList<String> arrayList = new ArrayList<String>();//创建ArrayList实例
/*
List<String> arrayList = new ArrayList<String>();
这段代码中,List和ArrayList实现了“向上转型操作”,即将注释释放,下面代码中的方法调用会触发动态绑定,
通过多态的形式来执行到ArrayList中的代码。
*/
System.out.println(arrayList.size());//顺序表长度
System.out.println(arrayList.isEmpty());//顺序表判断是否为空表
//1.add操作,把一个元素添加到ArrayList末尾。
arrayList.add("C");
arrayList.add("C++");
arrayList.add("JAVA");
arrayList.add("Python");
System.out.println(arrayList.size());
System.out.println("进行4次尾插操作后的结果:"+arrayList);
//ArrayList类重写了toString方法,所以可以直接打印。
//2.add操作,往ArrayList指定位置上插入一个元素。
arrayList.add(2,"JavaScript");
System.out.println(arrayList.size());
System.out.println("在下标为2的位置进行插入:"+arrayList);
//3.remove操作,删除ArrayList中指定位置的元素。
arrayList.remove(2);
System.out.println("删除下标为2位置的元素:"+arrayList);
//4.remove操作,删除Arraylist中指定值元素。
arrayList.add("C++");
System.out.println("往ArrayList中多加一个元素:"+arrayList);
arrayList.remove("C++");
System.out.println("删除内容为C++的元素:"+arrayList);
//删除指定元素,如果有多个该元素,那么只删除下标最小的那个位置的,如果想全部删除,要搭配循环。
/*
此处删除某一指定内容的元素,肯定需要对ArrayList进行遍历操作,然后比较每个位置的值与该指定内容是否相等。
此时判断相等的方式理论上可以有“==”和“equals”实现。但是实际上是由“equals”来实现的。
因为ArrayList里面可以存不同类型的元素(泛型),比如存了一个你自己写的类,
我们此时可以通过重写equals的方式,来告诉ArrayList什么叫做相等,然后实现正确的相等内容捕获,再删除。
*/
//5.contains操作,通过遍历的方式,判断与目标元素相等的元素是否存在于线性表中,返回值是Boolean类型。
boolean ret = arrayList.contains("JAVA");
System.out.println("用contains查找JAVA的结果为:"+ ret);
//6.indexOf操作,按照从前往后遍历的方式,找到第一个与目标元素相等的元素的下标,返回下标位置。
int index1 = arrayList.indexOf("JAVA");
System.out.println("用indexOf查找JAVA的结果为:"+index1);
//7.lastIndexOf操作,按照从后往前遍历的方式,找到第一个与目标元素相等的元素的下标,返回下标位置。
int index2 = arrayList.lastIndexOf("JAVA");
System.out.println("用indexOf查找JAVA的结果为:"+index2);
//8.get操作,通过元素的下标位置获取该位置元素,并且返回该元素。
String str = arrayList.get(1);
System.out.println("获取到下标位置为1的元素:"+str);
//9.set操作,指定一个目标位置以及要修改的内容, 用新的元素替换目标位置的元素,并返回该位置的原来的元素.
String elem = arrayList.set(0,"PHP");
System.out.println("0号下标的元素为:"+elem);
System.out.println("修改后的顺序表为:"+arrayList);
// 10.遍历操作,三种方法:
// a)通过下标来遍历。
for (int i=0;i<arrayList.size();i++){
System.out.println(arrayList.get(i));
}
// b)通过迭代器来遍历。
//先通过Iterator方法或取到迭代器对象。
Iterator<String> iterator = arrayList.iterator();
//再通过while循环来进行遍历.
while(iterator.hasNext()){ //()里面是判断是否有下一个元素,如果存在返回true,不存在返回false。
String e= iterator.next();//获取当前元素,并且“光标”指向下一个元素。
System.out.println(e);
}
// c)使用for-each来遍历。(本质是基于迭代器的方式实现的)
for (String e : arrayList){
System.out.println(e);
}
//11.clear操作,清空线性表,也就是调用clear()后,线性表的size()==0;isEmpty()==true。
arrayList.clear();
System.out.println(arrayList);
}
}
总结:
- Java实现顺序表的时候,有一个专门的类ArrayList类,这个类针对普通数组进行了封装,而且它是一个泛型类,通过泛型参数来指定ArrayList中都可以存储哪些类型的数据。
- 在java中,List是为了实现线性表而定义的一个接口,ArrayList是为了实现顺序表而定义的一个类,Collection表示的是元素集合,概念更加广泛,既包含了线性表,也包含了一些非线性结构。
- ArrayList的isEmpty和ArrayList=null的区别:如果把ArrayList想象成一个盒子,如果ArrayList的isEmpty为true,说明这是一个“空盒子”,如果ArrayList=null,就意味着连盒子没有。区别就在于是否有ArrayList的实例。
- ArrayList和LinkList都是实现了List接口,而add方法就是List接口中提供的,所以ArrayList中能实现的方法,在LinkList中一样可以实现。