LinkedList与单向链表(二)(双向链表)

1.ListedList的模拟实现

package Demo1;

/**
 * Describe:双向链表的简单模拟实现
 * User:lenovo
 * Date:2023-01-08
 * Time:11:20
 */
class Node {
    int val;
    Node prev;
    Node next;

    public Node(int val) {
        this.val = val;
    }

    public Node() {
    }
}
public class MyLinkedList {
    Node first;
    Node last;
    int size = 0;

    public MyLinkedList() {
    }

    //头插法
    public void addFirst(int data){
        Node cur = new Node(data);
        //链表为空
        if(first == null) {
            first = cur;
            last = cur;
            size++;
            return;
        }
        //链表不为空
        cur.next = first;
        first.prev = cur;
        first = cur;
        size++;
    }
    //尾插法
    public void addLast(int data){
        Node cur = new Node(data);
        //链表为空
        if(first == null) {
            first = cur;
            last = cur;
            size++;
            return;
        }
        //链表不为空
        last.next = cur;
        cur.prev = last;
        last = last.next;
        size++;
    }

    //任意位置插入,第一个数据节点为0号下标
    public void addIndex(int index,int data){
        if(index < 0 || index > size) {
            return;//这里我们可以直接返回,或者报错
        }
        Node cur = new Node(data);
        Node s1 = first;
        Node s2 = first;
        //头节点的插入
        if(index == 0) {
            addFirst(data);
            return;
        }
        //尾节点的插入
        if(index == size){
            addLast(data);
            return;
        }
        //找这个下表的节点
        //如果它小,我们从头找这个元素
        int count = 0;
        if(index < size / 2) {
            while(count != index) {
                s2 = s2.next;
                count++;
            }
        }else {
            s2 = last;
            while(size - 1 - index != count) {
                s2 = s2.prev;
                count++;
            }
        }

        s1 = s2.prev;
        //开始插入
        s1.next = cur;
        cur.next = s2;
        s2.prev = cur;
        cur.prev = s1;
        size++;
    }

    //查找是否包含关键字key是否在单链表当中
    public boolean contains(int key){
        Node cur = first;
        if(first == null ) {
            return false;
        }
        while(cur != null && cur.val != key) {
            cur = cur.next;
        }
        if(cur == null) {
            return false;
        }else {
            return true;
        }
    }

    //删除第一次出现关键字为key的节点
    public void remove(int key){
        Node cur = first;
        if(first == null ) {
            return;
        }
        while(cur != null) {
            if(cur.val == key) {
                //头节点的判断
                if(cur == first) {
                    //如果只有一个节点
                    if(cur.next == null) {
                        first = null;
                        last = null;
                        size--;
                        break;
                    }
                    Node s1 = cur.next;
                    s1.prev = null;
                    first = s1;
                    size--;
                    break;
                }else if(cur == last) {//尾节点的判断
                    Node s1 = cur.prev;
                    s1.next = null;
                    last = s1;
                    size--;
                    break;
                }else {//其他节点的判断
                    Node s1 = cur.prev;
                    Node s2 = cur.next;
                    s1.next = s2;
                    s2.prev = s1;
                    size--;
                    break;
                }

            }
            cur = cur.next;
        }
    }
    //删除所有值为key的节点
    public void removeAllKey(int key){
        if(first == null ) {
            return;
        }

        Node cur = first;
        while(cur != null) {
            if(cur.val == key) {
                //头节点的判断
                if(cur == first) {
                    //如果只有一个节点
                    if(cur.next == null) {
                        first = null;
                        last = null;
                        size--;
                        break;
                    }
                    Node s1 = cur.next;
                    s1.prev = null;
                    first = s1;
                    size--;
                }else if(cur == last) {//尾节点的判断
                    Node s1 = cur.prev;
                    s1.next = null;
                    last = s1;
                    size--;
                }else {//其他节点的判断
                    Node s1 = cur.prev;
                    Node s2 = cur.next;
                    s1.next = s2;
                    s2.prev = s1;
                    size--;
                }
            }
            cur = cur.next;

        }
    }

    //得到单链表的长度
    public int size(){
        return size;
    }

    public void display(){
        //链表为空
        if(this.first ==null) {
            return;
        }
        Node cur = first;
        while(cur != null) {
            System.out.print(cur.val + " ");
            cur = cur.next;
        }
        System.out.println();
    }

    public void clear(){
        //最保险的方式是遍历数组每个节点的上下节点设为空
        Node cur = first;
        while(cur != null) {
            Node tmp = cur.next;
            cur.prev = null;
            cur.next = null;
            cur = tmp;
        }
        first = null;
        last = null;
    }

