一个线性表是n个具有相同特性的数据元素的有限序列。
线性表的存储结构
1、顺序表-顺序存储结构
Vector线程安全
ArrayList线程不安全
优点:
在内存中分配连续的存储空间,只存储数据,不需要存储地址信息。位置就隐含着地址
索引查询效率高,每个节点对于一个序号,可由该序号直接算出节点的存储地址
缺点:
插入删除效率低
提前分配固定数量的空间,容易导致浪费
按着内容查询效率低,需要逐个判断
2、链表-链式存储结构
2.1单链表
特点:
数据的存储是不连续的空间
有元素才会分配空间,不会有闲置的节点
插入删除灵活(不需要移动节点)
缺点:
比顺序存储结构的存储密度小(每个元素由数据域和指针域组成)
查找慢(节点不连续,无规律)
访问前驱节点比较麻烦,无法直接访问前驱节点
2.2双向链表
头结点和尾节点都不存储数据,头结点的pre和尾节点的next为空,实现算法的一致
LinkedList的底层使用的是双向链表
2.3循环链表
定义一个线性表接口
List.java
package com.liang.datastructure.linetable;
/**
* 线性表接口
* 和存储结构无关
* @author sdl
*
*/
public interface List {
// 返回线性表的大小,即数据元素的个数。
public int size();
// 返回线性表中序号为 i 的数据元素
public Object get(int i);
// 如果线性表为空返回 true,否则返回 false。
public boolean isEmpty();
// 判断线性表是否包含数据元素 e
public boolean contains(Object e);
// 返回数据元素 e 在线性表中的序号
public int indexOf(Object e);
// 将数据元素 e 插入到线性表中 i 号位置
public void add(int i, Object e);
// 将数据元素 e 插入到线性表末尾
public void add(Object e);
// 将数据元素 e 插入到元素 obj 之前
public boolean addBefore(Object obj, Object e);
// 将数据元素 e 插入到元素 obj 之后
public boolean addAfter(Object obj, Object e);
// 删除线性表中序号为 i 的元素,并返回之
public Object remove(int i);
// 删除线性表中第一个与 e 相同的元素
public boolean remove(Object e);
// 替换线性表中序号为 i 的数据元素为 e,返回原数据元素
public Object replace(int i, Object e);
}
自定义异常
MyArrayIndexOutOfBoundsException.java
package com.liang.datastructure.linetable;
/**
* 自定义异常
* @author sdl
*
*/
@SuppressWarnings("serial")
public class MyArrayIndexOutOfBoundsException extends RuntimeException{
public MyArrayIndexOutOfBoundsException() {
super();
}
public MyArrayIndexOutOfBoundsException(String message) {
super(message);
}
}
使用顺序表实现
ArrayList.java
package com.liang.datastructure.linetable;
import java.util.Arrays;
/**
* 顺序表
* 底层采用数组,但是可由动态的增加长度
* @author sdl
*
*/
public class ArrayList implements List {
private Object[] elementData;//底层是一个数组,目前没有指定长度
private int size;//元素个数
/**
* 无参构造,长度默认为5
*/
public ArrayList() {
this(5);
}
/**
*
* @param initialCapacity 制定数组初始长度
*/
public ArrayList(int initialCapacity) {
//给数组分配空间
elementData=new Object[initialCapacity];
//制定顺序表元素个数,默认是零0
size=0;
}
@Override
public int size() {
return size;
}
@Override
public Object get(int i) {
if(i<0 || i>=size) {
throw new MyArrayIndexOutOfBoundsException("数组越界异常"+i);
}
return elementData[i];
}
@Override
public boolean isEmpty() {
return size==0;
}
@Override
public boolean contains(Object e) {
for(int i=0;i<size;i++) {
if(elementData[i].equals(e)) {
return true;
}
}
return false;
}
@Override
public int indexOf(Object e) {
for(int i=0;i<size;i++) {
if(elementData[i].equals(e)) {
return i;
}
}
return -1;
}
@Override
public void add(int i, Object e) {
if(i<0 || i>size) {
throw new MyArrayIndexOutOfBoundsException("指针越界"+i);
}
//如果数组满了,扩容
if(size==elementData.length) {
elementData = Arrays.copyOf(elementData, elementData.length*2);
}
for(int j=size;j>i;j--) {
elementData[j]=elementData[j-1];
}
elementData[i]=e;
size++;
}
@Override
public void add(Object e) {
// //如果数组满了,扩容
// if(size==elementData.length) {
Object[] newelementData=new Object[size*2];
for(int i=0;i<5;i++) {
newelementData[i] = elementData[i];
}
elementData = newelementData;
// elementData = Arrays.copyOf(elementData, elementData.length*2);//功能同上
// }
//
// elementData[size++] = e;
this.add(size, e);
}
@Override
public boolean addBefore(Object obj, Object e) {
int indexOf = indexOf(obj);
if(indexOf<0) {
return false;
}
if(size==elementData.length) {
elementData = Arrays.copyOf(elementData, elementData.length*2);
}
for(int j=size;j>indexOf;j--) {
elementData[j]=elementData[j-1];
}
elementData[indexOf]=e;
size++;
return true;
}
@Override
public boolean addAfter(Object obj, Object e) {
int indexOf = indexOf(obj);
if(indexOf<0) {
return false;
}
if(size==elementData.length) {
elementData = Arrays.copyOf(elementData, elementData.length*2);
}
for(int j=size;j>indexOf+1;j--) {
elementData[j]=elementData[j-1];
}
elementData[indexOf+1]=e;
size++;
return true;
}
@Override
public Object remove(int i) {
Object object = get(i);
for(int j=i;j<size-1;j++) {
elementData[j] = elementData[j+1];
}
size--;
return object;
}
@Override
public boolean remove(Object e) {
// int i = indexOf(e);
// if(i<0) {
// return false;
// }
// for(int j=i;j<size-1;j++) {
// elementData[j] = elementData[j+1];
// }
// size--;
return true;
}
@Override
public Object replace(int i, Object e) {
if(i<0 || i>size) {
throw new MyArrayIndexOutOfBoundsException("指针越界"+i);
}
Object object = get(i);
elementData[i] = e;
return object;
}
@Override
public String toString() {
if(size==0) {
return "[]";
}
StringBuilder str=new StringBuilder("[");
for(int i=0;i<size;i++) {
str.append(elementData[i]+",");
}
String substring = str.substring(0, str.length()-1)+"]";
return substring;
}
}
使用链表实现
定义一个节点
Node.java
package com.liang.datastructure.linetable;
/**
* 单链表的节点
* @author sdl
*
*/
public class Node {
private Object data;
private Node next;
public Node() {
}
public Node(Object data) {
super();
this.data = data;
}
public Node(Object data, Node next) {
super();
this.data = data;
this.next = next;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
SingleLinkedList.java
package com.liang.datastructure.linetable;
/**
* 单链表
* @author sdl
*
*/
public class SingleLinkedList implements List {
private Node head=new Node();//头结点,不存储数据,为了编程方便
private int size;
@Override
public int size() {
return size;
}
@Override
public Object get(int i) {
Node p=head;//找到i节点,从头节点开始
for(int j=0;j<=i;j++) {
p=p.getNext();
}
return p.getData();
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public boolean contains(Object e) {
Node p=head.getNext();
for(int i=0;i<size;i++) {
if(p.getData().equals(e)) {
return true;
}
p=p.getNext();
}
return false;
}
@Override
public int indexOf(Object e) {
Node p=head.getNext();
for(int i=0;i<size;i++) {
if(p.getData().equals(e)) {
return i;
}
p=p.getNext();
}
return -1;
}
@Override
public void add(int i, Object e) {
if(i<0 || i>size) {
throw new MyArrayIndexOutOfBoundsException("指针越界异常"+i);
}
Node p=head;//找到前一个节点,从头节点开始
for(int j=0;j<i;j++) {
p=p.getNext();
}
Node newNode=new Node(e);
newNode.setNext(p.getNext());
p.setNext(newNode);
size++;
}
@Override
public void add(Object e) {
this.add(size, e);
}
@Override
public boolean addBefore(Object obj, Object e) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean addAfter(Object obj, Object e) {
// TODO Auto-generated method stub
return false;
}
@Override
public Object remove(int i) {
Node p=head;
for(int j=0;j<i;j++) {
p=p.getNext();
}
Object data = p.getNext().getData();
p.setNext(p.getNext().getNext());
size--;
return data;
}
@Override
public boolean remove(Object e) {
// TODO Auto-generated method stub
return false;
}
@Override
public Object replace(int i, Object e) {
Node p=head;
for(int j=0;j<=i;j++) {
p=p.getNext();
}
Object data = p.getData();
p.setData(e);
return data;
}
@Override
public String toString() {
if(size==0) {
return "[]";
}
StringBuilder str=new StringBuilder("[");
Node p=head;
for(int i=0;i<size;i++) {
p=p.getNext();
str.append(p.getData()+",");
}
String substring = str.substring(0, str.length()-1)+"]";
return substring;
}
}
测试顺序表
package com.liang.datastructure.linetable;
public class TestArrayList {
public static void main(String[] args) {
List list=new ArrayList();
list.add(1);
list.add(2);
list.add(3);
list.add(888);
list.add(5);
System.out.println(list.toString());
System.out.println(list.size());
System.out.println(list.indexOf(2));
System.out.println(list.toString());
System.out.println(list.size());
System.out.println(list.replace(2, 999));
System.out.println(list.size());
System.out.println(list.toString());
}
}
测试单链表
package com.liang.datastructure.linetable;
public class TestLinkedList {
public static void main(String[] args) {
List list=new SingleLinkedList();
list.add(1);
list.add(2);
list.add(3);
list.add(888);
list.add(5);
list.add(5, 789);
System.out.println(list.toString());
System.out.println(list.size());
System.out.println(list.contains(8848));
System.out.println(list.indexOf(8808));
System.out.println(list.remove(3));
System.out.println(list.toString());
System.out.println(list.replace(2, 999));
System.out.println(list.toString());
}
}