3.基础数据结构-链表

3 基础数据结构-链表

3.1 定义

        链表(Linked List)是一种线性数据结构,由一系列节点(Node)组成。每个节点包含两部分:元素值(Element Value)和指向下一个节点的指针(Pointer)。链表可以分为多种类型,如单向链表、双向链表、循环链表等。元素在存储上并不连续。

 3.1.1 分类

(1)单向链表:每个元素只知道下一个元素。

(2)双向链表:每个元素知道下一个元素和上一个元素。

(3)循环链表:通常的链表为节点tail指向null,但是循环链表的tail指向head。

 3.1.2 哨兵节点

链表内还有一种特殊的节点,成为哨兵(Sentinel)节点,也叫做哑元(Dummy)节点,他并不存储数据,用来减缓别介判断。

3.2 性能

随机访问:

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

插入或者删除:

        起始位置:O(1)。

        结束位置:如果已知tail为节点是O(1),否则为O(n)。

        中间位置:根据index查找时间+O(1)。

3.3 单向链表

3.3.1 普通单向链表实现

package org.alogorithm.linkedList;

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

public class SingLinkListMain {
    public static void main(String[] args) {
        SingLinkList singLinkList = new SingLinkList();
        singLinkList.addFirst(1);
        singLinkList.addFirst(2);
        singLinkList.addFirst(3);
        singLinkList.addFirst(4);
        singLinkList.addFirst(5);
        //使用Consumer+while实现
        singLinkList.consumerLoop1(value -> System.out.println(value + "while,"));
        System.out.println("----------------------------------------");

        singLinkList.addLast(99);//尾部添加一个元素
        singLinkList.addLast(100);//尾部添加一个元素
        //使用Consumer+for实现
        singLinkList.consumerLoop2(value -> System.out.println(value + "for"));
        System.out.println("----------------------------------------");

        int res = singLinkList.get(3);
        System.out.println("查询结果为" + res);
        singLinkList.insert(0, 111);
        singLinkList.insert(3, 111);
        //使用迭代器实现
        for (Integer integer : singLinkList) {
            System.out.println(integer + "iterable");
        }
        System.out.println("----------------------------------------");
         /*int reserr = singLinkList.get(100);
        System.out.println("查询结果为"+reserr);*/
        // singLinkList.removeFirst();//删除第一个节点
        singLinkList.reomve(0);
        singLinkList.reomve(3);
        singLinkList.reomve(99);
        //使用递归
        singLinkList.recursionLoop(e -> {
            System.out.println(e + "recursion");
        }, singLinkList.head);
        // System.out.println(singLinkList.findLast());

    }
}

//单向链表
class SingLinkList implements Iterable {
    // head指针
    Node head;

    //删除指定索引节点
    public void reomve(int index) {
        if (index < 0) {
            IndexOutOfBoundsException(head, "索引不能为负");
        } else if (index == 0) {
            removeFirst();
        }
        Node node = findNode(index);//当前个节点
        IndexOutOfBoundsException(node, "当前节点为空");
        Node beforNode = findNode(index - 1);//上一个节点
        beforNode.next = node.next;

    }
    //删除第一个节点
    public void removeFirst() {
        IndexOutOfBoundsException(head, "链表为空无");
        head = head.next;//将head设置为之前的head.next第二个节点
    }

    //向索引位置添加一个元素
    public void insert(int index, int value) {
        Node afterNode = findNode(index);//后一个节点
        //构建新的节点
        Node newNode = new Node(value, afterNode);
        if (index == 0) {
            //索引为0向头部添加
            addFirst(value);
        } else {
            Node beforNode = findNode(index - 1);
            //否则将befor的next属性设置为当前节点
            IndexOutOfBoundsException(beforNode, "索引位置异常");
            beforNode.next = newNode;
        }

    }

    //抛出异常
    private static void IndexOutOfBoundsException(Node beforNode, String msg) {
        if (beforNode == null) {
            throw new IndexOutOfBoundsException(msg);
        }
    }

    //获取节点的值
    public int get(int index) {
        Node node = findNode(index);
        IndexOutOfBoundsException(node, "索引位置异常");
        return node.value;
    }

    //获取索引的元素
    private Node findNode(int index) {
        Node point = head;
        int i = 0;
        while (point != null) {
            if (i == index) {
                return point;
            } else {
                point = point.next;
                i++;
            }
        }
        return null;
    }

    //向最后添加一个元素
    public void addLast(int value) {
        Node last = findLast();//找到最后一个节点
        if (last == null) {
            //没有最后一个就添加第一个
            addFirst(value);
        } else {
            //否则设置最有一个节点的next属性为新的Node
            last.next = new Node(value, null);
        }
    }

    //查找最后一个元素
    public Node findLast() {
        Node point = head;
        if (head == null) {
            return null;
        }
        while (true) {
            if (point.next != null) {
                point = point.next;
            } else {
                return point;
            }
        }
    }

    //头部添加一个元素
    public void addFirst(int value) {
        //链表为空
//        head =  new Node(value,null);
        //链表非空
        head = new Node(value, head);//链表为空时head就是null
    }

    public void recursionLoop(Consumer consumer, Node point) {
        if (point != null) {
            consumer.accept(point.value); // 先输出当前节点的值
            recursionLoop(consumer, point.next); // 再递归处理下一个节点
        }

    }

