Java中单链表学习

104 阅读4分钟

链表

Java数据结构链表是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的地址。链表可分为单向链表和双向链表。单向链表的每个节点包含两个值:当前节点的值和一个指向下一个节点的链接。双向链表的每个节点有三个值:数值、向后的节点链接、向前的节点链接。

单链表

Java中单链表是一种基础的数据结构,它由一系列的节点组成,每个节点包含一个数据域和一个指向下一个节点的指针域。单链表的第一个节点称为头节点,最后一个节点的指针域为null。

常见操作

  • 头插法:在链表的头部插入一个新的节点,让新节点的指针域指向原来的头节点,然后更新头节点为新节点。
  • 尾插法:在链表的尾部插入一个新的节点,需要先找到链表的最后一个节点,然后让最后一个节点的指针域指向新节点,新节点的指针域为null。
  • 任意位置插入:在链表的指定位置插入一个新的节点,需要先找到该位置的前一个节点,然后让前一个节点的指针域指向新节点,新节点的指针域指向原来的后一个节点。
  • 查找是否包含关键字:遍历链表,比较每个节点的数据域和关键字是否相等,如果找到相等的返回true,否则返回false。
  • 得到单链表的长度:遍历链表,用一个计数器记录遍历过的节点个数,最后返回计数器的值。
  • 打印单链表:遍历链表,输出每个节点的数据域。
  • 删除第一次出现关键字为key的节点:遍历链表,找到第一个数据域为key的节点和它的前一个节点,然后让前一个节点的指针域指向后一个节点,释放当前节点。
  • 删除所有值为key的节点:遍历链表,找到所有数据域为key的节点和它们的前一个节点,然后让前一个节点的指针域指向后一个节点,释放当前节点。

优缺点

  • 优点:
  1. 单链表是一种动态的数据结构,可以根据需要增加或减少节点,不需要预先分配固定的空间,节省了内存。
  2. 单链表的插入和删除操作比较简单,只需要修改指针域即可,不需要移动其他元素,提高了效率。
  3. 单链表可以用来实现其他的数据结构,如栈、队列、多项式等。
  • 缺点:
  1. 单链表的存储空间开销较大,每个节点除了数据域外还需要一个指针域,占用额外的空间。
  2. 单链表的访问效率较低,不能随机访问任意位置的元素,只能从头节点开始顺序遍历,时间复杂度为O(n)。
  3. 单链表的反向遍历比较困难,需要借助栈或递归等方式实现。

单链表的增删改查

// 定义一个节点类
class Node {
    // 数据域
    int data;
    // 指针域
    Node next;
    // 构造方法
    public Node(int data) {
        this.data = data;
    }
}

// 定义一个单链表类
class MyLinkedList {
    // 头节点
    Node head;
    
    // 增加节点(尾插法)
    public void add(int data) {
        // 创建一个新节点
        Node node = new Node(data);
        // 如果链表为空,直接让头节点指向新节点
        if (head == null) {
            head = node;
        } else {
            // 否则,找到链表的最后一个节点,让它的指针域指向新节点,新节点的指针域为null
            Node cur = head;
            while (cur.next != null) {
                cur = cur.next;
            }
            cur.next = node;
        }
    }
    
    // 删除节点(根据数据域)
    public void delete(int data) {
       // 如果链表为空,直接返回
       if (head == null) {
           return;
       }
       // 如果头节点就是要删除的节点,直接让头节点指向下一个节点,并释放原来的头节点
       if (head.data == data) {
           head = head.next;
           return;
       }
       // 否则,找到要删除的节点的前一个节点,让它的指针域指向后一个节点,并释放要删除的节点
       Node prev = head;
       Node cur = head.next;
       while (cur != null) {
           if (cur.data == data) {
               prev.next = cur.next;
               break;
           }
           prev = cur;
           cur = cur.next;
       }
    }
    
    // 修改节点(根据数据域)
    public void update(int oldData, int newData) {
        // 如果链表为空,直接返回
        if (head == null) {
            return;
        }
        // 遍历链表,找到要修改的节点,更新它的数据域
        Node cur = head;
        while (cur != null) {
            if (cur.data == oldData) {
                cur.data = newData;
                break;
            }
            cur = cur.next;
        }
    }
    
    // 查询节点(根据数据域)
    public boolean search(int data) {
        // 如果链表为空,直接返回false
        if (head == null) {
            return false;
        }
        // 遍历链表,比较每个节点的数据域和查询的数据是否相等,如果找到相等的返回true,否则返回false
        Node cur = head;
        while (cur != null) {
            if (cur.data == data) {
                return true;
            }
            cur = cur.next;
        }
        return false;
    }
    
    // 打印单链表
    public void display() {
        Node cur = head;
        while (cur != null) {
            System.out.print(cur.data + " ");
            cur = cur.next;
        }
        System.out.println();
    }
}