单链表的链式存储实现

线性表除了顺序存储的实现还有另一种链式存储的实现方式,就是使用指针的方式将存储元素的结点连接起来;这种方式在执行插入或删除运算的时候,就不需要移动元素来腾出空间和填补空间,因此我们在进行这些操作的时候就会特别的方便。
链表是通过一系列的存储数据的结点用指针连接起来形成的,所以每一个结点至少都需要两个域;一个用来存储数据的数据域,一个是指向下一个结点的指针域。
结点的结构图

由于数据域存储的也是对象的引用,因此数据实际上是通过指向数据的物理存储地址来完成存储的,上面的单链表结点结构是结点的一种最简单的形式,这些结点结构都是只有一个数据域并能够完成数据元素的存储,因此在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();
    }
}

发布了42 篇原创文章 · 获赞 6 · 访问量 2967

猜你喜欢

转载自blog.csdn.net/qq_44666176/article/details/100567481
今日推荐