链表

定义单链表节点

力扣上单链表节点定义是:

package com.wang.base.linkedList;

public class Demo01 {
    class ListNode{
        int val;
        ListNode next;
        ListNode(int x){
            val=x;
        }
    }
}

但在实际的编程语言中,使用的节点会稍微复杂一些:

package com.wang.base.linkedList;

public class Demo01 {
    class Node<E>{
        E val;
        Node<E> next;
        Node<E> prev;
        Node(Node<E> prev,E element,Node<E> next){
            this.val=element;
            this.next=next;
            this.prev=prev;
        }
    }
}

主要区别:

  1. 编程语言标准库一般会提供泛型,即可以指定val字段为任何类型,而力扣的单链表节点的val字段只有int型

  2. 编程语言标准库一般使用双链表而不是单链表:单链表只有next一个指针,指向下一个节点,而双链表节点有两个指针,prev指向前一个节点,next指向下一个节点

为什么需要链表

一条链表不需要一整块连续的内存空间,链表的元素可以分散在内存空间的不同地方,通过节点上next和prev指针将零散的内存块串联起来形成一个链式结构。理论上链表是没有容量限制的。

但是链表不能通过索引快速访问元素,只能从头节点开始顺着next指针往后找

单链表的基本操作

创建一条单链表

package com.wang.base.linkedList;

public class Demo02 {
    //定义单链表
    class ListNode {
        int val;
        ListNode next;

        ListNode(int x) {
            val = x;
        }
        //输入一个数组,转换成一条单链条
        ListNode createLinkedList(int[]arr){
            //如果数组为空,报错
            if (arr==null||arr.length==0){
                return null;
            }
            ListNode head=new ListNode(arr[0]);
            ListNode cur=head;
            for (int i = 0; i < arr.length; i++) {
                cur.next=new ListNode(arr[i]);
                cur=cur.next;
            }
            return head;
        }
    }
}

查/改

package com.wang.base.linkedList;

public class Demo02 {
    //定义单链表
    class ListNode {
        int val;
        ListNode next;

        ListNode(int x) {
            val = x;
        }
        //输入一个数组,转换成一条单链条
        ListNode createLinkedList(int[]arr){
            //如果数组为空,报错
            if (arr==null||arr.length==0){
                return null;
            }
            //创建一条单链表
            ListNode head=createLinkedList(new int[]{1,2,3,4,5});
            //遍历单链表
            for(ListNode p=head;p!=null;p=p.next){
                System.out.println(p.val);
        }
        return head;
        }
    }
}

增加

在头部插入新元素

package com.wang.base.linkedList;

public class Demo02 {
    //定义单链表
    class ListNode {
        int val;
        ListNode next;

        ListNode(int x) {
            val = x;
        }
        //输入一个数组,转换成一条单链条
        ListNode createLinkedList(int[]arr){
            //如果数组为空,报错
            if (arr==null||arr.length==0){
                return null;
            }
            //创建一条单链表
            ListNode head=createLinkedList(new int[]{1,2,3,4,5});
            //在单链表头部插入一个新节点0
            ListNode newHead=new ListNode(0);
            newHead.next=head;
            head=newHead;
        return head;
        }
    }
}

在尾部插入新元素

package com.wang.base.linkedList;

public class Demo02 {
    //定义单链表
    class ListNode {
        int val;
        ListNode next;

        ListNode(int x) {
            val = x;
        }
        //输入一个数组,转换成一条单链条
        ListNode createLinkedList(int[]arr){
            //如果数组为空,报错
            if (arr==null||arr.length==0){
                return null;
            }
            //创建一条单链表
            ListNode head=createLinkedList(new int[]{1,2,3,4,5});
            //在单链表尾部插入一个新节点6
            ListNode p=head;
            //先走到链表的最后一个节点
            while (p.next!=null){
                p=p.next;
            }
            //现在p就是链表的最后一个节点
            //在p后面插入新节点6
            p.next=new ListNode(6);
        return head;
        }
    }
}

在中间插入新元素

package com.wang.base.linkedList;

public class Demo02 {
        //定义单链表
        class ListNode {
            int val;
            ListNode next;

            ListNode(int x) {
                val = x;
            }
            //输入一个数组,转换成一条单链条
            ListNode createLinkedList(int[] arr) {
                //如果数组为空,报错
                if (arr == null || arr.length == 0) {
                    return null;
                }
                //创建一条单链表
                ListNode head = createLinkedList(new int[]{1, 2, 3, 4, 5});
                //想在第三个节点后面插入新节点66
                //找到第三个节点
               ListNode p=head;
                for (int i = 0; i < 2; i++) {
                    p=p.next;
                }
                //此时p指向第三个节点
                //组装新节点后的后驱指针
                ListNode newNode=new ListNode(66);
                newNode.next=p.next;
                //插入新节点
                p.next=newNode;
                return head;
            }
        }
    }

