链表小结


前言

List 的两个重要实现类 ArrayList 和 LinkedList,各自的特点都是非常明显的。

ArrayList:

  1. 底层是数组,在逻辑上和物理上来说都是连续的,也就是说数组在内存上是存储在连续的空间里面的,这种存储的优势是通过 index(索引)可以实现快速查找和随机访问,操作复杂度只是O(1)。
  2. ArrayList 的缺点也很显然。对于插入和删除操作,每次插入或者删除元素,都需要对插入位置后面的元素进行后移或前移操作;如果数组已满还需要进行空间申请、拷贝数据、释放空间的一系列扩容操作,最差时间复杂度达到了O(N),对于规模大的数组来说不太友好。

LinkedList:

  1. 相比于ArrayList来说有着很大的不同。它将每个元素定义为一个节点,在节点中又申请了一块空间用于存放下一个节点的指针(pointer)。由于有指针的存在,链表在内存中一般来说都不是连续的,充分利用了内存中的碎片空间。
  2. 链表的插入、删除操作时间复杂度由于指针的存在变成了O(1)。但是,链表是不支持随机访问的,每次查找或者访问都需要遍历链表,从最差角度和平均角度来看,时间复杂度是O(N)。

LinkedList 和 ArrayList 作为基本的数据结构,在程序设计中经常用到,根据场景的不同使用不同的数据结构也是能够有很好的效果。相比较而言链表更抽象,更难理解,所以对链表 LinkedList 的实现以及 leetcode 刷过的所有链表题型进行一个归纳总结。


一、LinkedList(链表)

链表总体来说有很多类型,这里只是记录一下常用的单向链表、双向链表以及循环链表。

1. 单向链表

单向链表比较简单,每个节点只有两个域:数据域(val)和指针域(next),指针域 next 指向下一个节点,尾结点的 next 是 null 。
1.1 单向链表节点定义

    /**
     * Definition for singly-linked list.
     */
    class SinglyNode {
   
        int val;// 数据域
        SinglyNode next;// 指针域
        public SinglyNode(int val) {
   
            this.val = val;
        }
    }

1.2 单向链表的实现

public class MySinglyLinkedList {
   

    /**
     * Definition for singly-linked list.
     */
    class SinglyNode {
   
        int val;
        SinglyNode next;
        public SinglyNode(int val) {
   
            this.val = val;
        }
    }

    public SinglyNode head;// 头结点

    /**
     * 头插法
     */
    public void addFirst(int val) {
   
        SinglyNode node = new SinglyNode(val);
        // 第一次插入结点
        if (this.head == null) {
   
            this.head = node;
            return;
        }
        node.next = this.head;
        this.head = node;
    }

    /**
     * 尾插法
     */
    public void addLast(int val) {
   
        SinglyNode node = new SinglyNode(val);
        // 第一次插入结点
        if (this.head == null) {
   
            this.head = node;
            return;
        }
        // 遍历到尾部
        SinglyNode cur = this.head;
        while (cur.next != null) {
   
            cur = cur.next;
        }
        // 插入结点
        cur.next = node;
    }

    /**
     * 任意位置插入
     */
    public void addIndex(int index, int val) {
   
        // index 不合法
        if (index < 0 || index > size()) return;
        // 下标为 0, 头插法
        if (index == 0) {
   
            addFirst(val);
            return;
        }
        // 查找 index 的前驱
        SinglyNode prev = searchPrev(index);
        SinglyNode node = new SinglyNode(val);
        // 插入
        node.next = prev.next;
        prev.next = node;
    }

    /**
     * 查找 index 结点的前驱
     */
    public SinglyNode searchPrev(int index) {
   
        int count = 0;
        SinglyNode cur  = this.head;
        while (count < index-1) {
   
            cur = cur.next;
            count++;
        }
        return cur;
    }

    /**
     * 查找在单链表当中是否包含关键字 key
     */
    public boolean contains(int val) {
   
        SinglyNode cur = this.head;
        while (cur != null) {
   
            if (cur.val == val) {
   
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

    /**
     * 删除第一次出现关键字为key的节点
     */
    public void remove(int val) {
   
        if (this.head.val == val) {
   
            this.head = this.head.next;
            return;
        }
        SinglyNode cur = this.head;// 遍历查找关键字
        SinglyNode prev = null;// 遍历结点的前驱结点
        // 查找关键字
        while (cur != null) {
   
            if (cur.val == val) {
   
                prev.next 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值