Java-数构链表

1.链表

1.1链表的概念和结构

链表是一种物理存储结构上非连续 存储结构,数据元素的逻辑顺序 是通过链表中引用链接次序实现的。

这里大多讨论无头单向非循环链表。这种结构,结构简单,一般与其他数据结构结合,作为其他数据结构的子数据。

1.2链表的实现

java 复制代码
public class MysingleList {
    static class ListNode{
        public  int val;//节点的值域
        public ListNode next;//下一个节点为地址
        public ListNode(int val){
            this.val=val;
        }
    }
    public ListNode head;//当前链表的头节点
    public  void createList(){
        ListNode node1 = new ListNode(12);
        ListNode node2 = new ListNode(23);
        ListNode node3 = new ListNode(34);
        ListNode node4 = new ListNode(45);
        ListNode node5 = new ListNode(56);

        node1.next = node2;
        node2.next = node3;
        node3.next = node4;
        node4.next = node5;

        this.head = node1;
    }

}

1.3方法

这里仍然尝试自己创建方法了解一些基础的操作

java 复制代码
//头插法
        public void addFirst(int data){
        ListNode node=new ListNode(data);
        node.next=head;
        head=node;
        }
        //尾插法
        public void addLast(int data){
        ListNode node=new ListNode(data);
        ListNode cur=head;
        if (cur==null){
            head=node;
            return ;
        }
        while(cur.next!=null){
            cur=cur.next;
        }
        cur.next=node;
        }
        //任意位置插入,第一个数据节点为0号下标
        public void addIndex(int index,int data) {
        if (index<0||index>size()){
            System.out.println("位置不合法");
            return;
        }
        if (index==0){
            addFirst(data);
        }
        if (index==size()){
            addLast(data);
        }
            ListNode node = new ListNode(data);
            ListNode cur=findIndex(index);
            node.next=cur.next;
            cur.next=node;
        }
        private ListNode findIndex(int index){
        ListNode cur=head;
        int count=0;
        while (cur!=null){
         cur=cur.next;
         count++;
         if (count==index-1){
             break;
         }
        }
        return cur;
        }

        //查找是否包含关键字key是否在单链表当中
        public boolean contains(int key){
        ListNode cur=head;
        while (cur!=null){
            if(cur.val==key){
                return true;
            }
            cur=cur.next;
        }
            return false;
        }
        //删除第一次出现关键字为key的节点
        public void remove(int key){
        if (head==null){
            return;
        }
        if (head.val==key){
            head=head.next;
            return;
        }
        ListNode cur=findKey(key);
        if(cur==null){
            System.out.println("没有对应的数值");
            return ;
        }
        ListNode del=cur.next;
        cur.next=del.next;
        }
        private ListNode findKey(int key){
            ListNode cur=head;
            while (cur.next!=null){
              if (cur.next.val==key){
                  return cur;
            }
              cur=cur.next;
        }
            return null;
        }
    //删除所有值为key的节点
    public void removeAllKey(int key){
        if (head==null){
            return;
        }
        ListNode cur=head.next;
        ListNode pre=head;
        while(cur!=null){
            if(cur.val==key){
                pre.next=cur.next;
                cur=cur.next;
            }else {
                pre=cur;
                cur=cur.next;
            }
        }
        if (head.val==key){
            head=head.next;//需要放在最后不然找不到后面的数据了。
        }
    }
    //得到单链表的长度
    public int size(){
        int count=0;
        ListNode cur=head;
        while(cur!=null){
            count++;
            cur=cur.next;
        }
        return count;
    }
    public void clear() {
        this.head=null;
    }
    public void display() {
        ListNode cur=head;
        while(cur!=null){
            System.out.print(cur.val+" ");
            cur=cur.next;
        }
        System.out.println();
    }

另外在管理员中使用jps可以显示当前系统中所有正在运行的 Java 进程的 进程 ID(PID)主类名JAR 包名。jmap语言可以用于查看 Java 进程的内存使用情况、生成堆转储(heap dump)等。

这里再补充几道常见链表操作的题目:

876. 链表的中间结点

这一题可以使用快慢指针,快指针永远是慢支针步数的两倍。

java 复制代码
class Solution {
    public ListNode middleNode(ListNode head) {
        if(head==null){return null;}
        if(head.next==null){return head;}
        
        ListNode fast=head;
        ListNode slow=head;
        while(fast!=null&&fast.next!=null){
            fast=fast.next.next;
            slow=slow.next;
        }
        return slow;
    }
}

206. 反转链表

java 复制代码
class Solution {
    public ListNode reverseList(ListNode head) {
        if(head==null){
            return null;
        }
        if(head.next==null){
            return head;
        }
        ListNode cur=head.next;
        head.next=null;
        
       
        while(cur!=null){
           ListNode curNext=cur.next;//保存下一个节点
            cur.next=head;
            head=cur;
            cur=curNext;
        }
        return head;
    }
}

LCR 027. 回文链表

