上一篇文章讲述了动态数组ArrayList的简单实现,这次讲述一下单链表这种链式的存储结构,在此之前先弄懂以下几个基本问题:
1.什么是单链表?
是一种链式存储的数据结构,具有指针域和节点域两块内存空间,相对于其他链表来说,单链表只有一个指针域,且总是指向下一个结点(循环链表可以指向前面的结点);
2.与动态数组相比,有什么优势,什么劣势?
优势:在于首尾元素的插入与删除和不损性能的长度扩展,对于双向链表而言,首尾插入、删除的效率都是非常高的,而插入中间元素则相对低效,在长度扩展方面动态数组需要建立新数组,再将所有元素‘举家迁移’至新数组,而对于链表而言,不需要连续的存储空间,通过指针域来保存任意内存位置上的下一个结点;
劣势:获取中间数据效率低和占用内存大,由于没有索引,所以获取第n个位置的元素需要将指针移动n-1次,而动态数组则直接通过索引访问,占用内存大很好理解,相对于动态数组而言多了一个指针域;
实现过程如下:
1.建立MyList接口,提供线性表基本操作的规范:
见作者的上一篇博客《数据结构01-自定义ArrayList》
2.定义实现类:
package A01.LSQ;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class MyLinkedList<E> implements MyList<E>, Iterable<E>
{
// 头结点
private Node<E> head;
// 链表长度
private int size;
public MyLinkedList()
{
head = new Node<>();
}
// 末尾位置插入元素
@Override
public E add(E data)
{
Node<E> temp = head;
while (temp.next != null)
temp = temp.next;
temp.next = new Node<>(data);
size++;
return data;
}
// 自定义位置插入元素
@Override
public E add(int index, E data)
{
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException("越界");
int count = 0;
Node<E> temp = head;
while (temp.next != null)
{
if (count++ == index)
{
Node<E> p = new Node<>(data);
p.next = temp.next;
temp.next = p;
size++;
break;
}
temp = temp.next;
}
return data;
}
// 返回大小
@Override
public int size()
{
return size;
}
// 获取元素
@Override
public E get(int index)
{
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException("越界");
int count = 0;
Node<E> temp = head;
while (temp.next != null)
{
temp = temp.next;
if (count++ == index)
{
return temp.data;
}
}
return null;
}
// 通过位置删除元素
@Override
public boolean remove(int index)
{
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException("越界");
int count = 0;
Node<E> temp = head;
while (temp.next != null)
{
if (count++ == index)
{
temp.next = temp.next.next;
size--;
break;
}
temp = temp.next;
}
return true;
}
// 通过数据对比删除元素
@Override
public boolean remove(E data)
{
Node<E> temp = head;
int count = 0;
while (temp.next != null)
{
temp = temp.next;
if (temp.data.equals(data))
{
return remove(count);
}
count++;
}
return false;
}
// 修改元素
@Override
public E set(int index, E data)
{
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException("越界");
int count = 0;
Node<E> temp = head;
while (temp.next != null)
{
temp = temp.next;
if (count++ == index)
{
temp.data = data;
return temp.data;
}
}
return null;
}
// 内部结点类
private class Node<E>
{
Node<E> next;
E data;
public Node()
{
this(null);
}
public Node(E data)
{
this.data = data;
next = null;
}
}
// 遍历链表
public void disPlay()
{
Node<E> temp = head;
while (temp.next != null)
{
temp = temp.next;
System.out.println(temp.data);
}
}
// 增强for循环需要提供的方法,返回一个Iterator接口对象
@Override
public Iterator<E> iterator()
{
return new MyLinkedListIterator();
}
// 内部类实现Iterator接口,实现remove、hasNext、next三个基本方法
private class MyLinkedListIterator implements Iterator<E>
{
private int current = 0;
@Override
public void remove()
{
MyLinkedList.this.remove(--current);
}
@Override
public boolean hasNext()
{
return current < size;
}
@Override
public E next()
{
if (!hasNext())
throw new NoSuchElementException();
return get(current++);
}
}
}