顺序表、链表(ArrayList、LinkedList)

news2025/1/20 6:03:06

目录

前言:

顺序表(ArrayList):

顺序表的原理:

ArrayList源码: 

的含义:​编辑

ArrayList的相关方法:​编辑

向上转型List: 

练习题(杨辉三角): 

扑克牌游戏:

链表(LinkedList): 

链表的原理:

自定义链表的实现:

LinkedList源码: 

LinkedList使用注意事项: 

练习题(判断是否是会问链表): 

迭代器(Iterator): 

总结: 


前言:

        本篇我们来讲解数据结构中的顺序表和顺序表,因为Java有集合框架,所以可以直接使用类创建对象来完成。

顺序表(ArrayList):

顺序表的原理:

        顾名思义,就是有顺序的表,类是ArrayList,底层原理是一个数组,当到达最大容量时,会进行扩容。

        当一个数组(顺序表)中存放的基本类型数据时,我们想要全部清除可以直接将有效下标置为0,这样再添加就是覆盖的效果。

        但是如果数组中存放的是引用类型,则不能这样。因为基本类型都会默认初始化,比如整形会默认初始化为0。

        此时引用类型不能直接将有效下标置为0,否则会发生内存泄漏。 因为引用类型开辟的空间没有回收,JVM中,回收算法有很多。最好通过for循环来置空。

for() {
    elem[i] = null;
}

ArrayList源码: 

        接下来我们就来细致观察ArrayList源码: ArrayList底层就是顺序表,继承了AbstractList类,里面重写了toString方法。

        ArrayList底层就是顺序表,继承了AbstractList类,里面重写了toString方法。

public static void main(String[] args) {
    ArrayList<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(0,99);
    for (int i = 0; i < list.size(); i++) {
        System.out.println(list.get(i) + " ");
    }

    System.out.println(list);
}

        ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表。

        我们再来看源码:

        此时就分配了10个空间。 

        所以当使用无参构造器时,第一次添加元素是申请10个空间,之后每次到达上限以后就扩容1.5倍。

<? extends E>的含义:

         因为ArrayList实现了Collection接口。

public class Test {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);

        ArrayList<Number> list1 = new ArrayList<>(list);

        list1.add(99);
        list1.add(88);
        System.out.println(list1);
    }
}

ArrayList的相关方法:

public static void main(String[] args) {
    ArrayList<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    System.out.println(list);

    ArrayList<Number> list1 = new ArrayList<>();
    list1.addAll(list);
    list1.remove(new Integer(2));//删除指定对象
    System.out.println(list1);

}

        我们来观察一下代码: 

public static void main(String[] args) {
    ArrayList<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    list.add(4);

    List<Integer> list1 = list.subList(1, 3);//[1,3)
    list1.set(1,99);
    System.out.println(list);
    System.out.println(list1);
}

向上转型List: 

List<List<Integer>> list1 = new ArrayList<>();
list1.add(new ArrayList<>());
list1.add(new ArrayList<>());

        观察这个代码,意思其实是有一个ArrayList类,每一个元素里面是一个ArrayList存放整形的引用类型(List是一个接口)。其实可以理解为二维数组。

练习题(杨辉三角): 

class Solution {
    public List<List<Integer>> generate(int numRows) {
        List<List<Integer>> ret = new ArrayList<>();
        List<Integer> list = new ArrayList<>();
        list.add(1);

        ret.add(list);

        for (int i = 1; i < numRows; i++) {
            List<Integer> cur = new ArrayList<>();
            cur.add(1);

            //获取上一行
            List<Integer> prev = ret.get(i - 1);
            for (int j = 1; j < i; j++) {
                int val = prev.get(j) + prev.get(j - 1);
                cur.add(val);
            }

            //将此行最后一个元素置为1
            cur.add(1);
            ret.add(cur);
        }
        return ret;
    }
}

扑克牌游戏:

public class Test {
    public static void main(String[] args) {
        CardDome cardDome = new CardDome();
        List<Card> cardList = cardDome.buyCard();
        System.out.println("买的牌如下:");
        System.out.println(cardList);

        System.out.println("洗牌");
        cardDome.shuffle(cardList);
        System.out.println(cardList);

        System.out.println("揭牌:");
        cardDome.getCards(cardList);
    }
}
public class CardDome {
    //定义四种花色
    private static final String[] suits = {"♥","♣","♦","♠"};