java 复制代码
class Solution {
    public boolean isPalindrome(ListNode head) {
        ListNode fast=head;
        ListNode slow=head;
        //找到中间节点
        while (fast!=null && fast.next!=null){
            fast=fast.next.next;
            slow=slow.next;
        }
        //翻转后半部分的链表
        ListNode cur=slow.next;
        while(cur!=null){
            ListNode curNext=cur.next;
            cur.next=slow;
            slow=cur;
            cur=curNext;
        }
        //判断回文
        while(head!=slow){
            if(head.val!=slow.val){
                return false;
            }
            if(head.next==slow){return true;}
            head=head.next;
            slow=slow.next;
        }
        return true;
    }
}

链表分割_牛客题霸_牛客网

java 复制代码
public ListNode partition(ListNode pHead, int x) {
        // write code here
        ListNode bs = null;
        ListNode be = null;
        ListNode as = null;
        ListNode ae = null;

        ListNode cur = pHead;
        //没有遍历完 整个链表
        while(cur != null) {
            if(cur.val < x) {
                //第一次插入
                if(bs == null) {
                    bs = be = cur;
                }else {
                    be.next = cur;
                    be = be.next;
                }
            }else {
                //第一次插入
                if(as == null) {
                    as = ae = cur;
                }else {
                    ae.next = cur;
                    ae = ae.next;
                }
            }
            cur = cur.next;
        }
        //第一个段 没有数据
        if(bs == null) {
            return as;
        }
        be.next = as;
        //防止 最大的数据 不是最后一个
        if(as!=null) {
            ae.next = null;
        }
        return bs;
    }

141. 环形链表 - 力扣(LeetCode)

java 复制代码
public class Solution {
    public boolean hasCycle(ListNode head) {
        if(head==null){
            return false;
        }
        ListNode fast=head;
        ListNode slow=head;
        while(fast!=null&&fast.next!=null){
            fast=fast.next.next;
            slow=slow.next;
            if(fast==slow){
                return true;
            }
        
        }
        return false;
    }
}

160. 相交链表 - 力扣(LeetCode)

一定是Y型

java 复制代码
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        int lenA=0;
        int lenB=0;
        ListNode pl=headA;
        ListNode ps=headB;

        while(pl!=null){
            lenA++;
            pl=pl.next;
        }
        while(ps!=null){
            lenA++;
            ps=ps.next;
        }
        pl=headA;
        ps=headB;

        int len=lenA-lenB;
        if(len<0){
            pl=headB;
            ps=headA;
            len=lenB-lenA;//让len能够一定是正数
        }
    }
    //让最长的链表先走差值步
    while(len>0){
        pl=pl.next;
        len--;
    }
    //找到相遇的点
    while(pl!=ps){
        pl=pl.next;
        ps=ps.next;
    }
    return pl; 
}

142. 环形链表 II - 力扣(LeetCode)

java 复制代码
public class Solution {
    public ListNode detectCycle(ListNode head) {
       if(head==null){
            return null;
        }
        ListNode fast=head;
        ListNode slow=head;
        while(fast!=null&&fast.next!=null){
            fast=fast.next.next;
            slow=slow.next;
            if(fast==slow){
                break;
            }
        
        }
        if(fast==null||fast.next==null){
            return null;
        }
        fast=head;
        while(fast!=slow){
            fast=fast.next;
            slow=slow.next;
        }
        return fast;
    }
}

2.LinkedList

2.1概念

LinkedList的底层是双向链表结构,由于链表没有将元素储存在连续空间中,元素存储在单独节点中,通过引用将节点链接,因此在进行插入和删除元素的操作的时候,不需要搬移元素,效率较高。

2.2方法

为帮助理解常用方法的底层逻辑,这里再自己对方法进行实现。

java 复制代码
public class MyLinkList {
    //双向链表
    static class ListNode{
        private int  val;
        private ListNode prev;
        private ListNode next;
        public ListNode(int val) {
            this.val=val;
        }
    }
    public ListNode head;
    public ListNode last;
    //得到单链表的长度
    public int size(){
        ListNode cur=head;
        int count=0;
        while(cur!=null){
            count++;
            cur=cur.next;
        }
        return count;
    }
    public void display(){
        ListNode cur=head;
        while(cur!=null){
            System.out.print(cur.val+" ");
            cur=cur.next;
        }
        System.out.println();
    }
    //查找是否包含关键字key是否在单链表当中
    public boolean contains(int key){
        ListNode cur=head;
        while(cur!=null){
            if (cur.val==key){
                return true;
            }
            cur=cur.next;
        }
        return false;
    }

