数据结构之链表

链表的基本概念

链表是一种线性数据结构,由一系列节点组成,每个节点包含数据域和指针域。数据域存储数据,指针域存储下一个节点的地址。链表可以动态分配内存,不需要预先知道数据量的大小。

链表的类型

  1. 单链表:每个节点只有一个指针域,指向下一个节点。
  2. 双链表:每个节点有两个指针域,分别指向前一个节点和后一个节点。
  3. 循环链表:尾节点的指针域指向头节点,形成一个环。

链表的操作

插入节点

在链表中插入节点需要调整指针的指向。例如,在单链表中插入一个新节点:

  • 新节点的指针指向原位置的下一个节点。
  • 原位置的指针指向新节点。

删除节点

删除节点时,需要将前一个节点的指针指向被删除节点的下一个节点。例如,在单链表中删除一个节点:

  • 找到待删除节点的前驱节点。
  • 将前驱节点的指针指向待删除节点的后继节点。

遍历链表

从头节点开始,依次访问每个节点,直到指针域为 null

链表的优缺点

优点

  • 动态内存分配,不需要预先知道数据量。
  • 插入和删除操作高效,时间复杂度为 O(1)(已知位置时)。

缺点

  • 访问元素需要从头遍历,时间复杂度为 O(n)
  • 需要额外的空间存储指针。

链表的代码实现(JAVA)

java 复制代码
/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: zhany
 * Date: 2025-10-13
 * Time: 11:55
 */
public class MyLink implements IList{
    static class ListNode {
        int val;
        ListNode prev;
        ListNode next;

        public ListNode(int val) {
            this.val = val;
        }
    }
    public ListNode head;
    public ListNode last;
    @Override
    public void addFirst(int data) {
        ListNode node = new ListNode(data);
        if (head == null) {
            head = last  = node;
        } else {
            node.next = head;
            head.prev = node;
            head = node;
        }
        }

    @Override
    public void addLast(int data) {
    ListNode node = new ListNode(data);
        if (last == null) {
            head = last = node;
        } else {
            last.next = node;
            node.prev = last;
            last = node;
        }
    }

    @Override
    public boolean addIndex(int index, int data) {
        int len = size();
        if(len < 0 || len > size()){
            return false;
        }
        if (len == 0) {
            addFirst(data);
        }
        if (len == size()){
            addLast(data);
        }
        ListNode cur = findindex(index);
        ListNode node  =new ListNode(data);
        node.next = cur;
        cur.prev.next = node;
        node.prev = cur.prev;
        cur.prev = node;

        return true;
    }
    private ListNode findindex(int index) {
        ListNode cur = head;
        while(index == 0){
            cur  =cur.next;
            index--;
        }
        return cur;
    }

    @Override
    public boolean contains(int key) {
        ListNode cur = head;
        while(cur != null && cur.next !=null){
            if(cur.val == key){
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

    @Override
    public void remove(int key) {
        ListNode cur  = head;
    while(cur != null){
        if (cur.val == key){
            if (cur == head) {
                head = head.next;
                if (head != null) {
                    head.prev = null;
                }
            } else {
                cur.prev.next = cur.next;
                if (cur.next == null) {
                    last = last.prev;
                } else {
                    cur.next.prev = cur.prev;
                }
            }
            return;
        }
        cur = cur.next;
    }
    }

    @Override
    public void removeAllKey(int key) {
        ListNode cur = head;
        while(cur != null){
            if (cur == head) {
                head = head.next;
                if (head.prev != null) {
                    head.prev = null;
                }

            } else{
                cur.prev.next = cur.next;
                if (cur.next == null) {
                    last = last.prev;
                } else {
                    cur.next.prev = cur.prev;
                }
            }
            cur =cur.next;
        }

    }

    @Override
    public int size() {
        ListNode cur = head;
        int len = 0;
        while (cur != null && cur.next !=null){
            cur = cur.next;
            len++;
        }
        return len;
    }

    @Override
    public void display() {
    ListNode cur = head;
    while(cur != null && cur.next != null){
        System.out.println(cur.val+"  ");
        cur =cur.next;
    }
        System.out.println();
    }

    @Override
    public void clear() {
        ListNode cur = head;
        while(cur != null){
            ListNode curN =cur.next;
            cur.prev =null;
            cur.next = null;
            cur = curN;
        }
        last = head = null;
    }
}

链表的应用场景

  1. 动态内存管理:适用于需要频繁插入和删除的场景。
  2. 实现其他数据结构:如栈、队列、哈希表等。
  3. 文件系统:文件目录结构可以用链表表示。

链表是一种基础但强大的数据结构,理解其原理和实现方式对编程和算法学习至关重要。

相关推荐
rannn_1112 小时前
【力扣hot100】链表专题|160、206、234、141、142
java·算法·leetcode·链表·面试·开发
LuminousCPP6 小时前
数据结构-双向循环链表
c语言·数据结构·笔记·链表
白狐_7987 小时前
408数据结构第5章:树与二叉树②——遍历、线索树、森林与哈夫曼
数据结构·算法·深度优先
Jasmine_llq9 小时前
《P15800 [GESP202603 六级] 选数》
数据结构·long long·逆序线性 dp·从后往前推导·转移严格遵循题意·防止总和溢出·复杂度on
疯狂打码的少年9 小时前
【数据结构】串(字符串):基本概念与存储
数据结构·笔记
纵有疾風起10 小时前
线性表的定义与基本操作 — 从逻辑结构到 ADT 接口
数据结构·算法·408·线性表·adt
wuyk55511 小时前
1.栈:后进先出的线性数据结构
c语言·数据结构·stm32·单片机
LuminousCPP12 小时前
数据结构-时间与复杂度|时间/空间复杂度 + 两道力扣练习 + 二分查找复盘
c语言·数据结构·经验分享·算法·leetcode
Nil20812 小时前
leetcode 三数之和
数据结构·算法·leetcode
noipp12 小时前
推荐题目:洛谷 P16689 出征
java·开发语言·数据结构·c++·算法·洛谷·luogu