当前遇到一个问题
我们希望能够将数据按顺序存放,支持在某个位置插入一条数据、删除一条数据、修改一条数据等,如果使用数组的话这时候,就显得有些乏力了,因为数组的长度是固定。
我们实现一个新的数据结构:线性表
线性表是由同一类型的数据元素构成的有序序列的线性结构。线性表中元素的个数就是线性表的长度,表的起始位置称为表头,表的结束位置称为表尾,当一个线性表中没有元素时,称为空表。
线性表一般需要包含以下功能:
初始化线性表:将一个线性表进行初始化,得到一个全新的线性表。
获取指定位置上的元素:直接获取线性表指定位置i上的元素。
获取元素的位置:获取某个元素在线性表上的位置i。
插入元素:在指定位置i上插入一个元素。
删除元素:删除指定位置i上的一个元素。
获取长度:返回线性表的长度。
实现线性表的结构一般有两种,一种是顺序存储实现,还有一种是链式存储实现,我们先来看第一种,也是最简单的的一种。
public class ArrayList<E> {
private int size=0 ;// 当前顺序表的大小
private int capacity=10;//数组的容量
private Object[] array = new Object[capacity];
// 新增一个元素
public void add(E element,int index){
if(index<0 || index > size){
throw new IndexOutOfBoundsException("插入位置非法,合法插入的位置为:0 ~ "+size);
}
if(size >= capacity){
int newCapacity = capacity + (capacity >> 1); //扩容为原来的1.5倍
Object[] newArray = new Object[newCapacity];
System.arraycopy(array,0,newArray,0,size);
array = newArray;
capacity = newCapacity;
}
for (int i = size; i > index; i--) {
array[i] = array[i-1];
}
array[index] = element;
size++;
}
// 删除一个元素
public E remove(int index){
if (index<0|| index> size-1){
throw new IndexOutOfBoundsException("删除位置非法,合法删除的位置为:0 ~ "+(size-1));
}
for (int i = index; i < size; i++) {
array[i] = array[i+1];
}
size--;
return (E) array[index];
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < size; i++) {
stringBuilder.append(array[i]).append(" ");
}
return stringBuilder.toString();
}
}
我们接着来看第二种方式,我们可以使用链表来实现,那么什么是链表呢?
链表不同于顺序表,顺序表底层采用数组作为存储容器,需要分配一块连续且完整的内存空间进行使用,而链表则不需要,它通过一个指针来连接各个分散的结点,形成了一个链状的结构,每个结点存放一个元素,以及一个指向下一个结点的指针,通过这样一个一个相连,最后形成了链表。它不需要申请连续的空间,只需要按照顺序连接即可,虽然物理上可能不相邻,但是在逻辑上依然是每个元素相邻存放的,这样的结构叫做链表(单链表)
public class LinkList<E> {
class ListNode {
public E val;
public ListNode next;
public ListNode(E val) {
this.val = val;
}
}
public ListNode head;
//遍历单链表
public void show() {
ListNode cur = head;
while (cur != null) {
System.out.print(cur.val+" ");
cur = cur.next;
}
System.out.println();
}
// 头插法
public void addFirst(E data){
ListNode node = new ListNode(data);
node.next = head;
head = node;
}
// 尾插法
public void addLast(E data){
ListNode node = new ListNode(data);
if (head==null){
head = node;
return;
}
ListNode cur = head;
while (cur.next!=null){ //需要提前判断 cur.next是否存在
cur = cur.next;
}
cur.next = node;
}
public int size(){
int size=0;
ListNode cur = head;
while (cur!=null){
cur = cur.next;
size++;
}
return size;
}
// 随意位置插入
public void add(E data,int index){
// index合法位置判断
int len = size();
if(index <0 || index > len){
return;
}
if (index == 0) {
addFirst(data);
return;
}
if (index == size()) {
addLast(data);
return;
}
ListNode cur = getIndexData(index);
ListNode node = new ListNode(data);
node.next = cur.next;
cur.next = node;
}
public ListNode getIndexData(int index){
ListNode cur = head;
while (index!=0){
cur = cur.next;
index--;
}
return cur;
}
public void remove(int index){
if(index <0 || index > size()){
return;
}
if(index==0){
head.next=null;
}
ListNode indexData = getIndexData(index - 1);
indexData.next = indexData.next.next;
}
}