数据结构分类
数据结构有很多种,一般来说,按照数据的逻辑结构对其进行简单的分类,包括线性结构和非线性结构两类。
线性结构
线性结构是最基本,最简单也是最常用的一种数据结构。一个线性结构是N个具有相同特性的数据元素的有限序列。
简单地说,线性结构就是表中各个结点具有线性关系。如果从数据结构的语言来描述,线性结构应该包括如下几点:
1、线性结构是非空集。
2、线性结构有且仅有一个开始结点和一个终端结点。
3、线性结构所有结点都最多只有一个直接前驱结点和一个直接后继结点。
线性表就是典型的线性结构,还有栈、队列和串等都属于线性结构。线性表中数据存储方式可以是顺序存储,也可以是链式存储,按照数据的存储方式不同,可以把线性表分为顺序表和链表。
顺序表
顺序表在计算机内存中是以数组形式保存的线性表。线性表的顺序存储是指用一组地址连续的存储单元,依次存储线性表的各个元素,使得线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中,即通过数据元素物理粗糙的相邻关系来反映数据元素之间逻辑的相邻关系。
顺序表的简单实现
顺序表API
类 | SequenceList |
构造方法 | SequenceList(int capacity) |
成员变量 | private Object[] elements; // 存储元素的数组 private int size; //线性表长度 |
成员方法 | int size() //线性表长度 boolean isEmpty()//线性表是否为空 T get(int index) //根据索引查询 T set(int index, T element) 更新索引index的元素 void add(T element) //添加元素 void add(int index, T element) //指定位置添加元素 T remove(int index) //移除索引位置元素 |
顺序表容量变化
顺序表原始容量
顺序表添加元素D
在索引位置1 添加元素E
在添加元素F,顺序表需要扩容,
顺序表SequenceList
知道了顺序表的知识后,我们自己动手写一个顺序表SequenceList
import org.jetbrains.annotations.NotNull;
import java.util.Iterator;
/**
* 顺序表
*/
public class SequenceList<T> implements Iterable<T> {
/**
* 顺序表元素数组
*/
private T[] elements;
/**
* 顺序表长度
*/
private int size;
/**
* 构造方法
*/
public SequenceList(int capacity) {
elements = (T[]) new Object[capacity];
size = 0;
}
/**
* 顺序表元素长度
*/
public int size() {
return this.size;
}
/**
* 是否空数据
*/
public boolean isEmpty() {
return this.size == 0;
}
/**
* 根据索引查询
*/
public T get(int index) {
if (index >= elements.length) {
throw new IndexOutOfBoundsException("index to big");
}
return elements[index];
}
/**
* 设置值
*/
public T set(int index, T element) {
if (index >= elements.length) {
throw new IndexOutOfBoundsException("index to big");
}
T oldElement = elements[index];
elements[index] = element;
return oldElement;
}
/**
* 添加元素
*/
public void add(T element) {
if (size == elements.length - 1) {
T[] temp = elements;
int capacity = elements.length;
//数组扩容
elements = (T[]) new Object[capacity * 2];
//拷贝旧数组数据到扩容后数组
System.arraycopy(temp, 0, elements, 0, temp.length);
}
elements[size++] = element;
}
/**
* 指定位置添加元素
*/
public void add(int index, T element) {
if (index >= elements.length - 1) {
throw new IndexOutOfBoundsException("index to big");
}
for (int i = size; i > index; i--) {
elements[i] = elements[i - 1];
}
elements[index] = element;
size++;
}
/**
* 移除元素
*/
public T remove(int index) {
if (index >= elements.length) {
throw new IndexOutOfBoundsException("index to big");
}
T oldElement = elements[index];
for (int i = index; i < size - 1; i++) {
elements[index] = elements[++index];
}
size--;
return oldElement;
}
/**
* 返回iterator
*/
@NotNull
@Override
public Iterator<T> iterator() {
return new Itr<T>();
}
private class Itr<T> implements Iterator<T> {
private int cusor;
public Itr() {
this.cusor = 0;
}
/**
* 是否有下一个元素
*/
@Override
public boolean hasNext() {
return cusor < size;
}
/**
* 下一个元素
*/
@Override
public T next() {
return (T) elements[cusor++];
}
}
}
测试顺序表
public class SequenceListTest {
public static void main(String[] args) {
SequenceList<String> list = new SequenceList<>(10);
list.add("张三");
list.add("李四");
System.out.println("------add");
list.forEach(e -> {
System.out.println(e);
});
System.out.println("------add index");
list.add(1, "王五");
list.forEach(e -> {
System.out.println(e);
});
list.add(2, "赵六");
list.add("田七");
list.remove(1);
System.out.println("------remove index");
list.forEach(e -> {
System.out.println(e);
});
}
}
测试输出:
------add
张三
李四
------add index
张三
王五
李四
------remove index
张三
赵六
李四
田七
时间复杂度
操作 | 时间复杂度 |
get | O(1) |
add | O(n) |
remove | O(n) |
ArrayList
ArrayList API
java 中的ArrayList集合底层也 是一种顺序表,使用数组实现。
类 | ArrayList |
构造方法 | ArrayList(int initialCapacity) |
成员变量 | transient Object[] elementData; private int size; |
扩容代码实现
/**
* 添加元素
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
/**
* 计算数组长度 和 最小容量
*/
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
/**
* 如果minCapacity大于数组长度,则扩容
*/
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* 扩容
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}