    //测试
    public static void main(String[] args) {
        MyLinkedList list = new MyLinkedList();
        System.out.println("==================头插法===============");
        list.addFirst(1);
        list.addFirst(2);
        list.addFirst(3);
        list.addFirst(4);
        list.display();
        System.out.println("================尾插法================");
        MyLinkedList list2 = new MyLinkedList();
        list2.addLast(1);
        list2.addLast(2);
        list2.addLast(3);
        list2.addLast(4);
        list2.display();
        System.out.println("===============插入任意位置=============");
        list2.addIndex(-1,0);//这条不会被加上去
        list2.addIndex(4,5);
        list2.addIndex(1,11);
        list2.display();
        System.out.println("===============查找关键字===============");
        System.out.println(list2.contains(1));
        System.out.println(list2.contains(0));
        System.out.println("===============删除第一个关键字===========");
        list2.remove(11);
        list2.remove(22);
        list2.display();
        System.out.println("===============删除所有的5==============");
        list2.addLast(5);
        list2.addLast(5);
        list2.addLast(5);
        list2.addLast(6);
        list2.removeAllKey(5);
        list2.display();
        System.out.println("==============获得长度================");
        System.out.println(list2.size());
        System.out.println("==============清空数组================");
        list2.clear();
        list2.display();


    }
}

(如有错误,请批评指针,评论区会不定时查看)

LinkedList与单向链表(二)(双向链表)_第1张图片

2.LinkedList的使用

2.1什么是LinkedList

LinkedList的底层是双向链表结构,双向链表的的储存并不需要连续的大块空间,并且链表是通过节点链接起来的,因此在任意位置插入或删除元素并没有很高的复杂度。

LinkedList与单向链表(二)(双向链表)_第2张图片
  • LinkedList实现了List接口;

  • LinkedList的底层是双向链表;

  • LinkedList没有实现RandomAccess及接口,因此不支持随机访问;

  • LinkedList的任意位置插入和删除元素时效率比较高;

  • LinkedList比较适合任意位置插入和删除的场景。

2.2LinkedList的使用

    • LinkedList的构造方法

两个构造方法:

无参构造:LinkedList()

使用其他容器中元素构造List:public LinkedList(Collection c)

/**
 * Describe:LinkedList构造方法的介绍
 * User:lenovo
 * Date:2023-01-09
 * Time:14:17
 */
public class Test {
    public static void main(String[] args) {
        List list1 = new LinkedList<>();

        List list2 = new ArrayList<>();
        list2.add("javeSE");
        list2.add("javaWeb");

        List list3 = new LinkedList<>(list2);
    }
}

2.LinkedList的其他常用方法的介绍

//常用方法的介绍
public class Test {
    public static void main(String[] args) {
        LinkedList list = new LinkedList<>();
        System.out.println("===========尾插法================");
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        list.add(6);
        System.out.println(list);
        System.out.println("=================在任意位置插入===============");
        list.add(0, 0);
        System.out.println(list);
        System.out.println("=================移除元素===============");
        list.remove();//移除第一个元素,内部调用的是removeFirst
        System.out.println(list);
        list.removeFirst();//移除第一个元素
        System.out.println(list);
        list.removeLast();//移除最后一个元素
        System.out.println(list);
        list.remove((Integer) 3);//移除第一个指定的元素
        System.out.println(list);
        System.out.println("================contains()检测是否包含某一元素=============");
        System.out.println(list.contains(2));
        System.out.println(list.contains(3));
        System.out.println("=================找都某一元素返回下标======================");
        System.out.println(list.indexOf(2));
        System.out.println(list.lastIndexOf(4));
        System.out.println("===================获得某一位置的元素=====================");
        System.out.println(list.get(0));
        System.out.println("===================修改某一位置的元素=====================");
        list.set(0, 1);
        System.out.println(list);
        System.out.println("================subList()创建一个新的LinkedList==========");
        List list1 = list.subList(1, 3);//前闭后开
        System.out.println(list1);
        list1.set(0, 0);
        System.out.println(list);//修改链表1,但是原链表也改变了,说明公用一个链表
        System.out.println("====================清空链表===========================");
        list.clear();
        System.out.println(list);
        System.out.println(list.size());
    }
}

3.LinkedList的遍历

//双向链表的遍历
public class Test {
    public static void main(String[] args) {
        LinkedList list = new LinkedList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        //foreach遍历
        for (int a : list) {
            System.out.print(a + " ");
        }
        System.out.println();
        //迭代器,正向遍历
        ListIterator it = list.listIterator();
        while (it.hasNext()) {
            System.out.print(it.next() + " ");
        }
        System.out.println();
        //使用迭代器,反向遍历
        ListIterator rit = list.listIterator(list.size());
        while(rit.hasPrevious()) {
            System.out.print(rit.previous() + " ");
        }
        System.out.println();
    }
}

4.ArrayList和LinkedList的区别

不同点

ArrayList

LinkedList

储存空间上

连续的大段空间

逻辑上连续,空间上不需要连续

随机访问

时间复杂度O(1)

时间复杂度O(N)

头插

需要移动后面元素,较为复杂

不需要移动后面元素,效率较高

插入

空间不够,需要扩容

没有容量的概念

应用场景

元素高效储存+频繁访问

任意位置插入+频繁增删

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