线性表除了顺序存储的实现还有另一种链式存储的实现方式,就是使用指针的方式将存储元素的结点连接起来;这种方式在执行插入或删除运算的时候,就不需要移动元素来腾出空间和填补空间,因此我们在进行这些操作的时候就会特别的方便。
链表是通过一系列的存储数据的结点用指针连接起来形成的,所以每一个结点至少都需要两个域;一个用来存储数据的数据域,一个是指向下一个结点的指针域。
由于数据域存储的也是对象的引用,因此数据实际上是通过指向数据的物理存储地址来完成存储的,上面的单链表结点结构是结点的一种最简单的形式,这些结点结构都是只有一个数据域并能够完成数据元素的存储,因此在Java中就定义了一个结点接口,方便结点中存储数据的存储。
结点接口的定义:
/**
* 定义一个结点接口
*/
public interface Node {
//获取结点数据域
public Object getData();
//设置结点数据域
public void setData(Object obj);
}
把结点接口定义出来后,单链表的结点定义就可以通过实现结点接口来完成;
单链表结点的定义:
/**
* 单链表结点的实现
*/
public class SLNode implements Node{
private Object element; //定义一个元素
private SLNode next; //定义指针域
public SLNode() {
}
public SLNode(Object element, SLNode next) {
this.element = element;
this.next = next;
}
public Object getElement() {
return element;
}
public void setElement(Object element) {
this.element = element;
}
public SLNode getNext() {
return next;
}
public void setNext(SLNode next) {
this.next = next;
}
@Override
public Object getData() {
return element;
}
@Override
public void setData(Object obj) {
element=obj;
}
}
单链表是通过结点中的next域依次串联在一起而形成的,单链表的结构图如下:
与数组相似,单链表中的结点也具有一个线性次序;假设p结点的next指针指向s结点,那么p就是s的直接前驱,s是p的直接后继;注意:头结点是没有前驱的,尾结点是没有后继的;单链表的一个重要特性就是只能通过前驱结点找到后继结点,不能从后继结点找前驱结点。
那么就可以使用结点来实现单链表的主要功能:
首先还是定义线性表功能的接口:
package cn.jxlg.singlelist;
/**
* 定义线性表功能的接口
*/
public interface List {
//获取当前线性表的元素个数
public int getSize();
//判断线性表是否为空
public boolean isEmpty();
//判断线性表是否包含数据元素e
public boolean contains(Object e);
//返回元素e在线性表中的下标
public int indexOf(Object e);
//将元素e插入到线性表的下标为i的位置
public void insert(int i, Object e)throws OutOfBoundaryException;
//将元素e插入到元素obj之前
public boolean insertBefore(Object obj, Object e);
//将元素e插入到元素obj之后
public boolean insertAfter(Object obj, Object e);
//删除下标为i的数据元素,并返回
public Object remove(int i)throws OutOfBoundaryException;
//删除线性表表中第一个与e相同的元素
public boolean remove(Object e);
//将下标为i的数据元素替换为数据元素e,返回原数据元素
public Object replace(int i, Object e)throws OutOfBoundaryException;
//获取下标为i的数据元素
public Object get(int i)throws OutOfBoundaryException;
}
然后通过一个类去实现线性表的功能:
package cn.jxlg.singlelist;
/**
* 单链表的链式存储结构实现
*/
public class ListSLinked implements List{
private Strategy strategy; //数据元素比较策略
private SLNode head; //单链表头结点引用
private int size; //数据元素的个数
public ListSLinked() {
this(new DefaultStrategy());
}
public ListSLinked(Strategy strategy) {
this.strategy = strategy;
head=new SLNode();
size=0;
}
//辅助方法:获取数据元素e所在结点的前驱结点
public SLNode getPreNode(Object e){
SLNode p=head;
while(p.getNext()!=null)
if(strategy.equal(p.getNext().getData(),e)) return p;
else p=p.getNext();
return null;
}
//辅助方法:获取序号为0<=i<size的元素所在结点的前驱结点
public SLNode getPreNode(int i){
SLNode p=head;
for (;i>0;i--) p=p.getNext();
return p;
}
//获取序号为0<=i<size的元素的结点
public SLNode getNode(int i){
SLNode p=head.getNext();
for (;i>0;i--) p=p.getNext();
return p;
}
//返回线性表的元素个数
@Override
public int getSize() {
return size;
}
//如果线性表为空返回true,为false就不为空
@Override
public boolean isEmpty() {
return size==0;
}
//判断线性表中是否包含e元素
@Override
public boolean contains(Object e) {
SLNode p=head.getNext();
while(p!=null)
if (strategy.equal(p.getData(),e)) return true;
else p=p.getNext();
return false;
}
//返回元素e在线性表中的下标
@Override
public int indexOf(Object e) {
SLNode p=head.getNext();
int index=0;
while(p!=null)
if (strategy.equal(p.getData(),e)) return index;
else {
index++;
p=p.getNext();
}
return -1;
}
//在线性表的i处插入一个元素e
@Override
public void insert(int i, Object e) throws OutOfBoundaryException {
if (i<0||i>size)
throw new OutOfBoundaryException("错误,指定的插入序号越界");
SLNode p=getPreNode(i);
SLNode q=new SLNode(e,p.getNext());
p.setNext(q);
size++;
return;
}
//在元素obj的前面插入一个元素e
@Override
public boolean insertBefore(Object obj, Object e) {
SLNode p=getPreNode(obj);
if (p!=null){
SLNode q=new SLNode(e,p.getNext());
p.setNext(q);
size++;
return true;
}
else p=p.getNext();
return false;
}
//在元素obj的后面插入一个元素e
@Override
public boolean insertAfter(Object obj, Object e) {
SLNode p=head.getNext();
if (p!=null){
if (strategy.equal(p.getData(),obj)){
SLNode q=new SLNode(e,p.getNext());
p.setNext(q);
size++;
return true;
}
else p=p.getNext();
}
return false;
}
//删除线性表中索引为i的元素,并返回
@Override
public Object remove(int i) throws OutOfBoundaryException {
if (i<0||i>=size)
throw new OutOfBoundaryException("错误,指定的删除索引号越界");
SLNode p=getPreNode(i);
Object obj = p.getNext().getData();
p.setNext(p.getNext().getNext());
size--;
return obj;
}
//删除线性表中第一个与元素e相同的元素
@Override
public boolean remove(Object e) {
SLNode p=getPreNode(e);
if (p!=null){
p.setNext(p.getNext().getNext());
size--;
return true;
}
return false;
}
//将线性表中下标为i的元素替换为元素e,返回原始的数据
@Override
public Object replace(int i, Object e) throws OutOfBoundaryException {
if (i<0||i>=size)
throw new OutOfBoundaryException("错误。指定的序号越界");
SLNode p=getNode(i);
Object obj = p.getData();
p.setData(e);
return obj;
}
//获取线性表下标索引为i的元素,并返回
@Override
public Object get(int i) throws OutOfBoundaryException {
if (i<0||i>=size)
throw new OutOfBoundaryException("错误,指定的序号越界");
SLNode p=getNode(i);
return p.getData();
}
}