Java 链表知识点详解

一、链表的基本概念

    链表(Linked List)是一种常见的线性数据结构,它由一系列节点(Node)组成,每个节点包含数据域和一个指向下一个节点的引用(指针)。与数组相比,链表的优势在于插入和删除操作效率高(时间复杂度 O (1)),但随机访问效率低(需从头遍历,时间复杂度 O (n))。

链表的分类

  1. 单向链表:每个节点包含数据和指向下一个节点的引用,最后一个节点的引用为 null。
  2. 双向链表:每个节点包含数据、指向前一个节点的引用和指向后一个节点的引用,头节点的前驱引用和尾节点的后继引用为 null。
  3. 循环链表:与单向链表类似,但最后一个节点的引用指向头节点,形成一个环。

二、Java 中链表的实现

单向链表的实现

在 Java 中,我们可以通过定义节点类和链表类来实现单向链表:

// 节点类
class Node {
    int data;
    Node next;
    
    public Node(int data) {
        this.data = data;
        this.next = null;
    }
}

// 单向链表类
class LinkedList {
    private Node head;
    private int size;
    
    public LinkedList() {
        head = null;
        size = 0;
    }
    
    // 在链表尾部添加元素
    public void add(int data) {
        Node newNode = new Node(data);
        if (head == null) {
            head = newNode;
        } else {
            Node current = head;
            while (current.next != null) {
                current = current.next;
            }
            current.next = newNode;
        }
        size++;
    }
    
    // 删除指定位置的元素
    public void remove(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException();
        }
        
        if (index == 0) {
            head = head.next;
        } else {
            Node prev = getNode(index - 1);
            prev.next = prev.next.next;
        }
        size--;
    }
    
    // 获取指定位置的节点
    private Node getNode(int index) {
        Node current = head;
        for (int i = 0; i < index; i++) {
            current = current.next;
        }
        return current;
    }
    
    // 其他方法...
}

Java 内置链表类

Java 集合框架中提供了LinkedList类,它实现了双向链表结构,并实现了ListDeque接口,因此可以作为列表、队列或栈使用:

import java.util.LinkedList;

public class LinkedListExample {
    public static void main(String[] args) {
        // 创建LinkedList
        LinkedList<Integer> list = new LinkedList<>();
        
        // 添加元素
        list.add(1);        // 添加到尾部
        list.addFirst(0);   // 添加到头部
        list.addLast(2);    // 添加到尾部
        
        // 访问元素
        int first = list.getFirst();  // 获取头部元素
        int last = list.getLast();    // 获取尾部元素
        
        // 删除元素
        list.removeFirst();  // 删除头部元素
        list.removeLast();   // 删除尾部元素
        
        // 遍历链表
        for (int num : list) {
            System.out.println(num);
        }
    }
}

三、链表的常见操作及实现

1. 链表反转

链表反转是面试中的经典问题,可通过迭代或递归方法实现:

// 迭代法反转链表
public Node reverseList(Node head) {
    Node prev = null;
    Node curr = head;
    while (curr != null) {
        Node nextTemp = curr.next;
        curr.next = prev;
        prev = curr;
        curr = nextTemp;
    }
    return prev;
}

// 递归法反转链表
public Node reverseListRecursive(Node head) {
    if (head == null || head.next == null) return head;
    Node p = reverseListRecursive(head.next);
    head.next.next = head;
    head.next = null;
    return p;
}

2. 链表中环的检测

使用快慢指针法检测链表中是否存在环:

public boolean hasCycle(Node head) {
    if (head == null) return false;
    Node slow = head;
    Node fast = head.next;
    while (slow != fast) {
        if (fast == null || fast.next == null) return false;
        slow = slow.next;
        fast = fast.next.next;
    }
    return true;
}

3. 合并两个有序链表

递归合并两个有序链表:

public Node mergeTwoLists(Node l1, Node l2) {
    if (l1 == null) return l2;
    if (l2 == null) return l1;
    
    if (l1.data < l2.data) {
        l1.next = mergeTwoLists(l1.next, l2);
        return l1;
    } else {
        l2.next = mergeTwoLists(l1, l2.next);
        return l2;
    }
}

四、链表的应用场景

  1. 实现栈和队列:链表的插入和删除操作效率高,适合实现栈和队列。
  2. 内存管理:操作系统的内存分配常使用链表结构。
  3. 哈希表的冲突处理:哈希表解决冲突时,常使用链表存储相同哈希值的元素。
  4. 文件系统:文件系统的目录结构通常采用链表实现。

五、链表与数组的对比

特性链表数组
存储方式动态分配内存,不连续连续内存空间
插入 / 删除效率O (1)(已知位置)O (n)(需移动元素)
随机访问效率O (n)(需遍历链表)O (1)(通过下标直接访问)
内存占用每个节点需额外存储引用无需额外存储引用

六、常见思考题

  1. 如何判断链表是否有环?
  2. 如何找到链表的中间节点?
  3. 如何反转一个链表?
  4. 如何合并两个有序链表?
  5. 如何删除链表的倒数第 N 个节点?

掌握链表的基本原理和常见操作,对于理解数据结构和解决算法问题至关重要。通过不断练习和深入思考,你将能够灵活运用链表解决各种实际问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值