    //52张
    //J - 11  Q - 12  K - 13
    //买一副牌
    public List<Card> buyCard() {
        List<Card> cardList = new ArrayList<>();
        for (int i = 0; i < 4; i++) {
            for (int j = 1; j <= 13; j++) {
                Card card = new Card(suits[i], j);
                cardList.add(card);
            }
        }

        return cardList;
    }

    //洗牌
    public void shuffle(List<Card> cardList) {
        //生成随机数
        Random random = new Random();
        //从后向前打乱
        for (int i = cardList.size() - 1; i > 0; i--) {
            //有52张牌
            //第一次生成的就是 0 - 50 的随机数
            int index = random.nextInt(i);

            //index i 交换
            swap(cardList, i, index);
        }
    }

    private void swap(List<Card> cardList, int e1,int e2) {
        Card tmp = cardList.get(e1);
        cardList.set(e1,cardList.get(e2));
        cardList.set(e2,tmp);
    }

    //揭牌
    public void getCards (List<Card> cardList) {
        //3个人
        List<Card> hand1 = new ArrayList<>();
        List<Card> hand2 = new ArrayList<>();
        List<Card> hand3 = new ArrayList<>();

        List<List<Card>> hand = new ArrayList<>();
        hand.add(hand1);
        hand.add(hand2);
        hand.add(hand3);

        //3个人轮流抓牌5张牌
        for (int i = 0; i < 5; i++) {
            //j 代表人
            for (int j = 0; j < 3; j++) {
                Card card = cardList.remove(0);
                hand.get(j).add(card);
            }
        }

        System.out.println("第一个人揭牌如下:");
        System.out.println(hand1);
        System.out.println("第二个人揭牌如下:");
        System.out.println(hand2);
        System.out.println("第三个人揭牌如下:");
        System.out.println(hand3);

        System.out.println("剩下的牌:");
        System.out.println(cardList);
    }
}
public class Card {
    private String suit;//花色
    private int rank;//数字

    public Card(String suit, int rank) {
        this.suit = suit;
        this.rank = rank;
    }

    public String getSuit() {
        return suit;
    }

    public void setSuit(String suit) {
        this.suit = suit;
    }

    public int getRank() {
        return rank;
    }

    public void setRank(int rank) {
        this.rank = rank;
    }

    @Override
    public String toString() {
        return suit + ":" + rank + " ";
    }
}

链表(LinkedList): 

链表的原理:

        顺序表还是有缺点的,因为每次都是1.5倍扩容,所以有时量大时就会浪费内存,所以就衍生出了链表,不是连续内存,如果了解C语言中的链表,那么将是易如反掌。

自定义链表的实现:

        我们定义head成员,是为了保存头结点。

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(33);
        ListNode node3 = new ListNode(99);
        ListNode node4 = new ListNode(67);
        ListNode node5 = new ListNode(88);

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

        this.head = node1;
    }
}

LinkedList源码: 

        LinkedList的底层代码,可以发现这就是一个双向循环链表。 LinkedList的任意位置插入和删除元素师效率比较高,时间复杂度为O(1),比较适合任意位置插入的场景。

        还有很多方法无法注意介绍,大家可以看Structure里面的所有相关方法、属性和内部类。因为效率高,所以底层只使用了双向链表,没有使用单向链表。

LinkedList使用注意事项: 

        当我们使用的是自定义链表时(就是没用Java框架),清空链表,可以直接将头尾置空,也可以逐个将其置空。因为Java有回收算法。

        这里我们使用迭代器进行遍历,我们也可以反向遍历: 

public class Test2 {
    public static void main(String[] args) {
        LinkedList<Integer> linkedList = new LinkedList<>();
        linkedList.add(1);
        linkedList.add(2);
        System.out.println(linkedList);

        //通过迭代器遍历链表
        ListIterator<Integer> it1 = linkedList.listIterator();
        while (it1.hasNext()) {
            System.out.print(it1.next() + " ");
        }
        System.out.println();

        System.out.println("===反向===");
        ListIterator<Integer> it2 = linkedList.listIterator(linkedList.size());
        while (it2.hasPrevious()) {
            System.out.print(it2.previous() + " ");
        }
    }
}

 

练习题(判断是否是会问链表): 

