动态链表——线性表的链式存储结构
为了表示每个数据元素ai与其直接后继元素ai+1之间的逻辑关系,对数据元素a1来
说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息(即直接后继的存储
位置)。我们把存储数据元素信息的域称为数据域,把存储直接后继位置的域称为指针域。
指针域中存储的信息称为指针或链。这两部分信息组成数据元素ai的存储映像,称为结点
(Node)
n个结点链接成一个链表,即为线性表的链式存储结构,因此链表的每个结点只包含一
个指针域,所以叫做单链表。
头指针:
头指针是指链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指
针
头指针具有标识作用,所以常用头指针冠以链表的名字
无论链表是否为空,头指针均不为空。头指针是链表的必要元素
我们先定义List接口:
public interface List<E>{
public int getSize();// 获取链表元素个数
public boolean isEmpty();//判断链表是否为空
//增
public void add(int index,E e);//在指定位置添加元素
public void addFirst(E e);//在链表头增加元素
public void addLast(E e);//添加元素至链表尾
//删
public E remove(int index);//删除指定下标元素
public E removeFirst();//删除链表中第一个元素
public E removeLast();//删除链表中最后一个元素
public void removeElement(E e);//删除元素e;
public void clear();//清空链表
//查
public E get(int index);//获取列表指定下标元素
public E getFirst();//获取列表第一个元素
public E getLast();//获取列表最后一个元素
public boolean contains(E e);//判断列表是否包含指定元素E
public int find(E e);//在列表中查找元素e的角标
//改
public void set(int index,E e);//修改列表中指定元素位置为新元素
}
实现单链表时,我们设置一个头指针,其数据域为空,只其索引作用:
public class LinkedList<E> implements List<E>{
private class Node{
E data;
Node next;
public Node() {
this(null,null);
}
public Node(E data) {
this(data,null);
}
public Node(E data,Node next) {
data = (E) new Object();
this.next = next;
}
}
private Node head;
private Node rear;
private int size;
public LinkedList(E data) {
head = new Node();
rear = head;
size = 0;
}
@Override
public int getSize() {
return size;
}
@Override
public boolean isEmpty() {
return size==0;
}
@Override
public void add(int index, E e) {
if(index<0||index>size) {
throw new IllegalArgumentException();
}
Node n = head;
if(index==0) {
n.next = head.next;
head.next = n;
if(size==0) {
rear=n;
}
}else if(index==size) {
n.next = rear.next;
rear.next = n;
rear=n;
}else {
Node p = head;
for(int i=0;i<index;i++) {
p=p.next;
}
n.next = p.next;
p.next = n;
}
size++;
}
@Override
public void addFirst(E e) {
add(0,e);
}
@Override
public void addLast(E e) {
add(size,e);
}
@Override
public E remove(int index) {
if(index<0||index>=size) {
throw new IllegalArgumentException();
}
E res=null;
if(index==0) {
res = head.next.data;
head.next = head.next.next;
if(size==1) {
rear=head;
}
}else if(index==size-1) {
res = rear.data;
Node p =head;
while(p.next!=rear) {
p=p.next;
}
p.next=rear.next;
rear = p;
}else {
Node n = head;
for(int i = 0;i<index;i++) {
n=n.next;
}
res=n.next.data;
n.next = n.next.next;
}
size--;
return res;
}
@Override
public E removeFirst() {
return remove(0);
}
@Override
public E removeLast() {
return remove(size-1);
}
@Override
public void removeElement(E e) {
int index = find(e);
if(index!=-1) {
remove(index);
}
}
@Override
public void clear() {
head.next = null;
rear = head;
size = 0;
}
@Override
public E get(int index) {
if(index<0||index>=size) {
throw new IllegalArgumentException();
}
E res;
if(index==0) {
res=head.next.data;
}else if(index==size-1) {
res=rear.data;
}else {
Node p = head;
for(int i=0;i<index;i++) {
p=p.next;
}
res=p.data;
}
return res;
}
@Override
public E getFirst() {
return get(0);
}
@Override
public E getLast() {
return get(size-1);
}
@Override
public int find(E e) {
if(isEmpty()) {
return -1;
}
Node p = head;
for(int i = 0;i<size-1;i++) {
p=p.next;
if(p.equals(e)) {
return i;
}
}
return -1;
}
@Override
public boolean contains(E e) {
return find(e)!=-1;
}
@Override
public void set(int index, E e) {
if(index<0||index>=size) {
throw new IllegalArgumentException();
}
if(index==0) {
head.next.data=e;
}else if(index==size-1) {
rear.data=e;
}else {
Node p =head;
for(int i=0;i<index;i++) {
p=p.next;
}
p.data=e;
}
}
public String toString() {
if(isEmpty()) {
return "LinkedList = []";
}else {
StringBuilder sb = new StringBuilder();
Node p = head;
for(int i=0;i<size-1;i++) {
if(p.next==rear) {
sb.append(p.data+" ]");
}else {
sb.append(p.data+" ,");
}
}
return "Array: ["+sb.toString();
}
}
}