线性表(linear list)
线性表的逻辑结构
线性表时n个类型相同数据元素的有限序列,通常记作(a0,a1,。。。,ai,ai+1,。。。,an-1)。
- 相同数据类型:相同数据类型意味着在内存中存储时,每个元素会占用相同内存空间,便于后续的查询操作
- 序列(顺序性)
- 有限:在非空的线性表中每个数据元素在线性表中都有唯一确定的序号
线性表的存储结构
顺序表——顺序存储结构
特点:在内存中分配连续的空间,之存储数据,不需要存储地址信息,位置就隐含着地址。
优点:
- 节省存储空间,因为分配给数据的存储单元全用存放结点的数据,结点制件的逻辑关系没有占用额外的存储空间
- 索引查找效率高
缺点: - 插入和删除操作需要移动元素,效率较低 ,平均时间频度为O(n)
- 必须提前分配固定数量的空间,如果存储元素少,可能导致空闲浪费。
- 按照内容查询效率低,因为需要诸葛比较判断
package DataStructure.LineTable;
import java.util.Arrays;
/**
* @Description TODO 顺序表,底层采用数据,但长度可以动态变化
* TODO java.util.ArrayList 每次增长50%
* @Author Matthew
* @Date 2019/5/25 20:17
* @Version 1.0
*/
public class ArrayList implements List {
private Object[] elementData;//底层是一个数据,目前还没有确定长度。
private int size;//不是数组分配了几个空间,而是元素的个数。
public ArrayList() {
//没有指定长度,默认长度为4
this(4);
}
/**
* @Description :
* @Date 2019/5/25 20:22
* @Param initalCapacity 指定数组的初始长度
* @Return
*/
public ArrayList(int initalCapacity) {
//给数组分配指定数量的空间
elementData = new Object[initalCapacity];
//指定顺序表的元素个数,默认是0
size = 0;
}
@Override
public int size() {
return size;
}
@Override
public Object get(int i) {
if (i < 0 || i >= size) {//i<0或者i>=size
// throw new RuntimeException("数组索引越界异常" + i);
throw new MyArrayIndexOutBoundsException("数组索引越界异常" + i);
}
return elementData[i];
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public boolean contains(Object e) {
return false;
}
@Override
public int indexOf(Object e) {
return 0;
}
@Override
public void add(int i, Object e) {
//i的位置要正确
if (i < 0 || i > size) {
throw new MyArrayIndexOutBoundsException("数组索引越界异常 " + i);
}
if (size == elementData.length) {
grow();
}
//后移i和以后的元素,从最后一个元素开始
for (int j = size; j > i; j--) {
elementData[j] = elementData[j-1];
}
elementData[i] = e;
size++;
}
@Override
public void add(Object e) {
this.add(size, e);
/*//数组满了,就扩容
if (size == elementData.length) {
grow();
}
//给数组赋值
elementData[size] = e;
//元素个数+1
size++;
//elementData[size++] = e;
//System.out.println("length = " + elementData.length);*/
}
private void grow(){
/* //1.创建新数组,长度是旧数组二倍
Object[] newArr = new Object[2 * size];
//2.将旧数组的数据拷贝到新数组
for (int i = 0; i < size; i++) {
newArr[i] = elementData[i];
}
//3.让elementData指向新数组
elementData = newArr;*/
elementData = Arrays.copyOf(elementData, elementData.length * 2);
}
@Override
public boolean addBefore(Object obj, Object e) {
return false;
}
@Override
public boolean addAfter(Object obj, Object e) {
return false;
}
@Override
public Object remove(int i) {
return null;
}
@Override
public boolean remove(Object e) {
return false;
}
@Override
public Object replace(int i, Object e) {
return null;
}
@Override
public String toString() {
if (size == 0) {
return "[]";
}
StringBuilder builder = new StringBuilder("[");
for (int i = 0; i < size; i++) {
if (i != size - 1) {
builder.append(elementData[i] + " , ");
} else {
builder.append(elementData[i]);
}
}
builder.append("]");
return builder.toString();
}
}
package DataStructure.LineTable;
/**
* @Description TODO 自定义异常
* @Author Matthew
* @Date 2019/5/25 20:38
* @Version 1.0
*/
public class MyArrayIndexOutBoundsException extends RuntimeException{
public MyArrayIndexOutBoundsException() {
}
public MyArrayIndexOutBoundsException(String message) {
super(message);
}
}
package DataStructure.LineTable;
/**
* @Description TODO
* @Author Matthew
* @Date 2019/5/25 20:18
* @Version 1.0
*/
public class TestArrayList {
public static void main(String[] args) {
List list = new ArrayList();
list.add(123);
list.add(321);
list.add(456);
list.add(678);
list.add(23123);
list.add(213);
list.add(579);
list.add(222);
list.add(333);
list.add(80,233);
System.out.println(list.size());
System.out.println(list.isEmpty());
System.out.println(list.get(3));
System.out.println(list.toString());
}
}
链表——链式存储结构
特点:数据元素的存储对应的是不连续的存储空间,每个存储结点对应一个需要存储的数据元素。
每个结点是由数据域和指针域组成。元素制件的逻辑关系通过存储结点之间的链接关系反映出来,逻辑上相邻的节点物理上不必相邻。
优点:
- 插入、删除灵活(不必移动节点,只要改变节点中的指针,但是需要先定位到元素上)。
- 由元素才会分配节点空间,不会由闲置的节点。
缺点:
- 比顺序存储结构的存储密度小(每个节点都有数据与和指针域组成,所以相同空间内假设全存满的话顺序比链式存储更多)。
- 查找节点时链式存储摇臂顺序存储慢(每个节点地址不连续、无规律,导致按照索引查询效率低下)。