    //迭代器遍历
    @Override
    public Iterator iterator() {
        return new Iterator() {
            Node point = head;

            @Override
            public boolean hasNext() {
                return point != null;
            }

            @Override
            public Integer next() {
                int value = point.value;
                point = point.next;
                return value;
            }
        };
    }

    //循环遍历 for
    public void consumerLoop2(Consumer consumer) {
        for (Node point = head; point != null; point = point.next) {
            consumer.accept(point.value);
        }

    }

    //循环遍历 while
    public void consumerLoop1(Consumer consumer) {
        Node point = head;
        while (point != null) {
            consumer.accept(point.value);
            point = point.next;
        }
    }

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

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

这是一个普通单向链表的全部功能实现,但是实现起来比较麻烦。

补充:关于类需不需要带static:

        (1)Node内部类可以添加static关键字,这是因为Java允许在类中定义静态成员。将内部类声明为静态的,意味着它不再依赖于外部类的实例。

        (2)静态内部类不能访问外部类的非静态成员(包括字段和方法)。
        (3)由于不依赖外部类实例,创建静态内部类的对象不需要外部类对象。

3.3.2 单向链表-带哨兵

加入哨兵之后,就不存在head为空的情况,也不存在链表为空,某个节点上一个元素为空,插入头部时链表为空的情况,但是对应的循环遍历要从head.next开始,可以简化很多代码。

package org.alogorithm.linkedList;

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

public class SingLinkSentryListMain {
    public static void main(String[] args) {
        SingLinkSentryList singLinkSentryList = new SingLinkSentryList();
        singLinkSentryList.addLast(69);
        singLinkSentryList.addLast(70);
        //使用Consumer+while实现
        singLinkSentryList.consumerLoop1(value -> System.out.println(value + "while,"));
        System.out.println(singLinkSentryList.get(0));
        //System.out.println(singLinkSentryList.get(99));
        singLinkSentryList.insert(0,99);
//        singLinkSentryList.insert(99,99);
        System.out.println("----------------------------------------");
        //使用Consumer+for实现
        singLinkSentryList.consumerLoop2(value -> System.out.println(value + "for"));
        System.out.println("----------------------------------------");
        singLinkSentryList.reomve(1);
        singLinkSentryList.reomve(0);
//        singLinkSentryList.reomve(99);
        //使用迭代器实现
        for (Integer integer : singLinkSentryList) {
            System.out.println(integer + "iterable");
        }
        System.out.println("----------------------------------------");


        //使用递归
       /* singLinkSentryList.recursionLoop(e -> {
            System.out.println(e + "recursion");
        }, singLinkSentryList.head);*/

    }
}

//单向链表
class SingLinkSentryList implements Iterable {
    // head指针
    Node head=new Node(1,null);//头指针指向哨兵

    //删除指定索引节点
    public void reomve(int index) {
        if (index < 0) {
            IndexOutOfBoundsException(head, "索引不能为负");
        }
        Node node = findNode(index);//当前个节点
        IndexOutOfBoundsException(node, "当前节点为空");
        Node beforNode = findNode(index - 1);//上一个节点
        beforNode.next = node.next;

    }
    //删除第一个节点
    public void removeFirst() {
        IndexOutOfBoundsException(head, "链表为空无");
        reomve(0);
    }

    //向索引位置添加一个元素
    public void insert(int index, int value) {
        Node afterNode = findNode(index);//后一个节点
        //构建新的节点
        Node newNode = new Node(value, afterNode);
            Node beforNode = findNode(index - 1);
            //否则将befor的next属性设置为当前节点
            IndexOutOfBoundsException(beforNode, "索引位置异常");
            beforNode.next = newNode;

    }

    //抛出异常
    private static void IndexOutOfBoundsException(Node beforNode, String msg) {
        if (beforNode == null) {
            throw new IndexOutOfBoundsException(msg);
        }
    }

    //获取节点的值
    public int get(int index) {
        Node node = findNode(index);
        IndexOutOfBoundsException(node, "索引位置异常");
        return node.value;
    }

    //获取索引的元素
    private Node findNode(int index) {
        Node point = head;
        int i = -1;
        while (point != null) {
            if (i == index) {
                return point;
            } else {
                point = point.next;
                i++;
            }
        }
        return null;
    }

    //向最后添加一个元素
    public void addLast(int value) {
        Node last = findLast();//因为有哨兵,head不可能为空
        last.next = new Node(value, null);
    }

    //查找最后一个元素
    public Node findLast() {
        Node point = head;
        while (true) {
            if (point.next != null) {
                point = point.next;
            } else {
                return point;
            }
        }
    }

    //头部添加一个元素
    public void addFirst(int value) {
        insert(0,value);
    }


    public void recursionLoop(Consumer consumer, Node point) {
        if (point != null) {
            consumer.accept(point.value); // 先输出当前节点的值
            recursionLoop(consumer, point.next); // 再递归处理下一个节点
        }

    }

    //迭代器遍历
    @Override
    public Iterator iterator() {
        return new Iterator() {
            Node point = head.next;

            @Override
            public boolean hasNext() {
                return point != null;
            }

            @Override
            public Integer next() {
                int value = point.value;
                point = point.next;
                return value;
            }
        };
    }

    //循环遍历 for
    public void consumerLoop2(Consumer consumer) {
        for (Node point = head.next; point != null; point = point.next) {
            consumer.accept(point.value);
        }

    }

    //循环遍历 while
    public void consumerLoop1(Consumer consumer) {
        Node point = head.next;
        while (point != null) {
            consumer.accept(point.value);
            point = point.next;
        }
    }

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

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

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