前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >《Java初阶数据结构》----3.<线性表---LinkedList与链表>

《Java初阶数据结构》----3.<线性表---LinkedList与链表>

作者头像
用户11288958
发布2024-09-24 15:03:48
680
发布2024-09-24 15:03:48
举报
文章被收录于专栏:学习

前言

大家好,我目前在学习java。之前也学了一段时间,但是没有发布博客。时间过的真的很快。我会利用好这个暑假,来复习之前学过的内容,并整理好之前写过的博客进行发布。如果博客中有错误或者没有读懂的地方。热烈欢迎大家在评论区进行讨论!!! 喜欢我文章的兄弟姐妹们可以点赞,收藏和评论我的文章。喜欢我的兄弟姐妹们以及也想复习一遍java知识的兄弟姐妹们可以关注我呦,我会持续更新滴, 望支持!!!!!!一起加油呀!!!!

语言只是工具,不能决定你好不好找工作,决定你好不好找工作的是你的能力!!!!!

学历本科及以上就够用了!!!!!!!!!!!!!!!!!!


本篇博客主要讲解Java基础语法中的 一、链表的简介 1.1链表的概念 1.2链表的八种结构 重点掌握两种结构: 1.3单链表的常见方法 三、单链表的模拟实现 四、LinkedList的模拟实现(双链表) 4.1 什么是LinkedList 4.2LinkedList的使用(及实现) 五、ArrayList和LinkedList的区别

一、链表的简介

1.1链表的概念

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

1.2链表的八种结构

下面三种情况组合起来就有八种2^3。

1. 单向或者双向

2.带头或者不带头

3. 循环或者非循环

重点掌握两种

1.无头单向非循环链表(单链表):结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。

2.无头双向链表(双链表):在Java的集合框架库中LinkedList底层实现就是无头双向循环链表。

1.3单链表的常见方法

代码语言:javascript
复制
 // 1、无头单向非循环链表实现
 public class SingleLinkedList {
    //头插法
    public void addFirst(int data){
   }
    //尾插法
    public void addLast(int data){
   }
    //任意位置插入,第一个数据节点为0号下标
    public void addIndex(int index,int data){
   }
    //查找是否包含关键字key是否在单链表当中
    public boolean contains(int key){
        return false;
   }
    //删除第一次出现关键字为key的节点
    public void remove(int key){
   }
    //删除所有值为key的节点
    public void removeAllKey(int key){
   }
    //得到单链表的长度
    public int size(){
        return -1;
   }
 
    public void clear() {
   }
     
    public void display() {}
 }

三、单链表的模拟实现

用内部类的方式定义链表节点。

代码语言:javascript
复制
    //链表是由每一个节点组成的,每一个节点都是一个对象,
//  如果我们去抽象他,它有两个域,节点是链表的一部分,所以我们把节点定义成内部类
    static class ListNode{
        public int val;//节点的值域,整型
        public ListNode next;//下一个节点的地址,要表示节点的地址,因此是ListNode类型

        //由于new新的节点对象时,值可以知道,但是下一个节点的地址是未知的
        //因此我们创建构造方法时,只初始化val的值,next的值默认为null。
        public ListNode(int val) {
            this.val = val;
        }
    }

再定义一个头结点

代码语言:javascript
复制
    //对于链表本身,还应该有个head,来表示当前链表的头结点,这是我们链表的头结点
    //而不是节点的头结点。因此是链表的属性,切勿放到节点类之中。节点类只有两个属性,值域和下一个节点的地址域
    //要表示节点的地址,因此是ListNode类型
    public ListNode head;

简单的初始化链表

代码语言:javascript
复制
    public void easyCreateList(){
        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;
    }

遍历打印链表

代码语言:javascript
复制
    //注意:head必须一直指向第一个节点的位置,从而来找到这个链表
    //因此我们定义一个ListNode类型的cur。
    public void display(){
        ListNode cur = head;
        if (cur == null){
            System.out.print("当前链表为空,无法打印");
        }
        while (cur != null){
            System.out.printf(cur.val+" ");
            cur = cur.next;
        }
        System.out.println();
    }

从某节点开始打印链表

