• 线性表链表存储结构(单链表)


      链表是一系列的存储数据元素的单元通过指针串接起来形成的,因此每个单元至少有两
    个域,一个域用于数据元素的存储,另一个域是指向其他单元的指针。这里具有一个数据域
    和多个指针域的存储单元通常称为 结点(node)

      在 Java 中没有显式的指针类型,然而实际上对象的访问就是使用指针来实现的,即在
    Java 中是使用对象的引用来替代指针的。因此在使用 Java 实现该结点结构时,一个结点本
    身就是一个对象。结点的数据域 data 可以使用一个 Object 类型的对象来实现,用于存储任
    何类型的数据元素,并通过对象的引用指向该元素;而指针域 next 可以通过节点对象的引
    用来实现。
      由于数据域存储的也是对象引用,因此数据实际上和图 3-2 中一样,是通过指向数据的
    物理存储地址来完成存储的,但是在后面叙述的方便,我们在图示中都将数据元素直接画到
    了数据域中,请读者注意实际的状态与之是有区别的。


      上面的单链表结点结构是结点的一种最简单的形式,除此之外还有其他不同的结点结
    构,但是这些结点结构都有一个数据域,并均能完成数据元素的存取。为此在使用 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() {
            this(null,null);
        }
        public SLNode(Object ele, SLNode next){
            this.element = ele;
            this.next = next;
        }
        public SLNode getNext(){
            return next;
        }
        public void setNext(SLNode next){
            this.next = next;
        }
        /**************** Methods of Node Interface **************/
        public Object getData() {
            return element;
        }
        public void setData(Object obj) {
            element = obj;
        }
    }

    单链表实现

    public class ListSLinked implements List{
        private SLNode head; //单链表首结点引用
        private int size; //线性表中数据元素的个数
        public ListSLinked () {
            head = new SLNode();
            size = 0;
        }
        //辅助方法:获取数据元素 e 所在结点的前驱结点
        private SLNode getPreNode(Object e){
            SLNode p = head;
            while (p.getNext()!=null)
                if (p.getNext().getData().equals(e)) return p;
                else p = p.getNext();
            return null;
        }
        //辅助方法:获取序号为 0<=i<size 的元素所在结点的前驱结点
        private SLNode getPreNode(int i){
            SLNode p = head;
            for (; i>0; i--) p = p.getNext();
            return p;
        }
        //获取序号为 0<=i<size 的元素所在结点
        private SLNode getNode(int i){
            SLNode p = head.getNext();
    
            for (; i>0; i--) p = p.getNext();
            return p;
        }
        //返回线性表的大小,即数据元素的个数。
        public int getSize() {
            return size;
        }
        //如果线性表为空返回 true,否则返回 false。
        public boolean isEmpty() {
            return size==0;
        }
        //判断线性表是否包含数据元素 e
        public boolean contains(Object e) {
            SLNode p = head.getNext();
            while (p!=null)
                if (p.getData().equals(e)) return true;
                else p = p.getNext();
            return false;
        }
        //返回数据元素 e 在线性表中的序号
        public int indexOf(Object e) {
            SLNode p = head.getNext();
            int index = 0;
            while (p!=null)
                if (p.getData().equals(e)) return index;
                else {index++; p = p.getNext();}
            return -1;
        }
        //将数据元素 e 插入到线性表中 i 号位置
        public void insert(int i, Object e) throws IndexOutOfBoundsException {
            if (i<0||i>size)
                throw new IndexOutOfBoundsException("错误,指定的插入序号越界。");
            SLNode p = getPreNode(i);
            SLNode q = new SLNode(e,p.getNext());
            p.setNext(q);
            size++;
            return;
        }
    
    
    
        //删除线性表中序号为 i 的元素,并返回之
        public Object remove(int i) throws IndexOutOfBoundsException {
            if (i<0||i>=size)
                throw new IndexOutOfBoundsException("错误,指定的删除序号越界。");
            SLNode p = getPreNode(i);
            Object obj = p.getNext().getData();
            p.setNext(p.getNext().getNext());
            size--;
            return obj;
        }
        //删除线性表中第一个与 e 相同的元素
        public boolean remove(Object e) {
            SLNode p = getPreNode(e);
            if (p!=null){
                p.setNext(p.getNext().getNext());
                size--;
                return true;
            }
            return false;
        }
    
        //返回线性表中序号为 i 的数据元素
        public Object get(int i) throws IndexOutOfBoundsException {
            if (i<0||i>=size)
                throw new IndexOutOfBoundsException("错误,指定的序号越界。");
            SLNode p = getNode(i);
            return p.getData();
        }
    }

    基于时间的比较
      线性表的操作主要有查找、插入、删除三类操作。
    对于查找操作有基于序号的查找,即存取线性表中 i 号数据元素。由于数组有随机存取
    的特性,在线性表的顺序存储实现中可以在Θ(1)的时间内完成;而在链式存储中由于需要
    从头结点开始顺着链表才能取得,无法在常数时间内完成,因此顺序存储优于链式存储。查
    找操作还有基于元素的查找,即线性表是否包含某个元素、元素的序号是多少,这类操作线
    性表的顺序存储与链式存储都需要从线性表中序号为 0 的元素开始依次查找,因此两种实现
    的性能相同。综上所述,如果在线性表的使用中主要操作是查找,那么应当选用顺序存储实
    现的线性表。
    对于基于数据元素的插入、删除操作而言,当使用数组实现相应操作时,首先需要采用
    顺序查找定位相应数据元素,然后才能插入、删除,并且在插入、删除过程又要移动大量元
    素;相对而言链表的实现只需要在定位数据元素的基础上,简单的修改几个指针即可完成,
    因此链式存储优于顺序存储。对于基于序号的插入、删除操作,因为在顺序存储中平均需要
    移动一半元素;而在链式存储中不能直接定位,平均需要比较一半元素才能定位。因此顺序
    存储与链式存储性能相当。综上所述,如果在线性表的使用中主要操作是插入、删除操作,
    那么选用链式存储的线性表为佳。

  • 相关阅读:
    【剑指Offer】面试题55
    一大波趣图:CSS的力量
    你必须收藏的Github技巧
    3月份GitHub上最热门的Java开源项目
    趣图:快下班了,剩一个bug,修复一下再走
    Java程序员必备的Intellij插件
    为什么前后端分离了,你比从前更痛苦?
    趣图:好好干,今天再加个班
    高并发下的下单功能设计
    Mybatis的基本要素--核心对象
  • 原文地址:https://www.cnblogs.com/duan2/p/12782233.html
Copyright © 2020-2023  润新知