删除

在头部删除元素

package com.wang.base.linkedList;

public class Demo02 {
        //定义单链表
        class ListNode {
            int val;
            ListNode next;

            ListNode(int x) {
                val = x;
            }

            //输入一个数组,转换成一条单链条
            ListNode createLinkedList(int[] arr) {
                //如果数组为空,报错
                if (arr == null || arr.length == 0) {
                    return null;
                }
                //创建一条单链表
                ListNode head = createLinkedList(new int[]{1, 2, 3, 4, 5});
                //删除头节点
                head=head.next;
                return head;
            }
        }
    }

在尾部删除元素

package com.wang.base.linkedList;

public class Demo02 {
        //定义单链表
        class ListNode {
            int val;
            ListNode next;

            ListNode(int x) {
                val = x;
            }

            //输入一个数组,转换成一条单链条
            ListNode createLinkedList(int[] arr) {
                //如果数组为空,报错
                if (arr == null || arr.length == 0) {
                    return null;
                }
                //创建一条单链表
                ListNode head = createLinkedList(new int[]{1, 2, 3, 4, 5});
                //删除尾节点
               ListNode p=head;
               //找到倒数第二个节点
               while (p.next.next!=null){
                   p=p.next;
               }
               //此时p指向倒数第二个节点
                //把尾节点从链表中摘除
               p.next=null;//把节点变为null就是删除
                return head;
            }
        }
    }

在中间删除元素

package com.wang.base.linkedList;

public class Demo02 {
        //定义单链表
        class ListNode {
            int val;
            ListNode next;

            ListNode(int x) {
                val = x;
            }

            //输入一个数组,转换成一条单链条
            ListNode createLinkedList(int[] arr) {
                //如果数组为空,报错
                if (arr == null || arr.length == 0) {
                    return null;
                }
                //创建一条单链表
                ListNode head = createLinkedList(new int[]{1, 2, 3, 4, 5});
                //删除第四个节点,要操作前驱节点
               ListNode p=head;
                for (int i = 0; i < 2; i++) {
                    p=p.next;
                }
                //此时p指向第三个节点
                p.next=p.next.next;//第四个节点等于第五个节点,认为是删掉第四个节点
                return head;
            }
        }
    }

双链表的基本操作

双链表是有两条链子,所以断掉或者连接时要有两步

创建一条双链表

package com.wang.base.linkedList;

public class Demo03 {
    class DoublyListNode{
        int val;
        DoublyListNode next,prev;
        DoublyListNode(int x){val =x;}
    }
    DoublyListNode createDoublyLinkedList(int[]arr){
        if (arr==null||arr.length==0){
            return null;
        }
        DoublyListNode head=new DoublyListNode(arr[0]);
        DoublyListNode cur=head;
        //for循环迭代创建双链表
        for (int i = 1; i < arr.length; i++) {
            DoublyListNode newNode=new DoublyListNode(arr[i]);
            cur.next=newNode;
            newNode.prev=cur;
            cur=cur.next;
            
        }
        return head;
    }
}

查/改

package com.wang.base.linkedList;

public class Demo03 {
    class DoublyListNode{
        int val;
        DoublyListNode next,prev;
        DoublyListNode(int x){val =x;}
    }
    DoublyListNode createDoublyLinkedList(int[]arr){
        if (arr==null||arr.length==0){
            return null;
        }
        //创建一条双链表
        DoublyListNode head=createDoublyLinkedList(new int[]{1,2,3,4,5});
        DoublyListNode tail=null;
        //从头节点向后遍历双链表
        for (DoublyListNode p=head;p!=null;p=p.next){
            System.out.println(p.val);
            tail=p;
        }
        //从尾节点向前遍历双链表
        for (DoublyListNode p=tail;p!=null;p=p.prev){
            System.out.println(p.val);
        }
        return head;
    }
}

在实际应用中,可以根据索引是靠近头部还是尾部来选择合适的方向遍历,可以一定程度上提高效率

增加

在头部插入新元素

package com.wang.base.linkedList;

public class Demo03 {
    class DoublyListNode{
        int val;
        DoublyListNode next,prev;
        DoublyListNode(int x){val =x;}
    }
    DoublyListNode createDoublyLinkedList(int[]arr){
        if (arr==null||arr.length==0){
            return null;
        }
        //创建一条双链表
        DoublyListNode head=createDoublyLinkedList(new int[]{1,2,3,4,5});
        //想在头部插入0
        DoublyListNode newHead=new DoublyListNode(0);
        newHead.next=head;//这两个式子形成双链表
        head.prev=newHead;//这两个式子形成双链表
        head=newHead;//之前head=1,相等后head=0
        return head;
    }
}

