Java数据结构——链表(完整详解单向链表,附有案例+代码)

三.链表

3.1 概述

链表是数据元素的线性集合,其每个元素都指向下一个元素,元素存储上并不连续。

可以分为:

  • 单向链表,每个元素只知道其下一个元素是谁

    在这里插入图片描述

  • 双向链表,每个元素知道其上一个元素和下一个元素

    在这里插入图片描述

  • 循环链表,通常的链表尾节点 tail 指向的都是 null,而循环链表的 tail 指向的是头节点 head

    在这里插入图片描述

链表内还有一种特殊的节点称为哨兵(Sentinel)节点,也叫做哑元( Dummy)节点,它不存储数据,通常用作头尾,用来简化边界判断,如下图所示

在这里插入图片描述

随机访问性能

根据 index 查找,时间复杂度 O(n)

插入或删除性能

  • 起始位置:O(1)
  • 结束位置:如果已知 tail 尾节点(双向链表)是 O(1),不知道 tail 尾节点(单向链表)是 O(n)
  • 中间位置:根据 index 查找时间 + O(1) = O(n)

3.2 单向链表

实现以下链表方法:

  • addFirst(int value):向链头添加
  • 遍历
  • addLast(int value):向链尾添加
  • findLast():找最后一个节点
  • get(int index):根据索引找对应结点的值
  • insert(int index ,int value):向索引index位置插入元素
  • findNode(int index):根据索引找到对应的结点
  • removeFirst():删除第一个元素
  • remove(int index):从index索引位置删除
// 单向链表
//链表由多个节点Node组成,即组合的关系
//所以可以考虑将Node写成内部类
public class SinglyLinkedList implements Iterable<Integer>{//看作整体链表

    // 初始时,只有头指针没有节点
    //所以头指针指向null
    private Node head = null;//头指针,

    // 节点类
    private static class Node{//jing'tai
        int value;//值
        Node next;//下一节点指针

        // 有参构造,目的是方便是赋初值
        public Node(int value, Node next) {
            this.value = value;
            this.next = next;
        }
    }

    // 向链头添加元素
    public void addFirst(int value){
        // 1.链表为空
        // head = new Node(value, null);
      
       // 2.链表非空(可以处理链表为空的情况)
       //this.head为null,新增节点指向null,并作为新的this.head
       //若this.head不为null,新增节点指向原来的this.head,并作为新的this.head
       this.head = new Node(value,this.head);
    }

    // 遍历链表
    // 遍历方式一
    public void loop1(Consumer<Integer> consumer){
        // 定义指针,默认指向头指针的位置
        Node p  = head;
        while (p !=null){
            // 打印指针p的值
            consumer.accept(p.value);
            // 指针向后移动
            p = p.next;
        }
    }

    // 遍历方式二
    public void loop2(Consumer<Integer> consumer){
        for (Node p = head; p != null; p = p.next){
            consumer.accept(p.value);
        }
    }

    // 遍历方式三,迭代器遍历
    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            Node p = head;
            @Override
            public boolean hasNext() {
                //hasNext():是否有下一个元素
                return p != null;
            }

            @Override
            public Integer next() {
                // next():返回当前节点值,并指向下一个元素
                int value = p.value;
                p = p.next;
                return value;
            }
        };
    }
  
  
    // 向链表尾部添加
    // 首先需要找到最后一个节点
    private Node findLast(){
        //空链表情况,即只有一个头指针指向null
        if (head == null){
            return null;
        }

        Node p ;
        for (p = head; p.next != null; p  = p.next ){

        }
        return p;
    }
  
		// 在尾部添加
    public void addLast(int value){
        // 找打最后一个结点
        Node last = findLast();

        // 空链表情况,即没有结点,只有一个头指针指向null
        //此时直接添加,相当于在头部添加
        if (last == null){
            addFirst(value);
            return;
        }
        // 将最后结点的next指针指向添加的元素
        //新添加的元素next指针指向null
         last.next= new Node(value, null);
    }
  
  
    // 根据索引找到对应的结点
    private Node findNode(int index){
        int i = 0;
        for (Node p = head ; p != null ; p = p.next,i++){
            if(i == index){
                //找到返回对应的结点
                return p;
            }
        }
        // 循环结束没有索引index对应的结点返回null
        return null;
    }

    // 根据索引找对应结点的值
    public int get(int index){
        Node node = findNode(index);
        if (node == null){
            throw new IllegalArgumentException(
              String.format("index[%d] 不合法",index));
        }
        return node.value;
    }
  
  
  
    // 向索引index位置插入元素
    public void insert(int index,int value){
        if (index == 0){
            addFirst(value);
            // 此处return作用是让下面代码不再执行
            return;
        }
        // 找到插入位置的前一个结点
        Node prev = findNode(index - 1);
        if (prev == null){
            throw new IllegalArgumentException(
              String.format("index[%d] 不合法",index));
        }
        prev.next = new Node(value, prev.next);
    }
  
  
    // 删除第一个元素
    public void removeFirst(){
        // 空链表情况
        if (head == null){
            throw new IllegalArgumentException(
              String.format("index[%d] 不合法",0));
        }
        // head:指向第一个结点,即 head为第一个结点
        // head.next:表示第二个结点
        head = head.next;
    }
  
  
    // 根据index索引位置删除
    public void remove(int index){
        if (index == 0){
            removeFirst();
            return;
        }
        // index的上一个节点
        Node prev = findNode(index-1);
        if (prev == null){
            throw new IllegalArgumentException(
              String.format("index[%d] 不合法",index));
        }

        // 被删除的节点
        Node removed = prev.next;
        if (removed == null){
            throw new IllegalArgumentException(
              String.format("index[%d] 不合法",index));
        }
        prev.next = removed.next;
    }

  
  
  
  
  

  
}
========================================================
  public class Test {
    public static void main(String[] args) {

        SinglyLinkedList list = new SinglyLinkedList();
        // 向头部添加元素
        list.addFirst(1);
        list.addFirst(2);
        list.addFirst(3);
        
        // 方式一遍历
        list.loop1(value->{
            System.out.println(value);
        });// 3 2 1

        // 方式二遍历
        list.loop2(value->{
            System.out.println(value);
        });// 3 2 1

        // 方式三遍历
        for (Integer value : list) {
            System.out.println(value);
        }

        Iterator<Integer> it = list.iterator();
        while (it.hasNext()){
            Integer next = it.next();
            System.out.println(next);
        }
      
       // 向尾部添加
        SinglyLinkedList list2 = new SinglyLinkedList();
        list2.addLast(1);
        list2.addLast(2);
        list2.addLast(3);
        // 遍历
        list2.loop2(Value->{
            System.out.println(Value);
        });// 1 2 3
      
      
         // 根据索引找值
        int i = list2.get(0);
        System.out.println(i);//1
      
        // 向索引index位置插入元素
        list2.insert(2,6);
        list2.loop2(Value->{
            System.out.println(Value);// 1 2 6 3
        });
      
       System.out.println("删除第一个元素");
        // 删除第一个元素
        list2.removeFirst();
        list2.loop2(Value->{
            System.out.println(Value);//2 6 3
        });
      
      
        System.out.println("删除index索引位置元素");
        //删除index索引位置元素
        list2.remove(0);
        list2.loop2(Value->{
            System.out.println(Value);//6 3
        });
      
      

    }
}
  • Node 定义为内部类,是为了对外隐藏实现细节,没必要让类的使用者关心 Node 结构
  • 定义为 static 内部类,是因为 Node 不需要与 SinglyLinkedList 实例相关多个SinglyLinkedList实例能共用 Node 类定义
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蔚一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值