    //头插法
    public void addFirst(int data){
        ListNode node=new ListNode(data);
        if (head==null){
            head=node;
            last=node;
        }else{
            node.next=head;
            head.prev=node;
            head=node;
        }

    }
    //尾插法
    public void addLast(int data){
        ListNode node=new ListNode(data);
        if (head==null){
            head=node;
            last=node;
        }else {
            last.next=node;
            node.prev=last;
            last=last.next;
        }
    }
    //任意位置插入,第一个数据节点为0号下标
    public void addIndex(int index,int data){
        checkIndex(index);
        if (index==0){
            addFirst(data);
        }
        if (index==size()){
            addLast(data);
        }
        ListNode cur=findIndex(index);
        ListNode node=new ListNode(data);
        node.next=cur.next;
        cur.prev.next=node;
        node.prev=cur.prev;
        cur.prev=node;

    }
    private void checkIndex(int index){
        if (index<0||index>size()){
            throw new IndexOutOfException("index位置不合法");
        }
    }
    private ListNode findIndex(int index){
        ListNode cur=head;
        while(index !=0){
            cur=cur.next;
            index--;
        }
        return cur;
    }

    //删除第一次出现关键字为key的节点
    public void remove(int key){
        ListNode cur=head;
        while (cur!=null){
            if (cur.val==key){
                if (cur==head){//如果头节点正好是目标节点
                    head=head.next;//如果只有这一个节点则为空
                    if (head!=null){
                        head.prev=null;
                    }else {
                        last=null;
                    }
                }else {
                    //中间节点
                    if (cur.next!=null){
                        cur.prev.next=cur.next;
                        cur.next.prev=cur.prev;
                    }else {
                        //如果正好是last为目标节点
                        cur.prev.next=cur.next;
                        last=last.prev;
                    }
                }
             return ;
            }else {
                cur=cur.next;
            }
        }
    }
    //删除所有值为key的节点
    public void removeAllKey(int key){
        ListNode cur=head;
        while (cur!=null){
            if (cur.val==key){
                if (cur==head){//如果头节点正好是目标节点
                    head=head.next;//如果只有这一个节点则为空
                    if (head!=null){
                        head.prev=null;
                    }else {
                        last=null;
                    }
                }else {
                    //中间节点
                    if (cur.next!=null){
                        cur.prev.next=cur.next;
                        cur.next.prev=cur.prev;
                    }else {
                        //如果正好是last为目标节点
                        cur.prev.next=cur.next;
                        last=last.prev;
                    }
                }
                cur=cur.next;
            }
        }
    }
    public void clear(){
        ListNode cur=head;
        while(cur!=head){
            ListNode curNext=cur.next;//保存一下
            cur.prev=null;
            cur.next=null;
            cur=curNext;
        }
        head=null;
        last=null;
    }
}

2.3LinkedList的使用

LinkedList实现了List接口。

1.LinkedList的构造

LinkedList() --无参构造
public LinkedList(Collection<? extends E> c) -- 使用其他集合容器中元素构造 List

java 复制代码
    public static void main(String[] args) {
        List<Integer>list1=new LinkedList<>();
        list1.add(1);
        list1.add(2);
        list1.add(3);
    }

2.4遍历

java 复制代码
 public static void main(String[] args) {
        List<Integer>list1=new LinkedList<>();
        list1.add(1);
        list1.add(2);
        list1.add(3);

        for (int x: list1) {
            System.out.print(x+" ");
        }
        System.out.println();
        ListIterator<Integer>it=list1.listIterator();
        while (it.hasNext()){
            System.out.print(it.next()+" ");
        }
        System.out.println();
        ListIterator<Integer>it2=list1.listIterator(list1.size());
        while (it.hasPrevious()){
            System.out.print(it.previous()+" ");
        }
        System.out.println();
    }

2.5ArrayList和LinkedList的区别

又可以说是链表和顺序表的区别

|---------|-----------------|------------------------|
| 不同点 | ArrayList | LinkedList |
| 存储空间上 | 物理地址上连续 | 逻辑上连续,但物理地址不一定连续 |
| 随机访问 | 支持O(1) | 不支持:O(N) |
| 头插法 | 需要搬移元素,效率低 O(N) | 只需要修改引用的指向,时间复杂度为 O(1) |
| 插入法 | 空间不够,需要进行扩容 | 没有容量 |
| 应用场景 | 元素高效存储,频繁访问 | 任意位置插入和删除频繁 |

相关推荐
二进制person4 分钟前
数据结构--准备知识
java·开发语言·数据结构
半梦半醒*8 分钟前
H3CNE综合实验之机器人
java·开发语言·网络
xiaofann_39 分钟前
【数据结构】双向链表
数据结构·链表
消失的旧时光-194339 分钟前
Android模块化架构:基于依赖注入和服务定位器的解耦方案
android·java·架构·kotlin
仟濹1 小时前
【数据结构】栈与链表的区别
数据结构·链表
@ chen1 小时前
Spring Boot 解决跨域问题
java·spring boot·后端
洛_尘2 小时前
Java EE进阶2:前端 HTML+CSS+JavaScript
java·前端·java-ee
laoliu19962 小时前
GGE Lua 详细教程
开发语言·junit·lua
勇闯逆流河2 小时前
【C++】list及其模拟实现
开发语言·c++
转转技术团队2 小时前
转转上门隐私号系统的演进
java·后端