数据结构之链表

链表的基本概念

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

链表的类型

  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. 文件系统:文件目录结构可以用链表表示。

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

相关推荐
CSharp精选营2 天前
关系型 vs 非关系型:从原理到选型,一文搞定数据库核心分类
数据结构·nosql·关系型数据库·非关系型数据库·技术选型
刘马想放假5 天前
Modbus 全栈技术解析:TCP、RTU、ASCII、RTU over TCP
数据结构·网络协议
北域码匠6 天前
冒泡排序太慢?鸡尾酒排序双向优化,原生 C# 零第三方库完整代码
数据结构·排序算法·泛型·c# 算法·鸡尾酒排序·原生 c# 开发·冒泡排序优化·嵌入式算法
Darling噜啦啦13 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
小小工匠14 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
玖玥拾14 天前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
Qres82114 天前
算法复键——树状数组
数据结构·算法
牛油果子哥q14 天前
并查集(DSU)超精讲,路径压缩、按秩合并、万能模板、连通性判定、最小生成树与刷题实战全解
数据结构·c++·最小生成树·并查集
凌波粒14 天前
LeetCode--491.递增子序列(回溯算法)
数据结构·算法·leetcode
疯狂成瘾者14 天前
Java 集合 LinkedList 详解:链表结构、常用方法和队列使用
java·开发语言·链表