public class PalindromeList {
    public boolean chkPalindrome(ListNode head) {
        if (head == null || head.next == null) {
            return true;
        }
        // write code here
        ListNode slow = head;
        ListNode fast = head;
        while(fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }

        //翻转slow以后的链表
        ListNode cur = slow.next;
        while (cur != null) {
            ListNode nextPos = cur.next;
            //翻转(利用指针翻转)
            cur.next = slow;
            slow = cur;
            cur = nextPos;
        }

        //从前向后 从后向前
        while(head != slow) {
            if (slow.val != head.val) {
                return false;
            }
            if (head.next == slow) {
                return true;
            }
            head = head.next;
            slow = slow.next;
        }
        return true;

    }
}

迭代器(Iterator): 

        我们可以利用迭代器进行遍历:

public static void main(String[] args) {
    ArrayList<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    list.add(4);

    Iterator<Integer> it = list.iterator();
    while(it.hasNext()) {
        System.out.print(it.next() + " ");
    }
}

总结: 

        这里我还是默认各位都有基础,希望可以对有基础的人有些帮助(更多的是记笔记),感谢各位支持。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1447181.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

单页404源码

<!doctype html> <html> <head> <meta charset"utf-8"> <title>简约 404错误页</title><link rel"shortcut icon" href"./favicon.png"><style> import url("https://fonts.googleapis.co…

Java中抽象类和接口的区别

抽象类和接口都是 Java 中多态的常见使用方式. 都需要重点掌握. 同时又要认清两者的区别(重要!!! 常见面试题)。 核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写而重写抽象方法), 而接口中不能包含普通方法&#xff08;接口…

生成式人工智能(AIGC)之最全详解图解

生成式人工智能&#xff08;AIGC&#xff09;之最全详解图解 1. AIGC的发展历程1.1 AIGC演化重要时间节点AIGC发展历程图OpenAI大语言模型发展进程 1.2技术推进路线 2.AIGC技术场景2.1 技术场景 3.1AIGC相关应用4.AIGC未来发展前景 1. AIGC的发展历程 AIGC&#xff08;AI-Gene…

ClickHouse--04--数据库引擎、Log 系列表引擎、 Special 系列表引擎

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.数据库引擎1.1 Ordinary 默认数据库引擎1.2 MySQL 数据库引擎MySQL 引擎语法字段类型的映射 2.ClickHouse 表引擎3.Log 系列表引擎几种 Log 表引擎的共性是&#…

任务调度

1.学习目标 1.1 定时任务概述 1.2 jdk实现任务调度 1.3 SpringTask实现任务调度 1.4 Spring-Task 分析 1.5 Cron表达式 https://cron.qqe2.com/ 2. Quartz 基本应用 2.1 Quartz 基本介绍 2.2 Quartz API介绍 2.3 入门案例 <dependency> <groupId>org.springframe…

《Java 简易速速上手小册》第7章:Java 网络编程(2024 最新版)

文章目录 7.1 网络基础和 Java 中的网络 - 揭开神秘的面纱7.1.1 基础知识7.1.2 重点案例&#xff1a;实现一个简单的聊天程序7.1.3 拓展案例 1&#xff1a;使用 UDP 进行消息广播7.1.4 拓展案例 2&#xff1a;建立一个简单的 Web 服务器 7.2 创建客户端和服务器 - 构建沟通的桥…

Microsoft Word 清除格式

Microsoft Word 清除格式 References 选择文本&#xff0c;用快捷键 Ctrl Shift N&#xff0c;可以快速清除格式。 选择文本&#xff0c;清除格式。 References [1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/

Java图形化界面编程—— ImageIO 笔记

2.8.4 ImageIO的使用 在实际生活中&#xff0c;很多软件都支持打开本地磁盘已经存在的图片&#xff0c;然后进行编辑&#xff0c;编辑完毕后&#xff0c;再重新保存到本地磁盘。如果使用AWT要完成这样的功能&#xff0c;那么需要使用到ImageIO这个类&#xff0c;可以操作本地磁…

【数据结构】二叉树先序、中序、后序及层次四种遍历(C语言版)

数据结构——二叉树先序、中序、后序三种遍历 一、图示展示&#xff1a; &#xff08;1&#xff09;先序遍历&#xff08;2&#xff09;中序遍历&#xff08;3&#xff09;后序遍历&#xff08;4&#xff09;层次遍历&#xff08;5&#xff09;口诀 二、代码展示&#xff1a; 一…

使用JNDI API