在尾部插入新元素

package com.wang.base.linkedList;

public class Demo03 {
    class DoublyListNode{
        int val;
        DoublyListNode next,prev;
        DoublyListNode(int x){val =x;}
    }
    DoublyListNode createDoublyLinkedList(int[]arr){
        if (arr==null||arr.length==0){
            return null;
        }
        //创建一条双链表
        DoublyListNode head=createDoublyLinkedList(new int[]{1,2,3,4,5});
        DoublyListNode tail=head;//tail=1
        //先走到链表的最后一个节点
       while (tail.next!=null){
           tail=tail.next;
       }//tail=5
       //在尾部插入6
       DoublyListNode newNode=new DoublyListNode(6);
       tail.next=newNode;
       newNode.prev=tail;
       //更新尾节点引用
       tail=newNode;
        return head;
    }
}

在中间插入新元素

package com.wang.base.linkedList;

public class Demo03 {
    class DoublyListNode{
        int val;
        DoublyListNode next,prev;
        DoublyListNode(int x){val =x;}
    }
    DoublyListNode createDoublyLinkedList(int[]arr){
        if (arr==null||arr.length==0){
            return null;
        }
        //创建一条双链表
        DoublyListNode head=createDoublyLinkedList(new int[]{1,2,3,4,5});
        //想在第三个节点后插入新节点66
        DoublyListNode p=head;
        for (int i = 0; i < 2; i++) {
            p=p.next;//p=3
        }
        //组装新节点
        DoublyListNode newNode=new DoublyListNode(66);
        newNode.next=p.next;//66的后面是4
        newNode.prev=p;//66的前面是3
        //插入新节点
        p.next.prev=newNode;//3的后面是4,4的前面变成66
        p.next=newNode;//最终结果是3的后面是4
        return head;
    }
}

删除

在头部删除元素

package com.wang.base.linkedList;

public class Demo03 {
    class DoublyListNode{
        int val;
        DoublyListNode next,prev;
        DoublyListNode(int x){val =x;}
    }
    DoublyListNode createDoublyLinkedList(int[]arr){
        if (arr==null||arr.length==0){
            return null;
        }
        //创建一条双链表
        DoublyListNode head=createDoublyLinkedList(new int[]{1,2,3,4,5});
        //删除头部节点
        DoublyListNode toDelete=head;
        head=head.next;//head原本是1,现在是2
        head.prev=null;//2的前面变成null
        //清理已经删除节点的指针
        toDelete.next=null;
        return head;
    }
}

在尾部删除元素

package com.wang.base.linkedList;

public class Demo03 {
    class DoublyListNode{
        int val;
        DoublyListNode next,prev;
        DoublyListNode(int x){val =x;}
    }
    DoublyListNode createDoublyLinkedList(int[]arr){
        if (arr==null||arr.length==0){
            return null;
        }
        //创建一条双链表
        DoublyListNode head=createDoublyLinkedList(new int[]{1,2,3,4,5});
        //删除尾部节点
        DoublyListNode p=head;
        //找到尾部节点
        while (p.next!=null){
            p=p.next;
        }//现在p指向尾部节点,p=5
        
        //把尾部节点从链表中摘除
        p.prev.next=null;//5的前面是4,4的后面变成null
        //把被删的节点的指针都断掉
        p.prev=null;//经过上步,尾部节点已经去掉了一条,再说清楚它前面是null,可以把另外一条也去掉
        return head;
    }
}

在中间删除元素

package com.wang.base.linkedList;

public class Demo03 {
    class DoublyListNode{
        int val;
        DoublyListNode next,prev;
        DoublyListNode(int x){val =x;}
    }
    DoublyListNode createDoublyLinkedList(int[]arr){
        if (arr==null||arr.length==0){
            return null;
        }
        //创建一条双链表
        DoublyListNode head=createDoublyLinkedList(new int[]{1,2,3,4,5});
        //想要删除第四个节点
        //先找到第三个节点
        DoublyListNode p=head;
        for (int i = 0; i < 2; i++) {
            p=p.next;//p=3
        }
        DoublyListNode toDelete=p.next;//to=4
        //把to从链表中摘出去
        p.next=toDelete.next;//第四节点=5
        toDelete.next.prev=p;//4后面是5,5的前面变成3
        //把to前后指针都设置为null是个好习惯(可选)
        toDelete.next=null;
        toDelete.prev=null;
        return head;
    }
}
posted on 2025-01-22 17:33  红星star  阅读(25)  评论(0)    收藏  举报