数据结构-线性表

作者: Shimmer_ | 来源:发表于2021-01-24 22:19 被阅读0次

[TOC]

线性表-List

list是最简单的数据结构,可分为顺序表与链表,顺序表内部数据存储由数组实现,链表则是由一个个自定义的节点Node进行串联,就像锁链一样

List接口主要方法

  • int size();:表长度
  • boolean isEmpty();:表是否为空
  • boolean add(int index, E element);:添加元素
  • boolean remove(int index);::移除元素

顺序表--实现类ArrayList

因为内部是由数组实现(数组初始化时长度即固定),所有顺序表在增加元素时有动态扩容的需求,且元素发生变换时(物理地址连续),容易频繁引起数组的批量复制修改;

  • transient Object[] elementData;:内部存储数组

  • 增:元素添加时,如果中间插入还会触发对应位置及后续元素整体后移,如果size不满足增加后大小则会触发动态增长

    public void add(int index, E element) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }
    

    元素添加时,会进行size大小的校验,if (minCapacity - elementData.length > 0) grow(minCapacity);通过后就会触发增长,

    private void grow(int minCapacity) {
         // overflow-conscious code
         int oldCapacity = elementData.length;
         int newCapacity = oldCapacity + (oldCapacity >> 1);
         if (newCapacity - minCapacity < 0)
             newCapacity = minCapacity;
         if (newCapacity - MAX_ARRAY_SIZE > 0)
             newCapacity = hugeCapacity(minCapacity);
         // minCapacity is usually close to size, so this is a win:
         elementData = Arrays.copyOf(elementData, newCapacity);
    }
    
  • 删:删除对应位置的元素,后续元素copy并前移

     public E remove(int index) {
         if (index >= size)
             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    
         modCount++;
         E oldValue = (E) elementData[index];
    
         int numMoved = size - index - 1;
         if (numMoved > 0)
             System.arraycopy(elementData, index+1, elementData, index,
                              numMoved);
         elementData[--size] = null; // clear to let GC do its work
    
         return oldValue;
     }
    

链表--实现类LinkedList

链表内部是由自定义的节点进行连接的,所以能查找上一节点与下一节点的称为双链表,只能查找下一节点的称为单链表。单链表由于只能从头往尾查询,在节点查找上效率比双链表低一半(双链表可以通过位置与长度比较判断离头尾哪个更近)

  • Node:自定义存储节点

    private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;
    
        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }
    
    • transient Node<E> first;:头节点
    • transient Node<E> last;:尾节点
  • 增:触发指定位置的Node 及前Node的断裂与再连接

    public void add(int index, E element) {
        checkPositionIndex(index);
    
        if (index == size)
            linkLast(element);
        else
            linkBefore(element, node(index));
    }
    

    前节点preNode,指定位置节点node,添加节点newNode;

    1. newNode.prev = preNode;
    2. newNode.next = node;
    3. preNode.next = newNode;
    4. node.prev = newNode;

    在实际中要注意引用的变化,perNode一般是用node.prev来代替,如果node引用改变容易引起错误指向。同时注意前后节点不存在的情况(即头尾节点操作)

  • 删:触发指定位置的Node 与前后Node的断裂与再连接

    public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }
    E unlink(Node<E> x) {
        // assert x != null;
        final E element = x.item;
        final Node<E> next = x.next;
        final Node<E> prev = x.prev;
    
        if (prev == null) {
            first = next;
        } else {
            prev.next = next;
            x.prev = null;
        }
    
        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }
    
        x.item = null;
        size--;
        modCount++;
        return element;
    }
    

    前节点preNode,指定位置节点node,后节点nextNode;

    1. preNode.next = nextNode;
    2. nextNode.prev = preNode;
    3. node.next = null;
    4. node.prev = null;
    5. node.item = null;

    同样注意:在实际中要注意引用的变化,perNode,nextNode一般是间接引用,如果node引用改变容易引起错误指向。同时注意前后节点不存在的情况(即头尾节点操作)

    链表的其他形式

    • 循环链表 : 将单链表中终端节点的指针端由空指针改为指向头节点,就使整个单链表形成一个环,这种头尾相连的单链表称为单循环链表,简称循环链表
    • 双向循环链表 : 双向循环链表是单向循环链表的每个节点中,再设置一个指向其前驱节点的指针域
      与双向链表的区别:
      双向链表没有闭合形成环,头节点、尾节点并不互相连接指向

对比

List 优点 缺点 应用
顺序表 存储空间连续、允许随机访问、尾插,尾删方便 插入效率低 删除效率低 长度固定 普遍在用(Android中基本存储查询操作较多,不涉及太多中间增删)
单链表 随意进行增删改、插入效率高、删除效率高、长度可以随意修改 内存不连续、不能随机查找、查询效率低 MessageQueue、HashMap
双链表 随意进行增删改、插入效率高、删除效率高、长度可以随意修改 内存不连续、不能随机查找、查询效率比单链表快一倍 LinkedList

相关算法题

  1. 反转单链表 https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof/
  2. 合并两个有序链表 https://leetcode-cn.com/problems/merge-two-sorted-lists/
  3. 两数相加 https://leetcode-cn.com/problems/add-two-numbers/
  4. 两两交换 https://leetcode-cn.com/problems/swap-nodes-in-pairs/

相关文章

  • 目录 - 数据结构

    总目录 数据结构 第01局:绪论 数据结构 第02局:线性表 上 数据结构 第03局:线性表 下 数据结构 第04...

  • iOS设计模式--迭代器

    学习迭代器之前,先看一种数据结构--线性表 线性表:线性表是最基本,最简单,也是最常用的一种数据结构。 线性表中数...

  • Java造轮子-数据结构-线性表

    数据结构-线性表 @(数据结构) 线性表是数据结构中的逻辑结构。可以存储在数组上,也可以存储在链表上。 顺序表(数...

  • 数据结构与算法02——线性表

    一、 线性表线性表是最基本、最简单、也是最常用的一种数据结构。线性表(linear list)是数据结构的一种,一...

  • 23-二叉树基础(上):什么样的二叉树适合用数组来存储?

    前面讲的都是线性表结构,栈、队列等等。今天讲一种非线性表结构,树。树这种数据结构比线性表的数据结构要复杂得多,内容...

  • 数据结构之线性表

    数据结构之线性表 1. 什么是线性表 线性表是一种最常用,最简单的一种数据结构。它是n个数据元素的有限序列。n 为...

  • 玩转数据结构之线性表

    0. 序言 学习数据结构的第一步,让我们来了解下线性表。 1. 概念 线性表是最基本的数据结构。一个线性表是由N个...

  • 栈和队列

    栈和队列是两种应用非常广泛的数据结构,它们都来自线性表数据结构,都是“操作受限”的线性表。 栈 栈(Stack):...

  • 2019-06-10

    数据结构线性表自己高数中值定理

  • 数据结构探险之线性表篇(上):顺序表

    数据结构探险之线性表篇 将要学到得: 线性表(链表) 什么是线性表? 线性表是n个数据元素的有限序列 排列之后成线...

网友评论

    本文标题:数据结构-线性表

    本文链接:https://www.haomeiwen.com/subject/sxuvzktx.html