使用JNDI API Java EE应用程序使用JNDI API作为通用的名称查找服务来查找组件、外部资源和组件环境属性。JNDI API公开底层命名协议和实现的详细信息。 1. JNDI API的架构 JNDI架构由以下组件组成: JNDI API:它可让Java应用程序访问各种命名服务和目录服务。JNDI服务提供商接…

‘vue-cli-service‘ 不是内部或外部命令,也不是可运行的程序

遇到 vue-cli-service 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。 的错误时&#xff0c;通常意味着Vue CLI没有被正确安装或配置在项目中。这可能是因为node_modules目录缺失了必要的包&#xff0c;或者局部安装的Vue CLI没有被正确设置到系统的PATH环境…

理解JAVA命名和目录接口(JNDI)

理解JAVA命名和目录接口(JNDI) 考虑访问网站的场景,Web用户要求记住四字节的IP地址而不是有意义的名称。例如,假设Web用户用123.23.3.123而不是hotmail.com访问hotmail网站。在这种情形下,Web用户难以记住不同的IP地址来访问不同的网站。因此,要使其变得对Web用户简单方…

九、java 继承

文章目录 java 继承3.1 根父类Object3.2 方法重写3.3 继承案例&#xff1a;图形类继承体系3.4 继承的细节3.4.1 构造方法3.4.2 重名与静态绑定3.4.3 重载和重写3.4.4 父子类型转换3.4.5 继承访问权限protected3.4.6 可见性重写3.4.7 防止继承final 3.5 继承是把双刃剑3.5.1 继承…

lime-echart 一个基于 JavaScript 的开源可视化图表库 使echarts图表能跑在uniapp各端中的插件

Lime-echart 是一个基于 JavaScript 的开源可视化图表库&#xff0c;旨在使 ECharts 图表能够在 UniApp 各个端中运行。UniApp 是一个跨平台的应用程序开发框架&#xff0c;允许开发人员使用 Vue.js 开发一次&#xff0c;然后部署到多个平台&#xff0c;包括 iOS、Android、Web…

openGauss学习笔记-218 openGauss性能调优-确定性能调优范围-硬件瓶颈点分析-I/O

文章目录 openGauss学习笔记-218 openGauss性能调优-确定性能调优范围-硬件瓶颈点分析-I/O218.1 查看I/O状况218.2 性能参数分析 openGauss学习笔记-218 openGauss性能调优-确定性能调优范围-硬件瓶颈点分析-I/O 获取openGauss节点的CPU、内存、I/O和网络资源使用情况&#xf…

数据库基本操作2

一.DML&#xff08;Data Manipulation Language&#xff09; 用来对数据库中表的数据记录进行更新 关键字&#xff1a;增删改 插入insert 删除delete 更新update 1.数据插入 insert into 表&#xff08;列名1&#xff0c;列名2&#xff0c;列名3……&#xff09;values&a…

STM32Cubmax DAC 采集

一、概念 DMA&#xff0c;全称为&#xff1a; Direct Memory Access&#xff0c;即直接存储器访问&#xff0c; DMA 传输将数据从一个 地址空间复制到另外一个地址空间。 当 CPU 初始化这个传输动作&#xff0c;传输动作本身是由 DMA 控制器 来实行和完成。典型的例子就是移动…

谁再用Arrays.asList就开除谁

谁再用Arrays.asList就开除谁 hi&#xff0c;我是achang&#xff0c;今天说一个使用Arrays.asList后对应出现的一系列坑&#xff0c;因为他有那么多坑&#xff0c;所以会有开玩笑的说&#xff1a;谁再用Arrays.asList就开除谁 那Arrays.asList的作用很简单&#xff0c;就是把…

Python中多种生成随机密码超实用实例

前言 密码是信息安全的基石&#xff0c;它用于保护我们的账户、数据和隐私。为了确保密码足够强大&#xff0c;需要生成随机密码。在本文中&#xff0c;将讨论多种Python方法&#xff0c;用于生成随机密码的实用示例和技巧。 目录 ​编辑 前言 密码生成的要求 使用secrets…

每日五道java面试题之java基础篇(七)

第一题. HashMap和HashTable有什么区别&#xff1f;其底层实现是什么&#xff1f; 区别 &#xff1a; HashMap⽅法没有synchronized修饰&#xff0c;线程⾮安全&#xff0c;HashTable线程安全&#xff1b;HashMap允许key和value为null&#xff0c;⽽HashTable不允许 底层实现…