代码语言:javascript
复制
    public void display(ListNode listNode){
        ListNode cur = listNode;
        if (cur == null){
            System.out.print("当前链表为空,无法打印");
        }
        while (cur != null){
            System.out.printf(cur.val+" ");
            cur = cur.next;
        }
        System.out.println();
    }

求链表的长度

代码语言:javascript
复制
    //求链表的长度
    public int size(){
        int count = 0;
        ListNode cur = head;
        while (cur != null){
            count++;
            cur = cur.next;
        }
        return count;
    }

是否链表是否包含关键字key

代码语言:javascript
复制
    //是否链表是否包含关键字key
    public boolean contains(int key){
        ListNode cur = head;
        while (cur != null){
            if(key == cur.val){
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

头插法

代码语言:javascript
复制
    //头插法,就算链表里一个节点都没有,此方法也可以插入新的节点
    //因此创建链表可以用此方法创建
    public void addFirst(int data){
        ListNode node = new ListNode(data);
        node.next = head;
        head = node;
    }

尾插法

代码语言:javascript
复制
    //尾插法,在链表最后面插入元素
    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;
    }

在指定位置插入元素

代码语言:javascript
复制
    //在指定位置插入元素
    public void addIndex(int index, int data){
        if(index < 0|| index > size()){
            System.out.println("index不合法");
            return;
        }
        if(index == 0){
            addFirst(data);
            return;
        }
        if(index == size()){
            addLast(data);
            return;
        }
//        ListNode node = new ListNode(data);
//        ListNode pre = head;
//        int count = 0;
//        while (true){
//            pre = pre.next;
//            count++;
//            if (index == count+1){
//                node.next = pre.next;
//                pre.next = node;
//                break;
//            }
//        }
        ListNode cur = findIndexSubOne(index);
        ListNode node = new ListNode(data);
        node.next = cur.next;
        cur.next = node;
    }

找到要删除节点的位置的前一个节点

代码语言:javascript
复制
    //找到要删除节点的位置的前一个节点
    private ListNode findIndexSubOne(int index){
        ListNode cur = head;
        for (int i = 0; i<index-1; i++){
            cur = cur.next;
        }
        return cur;

//        while (index-1 != 0){
//            cur = cur.next;
//            index--;
//        }
//        return cur;
    }

删除第一次出现关键字为key的节点

代码语言:javascript
复制
    //删除第一次出现关键字为key的节点
    public void remove(int key){
        if(head == null){
            System.out.println("当前链表为空,您要删除的数据不存在");
            return;
        }
        if (head.val == key){
            head = head.next;
            return;
        }
        ListNode cur = searchPrev(key);
        if (cur == null){
            System.out.println("没有找到你要删除的数字");
            return;
        }
        cur.next = cur.next.next;
    }

找到key的前驱

代码语言:javascript
复制
    //找到key的前驱
    private ListNode searchPrev(int key){
        ListNode cur = head;
        while (cur.next!=null){
            if (cur.next.val == key){
                return cur;
            }
            cur = cur.next;
        }
        return null;
    }

删除链表中元素

代码语言:javascript
复制
    public void removeAllKey(int key){
        if(head == null){
            System.out.println("当前链表为空,无法删除!");
            return;
        }
        ListNode cur = head.next;
        ListNode prev = head;
        while (cur != null){
            if(cur.val == key){
                prev.next = cur.next;
                cur = cur.next;
            }else {
                cur = cur.next;
                prev = prev.next;
            }
        }
        if (head.val == key){
            head = head.next;
        }
    }

逆置链表

代码语言:javascript
复制
    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;
    }
代码语言:javascript
复制
    public void reverseList(){
        if(head == null){
            return;
        }
        if(head.next == null){
            return;
        }

        ListNode cur = head.next;
        head.next = null;
        while (cur != null){
            ListNode curNext = cur.next;
            cur.next = head;
            head = cur;
            cur = curNext;
        }
    }

用栈的方式逆序打印链表

代码语言:javascript
复制
    //用栈的方式逆序打印链表
    public void reverseStackList(){
        Stack<ListNode> stack = new Stack<>();
        ListNode cur = head;
        while (cur != null){
            stack.push(cur);
            cur=cur.next;
        }
        while (!stack.isEmpty()){
            ListNode top = stack.pop();
            System.out.print(top.val+" ");
        }
        System.out.println();
    }

暴力清空链表

代码语言:javascript
复制
    public void clear(){
        this.head = null;
    }

四、LinkedList的模拟实现(双链表)

4.1 什么是LinkedList

LinkedList:的底层是双向链表结构,由于链表没有将元素存储在连续的空间中,元素存储在单独的节 点中,然后通过引用将节点连接起来了,因此在在任意位置插入或者删除元素时,不需要搬移元素,效率比较高。

在集合框架中,LinkedList也实现了List接口,具体如下:

说明

1. LinkedList实现了List接口

2. LinkedList的底层使用了双向链表

3. LinkedList没有实现RandomAccess接口,因此LinkedList不支持随机访问

4. LinkedList的任意位置插入和删除元素时效率比较高,时间复杂度为O(1)

5. LinkedList比较适合任意位置插入的场景

4.2LinkedList的使用(及实现)

1. LinkedList的构造

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

3.方法的具体实现

使用内部类构造双链表的节点,头节点,尾结点

代码语言:javascript
复制
    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;//双向链表的尾巴

头插法

代码语言:javascript
复制
    //头插法
    public void addFirst(int data){
        ListNode node = new ListNode(data);
        if (head == null){
            head = node;
            last = node;
            return;
        }
        head.prev =node;
        node.next = head;
        head = node;
    }

尾插法

代码语言:javascript
复制
    //尾插法
    public void addLast(int data){
        ListNode node =new ListNode(data);
        if (head == null){
            head = node;
            last = node;
            return;
        }
        last.next =node;
        node.prev = last;
        last = node;
    }

链表长度

代码语言:javascript
复制
    //链表长度
    public int size(){
        int count = 0;
        ListNode cur = head;
        while (cur != null){
            cur = cur.next;
            count++;
        }
        return count;
    }

打印链表

代码语言:javascript
复制
    //打印链表
    public void display(){
        ListNode cur = head;
        if (cur == null){
            System.out.println("该链表为空,无法打印!");
            return;
        }
        while (cur != null){
            System.out.print(cur.val+" ");
            cur = cur.next;
        }
        System.out.println();//方便测试看数据
    }

链表是否包含某元素

代码语言:javascript
复制
    //链表是否包含某元素
    public boolean contains(int key){
        ListNode cur = head;
        if (cur == null){
            System.out.println("该链表为空!");
            return false;
        }
        while (cur != null){
            if(cur.val == key){
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

检查下标是否异常

代码语言:javascript
复制
    //检查下标是否异常
    public void checkIndex(int index){
        if (index<0 || index >size()){//等于size用尾插法
            throw new indexOutOfException("index 不合法!"+index);
        }
    }

在某位置添加元素

代码语言:javascript
复制
    public void addIndex(int index, int data) {
        checkIndex(index);
        if (index == 0) {
            addFirst(data);
            return;
        }
        if(index == size()) {
            addLast(data);
            return;
        }
        ListNode node = new ListNode(data);
//            while (index !=0){
//                cur = cur.next;
//                index--;
//            }
        ListNode cur = searchIndexNode(index);
        node.prev=cur.prev;
        node.next=cur;
        cur.prev.next = node;
        cur.prev = node;
    }

找到第n个节点的位置

代码语言:javascript
复制
    //双链表,由于知道了前一个节点的位置
    //因此插进第n个元素时直接找到第n个节点的位置就可以
    private ListNode searchIndexNode(int index){
        ListNode cur =head;
        while (index !=0){
            cur = cur.next;
            index--;
        }
        return cur;
    }

删除第一个出现的某元素

删除链表中所有这个元素

后续会添加完整的代码

五、ArrayList和LinkedList的区别

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-07-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 一、链表的简介
    • 1.1链表的概念
      • 1.2链表的八种结构
        • 重点掌握两种
          • 1.3单链表的常见方法
          • 三、单链表的模拟实现
          • 四、LinkedList的模拟实现(双链表)
            • 4.1 什么是LinkedList
              • 4.2LinkedList的使用(及实现)
              • 五、ArrayList和LinkedList的区别
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档