顺序表
在Java中线性表的顺序表的存储结构是利用数组来实现的,存储空间是连续的。存储空间的起始位置就是由数组名表示的地址常量。
实例
ArrayList也是用数组实现的,其内部维护了一个数组,是一种可变长度的数组。
数组在创建时其存储空间就已经固定,为了解决这个问题,ArrayList会先创建一个数组,当向尾部添加元素时,会先检查数组长度是否够用,如果够用就把数据加到数组中,如果不够用会创建新的数组,将原数组中元素一个个复制到新数组后,将新元素添加进来。如果向头部或者中间插入元素会直接导致数据移动。
在ArrayList中,相邻的元素其存储位置也相邻,在进行插入或删除操作时,平均需要移动半个表的元素,时间复杂度为O(n),但是其在进行查找时可以其时间复杂度为O(1),所以一般用于查找比较多的场景中。
链表
在链式存储中,每个存储结点不仅包含元素本身的信息(数据域),还包含了下一个(双链表中还有上一个)元素的地址信息(指针域)。
在链表中存储空间不要求一定是连续的,每个结点存储位置可以任意安排,所以在执行插入或删除操作时只需要修改相关结点的指针域即可。
链表比顺序表更适合插入和删除操作。
单链表
单链表:在每个结点中除包含数据域外,还设置一个指针域用以指向其后继结点,这种构成的链接表称为线性单向链接表,简称单链表。
单链表中当访问一个结点后,只能访问其后继结点,而无法访问其前驱结点。
当单链表在执行插入时,比如要在a结点前插入一个结点,那么就要修改a结点的前驱结点的指针域,但是因为通过结点不能找到其前驱结点,所以需要从表头遍历至前驱结点然后进行插入操作,这样时间复杂度就是O(n)。虽然单链表和顺序表在执行插入时时间复杂度都是O(n),但是顺序表还要执行移动结点的操作而链表却不用移动结点,该操作通常要比单纯的查找更加费时。所以单链表的插入比顺序表的插入要高效。
当单链表执行删除操作时时间复杂度是O(1) 比顺序表的删除操作要高效。
当单链表执行查找操作时要从表头开始遍历,时间复杂度是O(n) 比顺序表的查找操作要低效。
双链表
双链表:在每个结点中除包含数据域外,还设置个两个指针域,一个用以指向其后继结点,一个用以指向其前驱继结点,这种构成的链接表称为线性双向链接表,简称双链表。
双链表可以访问其后继结点及其前驱结点,这样就可以从两端访问所有结点,并且对于插入操作中查找前驱结点的问题,在双链表中是不存在的。
在双链表中结点的插入和删除操作涉及前后结点的两个指针域的变化。java中LinkedList正是对双链表的实现。
双链表的插入和删除操作时间复杂度是O(1)。
双单链表执行查找操作时会从离的较近的表头开始遍历,时间复杂度是O(n) 比顺序表的查找操作要低效。
循环链表
循环链表也是链式存储结构,它的尾结点的指针域指向头结点,如果是双向链表其头结点指向前驱结点的指针会指向尾结点,这样整个链表形成一个环。从表中任意一结点出发均可找到链表中其他结点。
有序表
有序表:按照结点元素的值以递增或递减方式排列,并且要求有序表中不存在元素值相同的结点。
有序表可以采用顺序表和链表进行存储。