数据结构之 线性表

线性结构的特点:
在数据元素的非空有限集合中
1、存在唯一一个被称为“第一个”的数据元素,
2、存在唯一一个被称作“最后一个”的数据元素,
3、除第一个之外,集合中的每一个数据元素均只有一个前驱,
4、除最后一个之外,集合中的每一个数据元素均只有一个后继

线性表:是n个数据元素的有限序列。
线性表的顺序表示:
用一组地址连续的存储单元依次存储线性表的数据元素。
用数组实现具体参照jdk源码ArrayList

package java.util;

public class SeriesList<E> {

    private Object[] elements;

    //存储数据个数
    private int size;

    //修改次数
    protected transient int modCount = 0;

    public SeriesList(int length) {
        elements = new Object[length];
    }

    private SeriesList() {
        this(10);
    }

    /**
     * 通过索引获取
     * @param i
     * @return
     */
    public E get(int i) {
        rangeCheck(i);
        return (E) elements[i];
    }

    /**
     * 添加
     * @param e
     */
    public boolean add(E e) {
        ensureCapacity(size+1);
        elements[size++]=e;
        return true;
    }

    /**
     * 删除
     */
    public E remove(int i){
        rangeCheck(i);
        modCount++;
        E oldValue = (E) elements[i];

        int numMoved = size - i - 1;
        if (numMoved > 0)
            System.arraycopy(elements, i+1, elements, i,
                     numMoved);
        elements[--size] = null; // Let gc do its work

        return oldValue;
    }

    /**
     * 清空
     */
    public void clear() {
        modCount++;

        // Let gc do its work
        for (int i = 0; i < size; i++)
            elements[i] = null;

        size = 0;
    }

    /**
     * 确保数组的长度足够保存相关数据
     * @param minCapacity
     */
    private void ensureCapacity(int minCapacity) {
        modCount++;
        int oldLength = elements.length;
        if(oldLength<minCapacity) {
            int newLength = oldLength*3/2+1;
            if(newLength<minCapacity) {
                newLength = minCapacity;
            }
            elements = Arrays.copyOf(elements, newLength);
        }
    }

    /**
     * 检查角标越界
     * @param i
     */
    private void rangeCheck(int i) {
        if( i>=size ) {
            throw new IndexOutOfBoundsException("Index:"+i+",Size:"+size);
        }
    }

}

线性表的链式表示及实现
线性链表
用一组任意的存储单元来存储数据元素 , 不要求物理存储单元的连续性,由一系列结点组成,每个结点除了要存储数据外,还需存储指向后继结点或前驱结点的存储地址。
线性表的链式实现:
具体可以参照LinkedList双向链表

package java.util;

public class LinkedList<E> {

    private transient int size = 0;

    private transient Entry header = new Entry<E>(null, null, null);

    private Entry<E> next;

    public LinkedList () {
        header.next=header.pre=header; 
    }

    /**
     * 添加
     * @param e
     */
    public void add(E e) {
        addBefore(e,header);
    }

    /**
     * 按索引查找
     * @return 
     */
    public E get(int index) {
        return entry(index).element;
    }

    /**
     * 查找数据节点
     * @return 
     */
    private Entry<E> entry(int i){
        if(i<0||i>=size) {
            throw new IndexOutOfBoundsException("Index: "+i+
                    ", Size: "+size);
        }

        Entry<E> e = header;

        if (i < (size >> 1)) {
            for (int j = 0; j <= i; j++)
                e = e.next;
        } else {
            for (int j = size; j > i; j--)
                e = e.pre;
        }
        return e;

    }
    /**
     * 删除
     * @param index
     * @return
     */
    public E remove(int index) {
        return remove(entry(index));
    }

    private E remove(Entry<E> e) {
        if (e == header)
            throw new NoSuchElementException();

        E result = e.element;
        e.pre.next = e.next;
        e.next.pre = e.pre;
        e.next = e.pre = null;
        e.element = null;
        size--;
        return result;
    }


    public Entry addBefore(E e, Entry<E> entry) {
        Entry newEntry = new Entry<E>(e, entry.pre, entry);
        newEntry.next.pre=newEntry;
        newEntry.pre.next=newEntry;
        size++;
        return newEntry;
    }

    private static class Entry<E> {

        E element;

        Entry<E> pre;

        Entry<E> next;

        public Entry(E element,Entry<E> pre,Entry<E> next){
            this.element = element;
            this.pre = pre;
            this.next = next;
        }

    }

}

顺序存储和链式存储对比

顺序存储结构
优点
实现比较简单
查找指定位置的元素效率很快,时间复杂度为常数阶O(1)
无需额外存储元素之间的逻辑关系(链式存储由于存储空间随机分配,需要存储元素之间的逻辑关系)
缺点
需要预先分配存储空间,如果数据元素数量变化较大,很难确定存储容量,并导致空间浪费
若频繁进行插入删除操作,则可能需要频繁移动大量数据元素
链式存储结构
优点
不需要提前分配存储空间,元素个数不受限制
对于插入删除操作,在已找到目标位置前提下,效率很高,仅需处理元素之间的引用关系,时间复杂度为O(1)
缺点
实现相对复杂
查找效率较低,最坏情况下需要遍历整张表
由于物理存储位置不固定,需要额外存储数据元素之间的逻辑关系

循环链表 特点:
表中最后一个结点的指针域指向头结点,整个链表形成一个环。从表中任一结点出发均可找到表中其他结点。
双向链表:
在双向链表的结点中有两个指针域,其一指向直接后继,另一指向直接前驱。
双向链表的的每一个结点,包含两个指针域,一个指向它的前驱结点,一个指向它的后继结点。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值