数据结构与算法-单向链表

单向链表是一种线性表数据结构,其中每个节点包含两个部分:数据域和指向下一个节点的指针。
单向链表的节点类型包括:
1、数据域:存储节点的数据,通常包括节点的值和指向下一个节点的指针。
2、指针域:存储指向下一个节点的指针,通常包括当前节点的地址和指向下一个节点的指针。
单向链表的基本操作包括:
1、插入节点:在链表的头部插入一个新节点,该节点的数据域设置为新节点的数据,指针域指向新节点的下一个节点。
2、删除节点:从链表的头部删除一个节点,该节点的数据域设置为删除节点的数据,指针域指向删除节点的前一个节点。
3、获取节点:获取链表中指定位置的节点,该节点的数据域设置为指定位置的节点的数据,指针域指向该节点的下一个节点。
4、遍历链表:按照指定的顺序访问链表中的所有节点,从头部开始逐个访问,直到到达尾部。
5、查找节点:在链表中查找指定值的节点,返回该节点的数据域或指针域,如果不存在则返回NULL。
倒序遍历链表:按照倒序访问链表中的所有节点,从尾部开始逐个访问,直到到达头部。
6、反转链表:将链表中的节点顺序翻转,可以通过修改指针域来实现,也可以直接修改数据域来实现。
单向链表相比于数组链表具有更好的灵活性和可扩展性,因为它可以动态地分配和释放内存,并且可以实现快速的插入和删除操作。然而,单向链表也有一些缺点,例如需要额外的空间来存储指针域,导致插入和删除操作的时间复杂度较高。

上代码:

package com.demo._03单向链表;

import java.util.Iterator;
import java.util.function.Consumer;

/**
 * @create 2023/5/4 16:20
 * @Desc 单向链表(带哨兵)
 * 遍历逻辑,head 改成 head.next
 **/
public class SinglyLinkedListSentinel implements Iterable<Integer>{
    // 头指针
    private Node head = new Node(000, null);

    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            Node p = head.next ;
            // 是否存在下一个元素
            @Override
            public boolean hasNext() {
                return p != null;
            }

            // 返回当前元素的值,并且指向下一个元素
            @Override
            public Integer next() {
                int v = p.value;
                p = p.next ;
                return v;
            }
        };
    }

    /**
     * 节点类
     */
    private static class Node{
        // 值
        int value ;
        // 下一个节点指针
        Node next ;

        public Node(int value, Node next) {
            this.value = value;
            this.next = next;
        }
    }

    /**
     * 向链表头部添加
     * @param value
     */
    public void addFirst(int value) {
        insert(0, value);
    }

    /**
     * 遍历链表1
     * @param consumer
     */
    public void loop(Consumer<Integer> consumer) {
        Node p = head ;
        while (p != null){
            // 处理完当前节点,获取当前节点的下一个节点
            consumer.accept(p.value);
            p = p.next ;
        }
    }

    /**
     * 遍历链表2
     * @param consumer
     */
    public void loop2(Consumer<Integer> consumer) {
        for (Node p = head ; p != null; p = p.next ){
            // 处理完当前节点,获取当前节点的下一个节点
            consumer.accept(p.value);
        }
    }

    /**
     * 查找最后一个节点
     * @return
     */
    private Node findLast() {
        Node p ;
        for (p = head ; p.next != null; p = p.next ){
        }
        return p ;
    }

    /**
     * 添加尾元素
     * @param value
     */
    public void addLast(int value) {
        Node last = findLast();
        // 加入哨兵,不存在为空的情况
//        if(last == null) {
//            addFirst(value);
//            return;
//        }
        last.next = new Node(value, null) ;
    }

    private Node findNode(int index) {
        int i = -1;
        for (Node p = head; p != null ; p = p.next, i++) {
            if(i == index) {
                return p ;
            }
        }
        return null ;
    }

    /**
     * 根据索引获取元素
     * @param index
     * @return
     */
    public int get(int index) {
        Node node = findNode(index);
        if(node == null) {
            throw illegalArgumentException(index);
        }
        return node.value ;
    }

    /**
     * 向索引位置插入
     * @param index 索引位置
     * @param value 插入值
     */
    public void insert(int index, int value) {
        // 添加哨兵了,去掉
//        if(index == 0) {
//            addFirst(value);
//            return;
//        }
        // 找到上一个节点
        Node prev = findNode(index - 1);
        if(prev == null) {
            throw illegalArgumentException(index);
        }
        prev.next = new Node(value, prev.next);
    }

    /**
     * 异常
     * @param index
     * @return
     */
    private IllegalArgumentException illegalArgumentException(int index) {
        return new IllegalArgumentException(String.format("index [%d] 不合法%n", index));
    }

    /**
     * 删除第一个节点
     */
    public void removeFirst() {
        remove(0);
    }

    /**
     * 删除指定索引元素
     * @param index 索引
     */
    public void remove(int index){
        // 添加哨兵,去掉判断逻辑
        /*if(index == 0) {
            removeFirst();
            return;
        }*/
        // 上一个节点
        Node prev = findNode(index - 1) ;
        if(prev == null) throw illegalArgumentException(index) ;
        // 被删除的节点
        Node removed = prev.next ;
        if(removed == null) throw illegalArgumentException(index) ;
        prev.next = removed.next ;
    }

    public static void main(String[] args) {
        SinglyLinkedListSentinel list = new SinglyLinkedListSentinel();
        list.addLast(1);
        list.addLast(2);
        list.addLast(3);
        list.addLast(4);

        list.insert(4, 5);

//        list.loop(value -> System.out.println(value));
//        System.out.println("----------------------");
//        list.loop2(value -> System.out.println(value));
//        System.out.println("----------------------");
        list.addFirst(5);
        list.addFirst(6);
        list.addFirst(7);
        list.addFirst(8);

        // System.out.println(list.get(0));

        // list.removeFirst();
        // list.remove(3);
        for (Integer integer : list) {
            System.out.println(integer);
        }

    }

}



你可能感兴趣的:(链表,数据结构,java)