01、数据结构与算法--顺序表

正式进入数据结构的学习,先从预备知识学起,戒焦戒躁戒焦戒躁...


一、泛型的引入

1、为什么需要泛型?

先来看一个题目:

实现一个类,类中包含一个数组成员,使得数组中可以存放任何类型的数据,也可以根据成员方法返回数组中某个下标的值

在没有泛型理念的思路可能是这样:

public class java0810 {public Object[] array = new Object[5];//成员变量public void set(int a,Object b){this.array[a] = b;}public Object get(int c){return array[c];}public static void main(String[] args) {java0810 x = new java0810();x.set(0,"哈哈");x.set(1, 2);String y1 = (String) x.get(0);int y2 = (int) x.get(1);  //需要强转,因为是object类型System.out.println(y1);System.out.println(y2);}
}

我们通过Object类做到了让一个数组中放入不同类型的数据,但在接收数据的时候需要对其进行强转,很麻烦


于是我们想到使用泛型来解决这个问题:

public class java0810<T> {  //变动1public Object[] array = new Object[5];public void set(int a,T b){this.array[a] = b;}public T get(int c){return (T)array[c]; //变动2}public static void main(String[] args) {    //变动3java0810<Integer> x1 = new java0810<>();//规定了存放数据的类型x1.set(0,1);x1.set(1,2);int y1 = x1.get(0);int y2 = x1.get(1);System.out.println(y1);System.out.println(y2);java0810<String> x2 = new java0810<>();x2.set(0,"巨浪");x2.set(1,"M14大人");String y3 = x2.get(0);String y4 = x2.get(1);System.out.println(y3);System.out.println(y4);}

所有的变动之处需要理解,这样做的好处就是:

“在新建一个对象时就规定了存放数据的类型,可以让系统帮忙检查同时不用强转了”

想要深入理解背后的逻辑可以搜索擦除机制桥接方法


2、泛型类的上界

我们常常用 <? extends T> 的方式来指定约束泛型类型的上限,从而约束了‘ ?’只能是T或者其子类

来看一个题目:

写一个泛型类,求数组中的最大值,数组的类型需要通过泛型类型来指定

                            //这是一个泛型类public class java0811<T extends Comparable<T>>  {//泛型类的上界public T find(T[] array){int i = 0;T max = array[0];for(i = 1;i < array.length;i++){if(array[i].compareTo(max) > 0){max = array[i];}}return max;}public static void main(String[] args) {java0811<Integer> y1 = new java0811<>(); //指定数组存放的类型java0811<String> y2 = new java0811<>();Integer []array1 = { 4, 3, 2, 91, 500 };String  []array2 = {"巨浪", "M14大人","腾龙"};int z = y1.find(array1);     //Integer或者int都可以String w = y2.find(array2);System.out.println(z);System.out.println(w);}}

这里通过实现了Comparable接口,指定了上界,从而可以使用comparaTo方法进行数字或者字符串的无差别比较

当然了,你也可以写成是一个泛型方法:

 public class java0811 {//这就是泛型方法public <T extends Comparable<T>> T find(T[] array){int i = 0;T max = array[0];for(i = 1;i < array.length;i++){if(array[i].compareTo(max) > 0){max = array[i];}}return max;}public static void main(String[] args) {java0811 x = new java0811();  //没有指定类型,因为它不是泛型类了Integer []array1 = { 4, 3, 2, 91, 500 };int y = x.find(array1);System.out.println(y);}
}

可以观察一下里面的变动


二、通配符

1、概念:

通配符通过上下界(extends/super)实现了比泛型类型参数更灵活的类型关系控制,并遵循PECS原则(在值设置和取出时有特定约束)。

我们先来看看通过泛型的方式存放和取出数据:

class Food{                 
}
class Fruit extends Food{     //先明确了继承关系
}
class apple extends Fruit{
}
class banana extends Fruit{
}public class Plate<T>{        //设置了一个泛型类public T array;public void set(T array){this.array = array;
}public T get(){return array;
}public static void main(String[] args) {Plate<apple> x1= new Plate<>();    //表示只能放入apple对象x1.set(new apple());Plate<banana> x2 = new Plate<>();  //同理x2.set(new banana());//     Plate<Food> x3 = new Plate<>();
//      fun1(x3);                      //会失败,因为通配符所以只能传入Fruit的子类fun1(x1);fun1(x2);}//通配符的上界
public static void fun1(Plate<? extends Fruit> z){//指定一个容器,存放的类型是Fruit或子类System.out.println(z.get());
}

这里通过fun来打印数据,接收的类型需要是Fruit或者其子类

2、通配符的上界:

采用<? extends T>的方式,在该方法中不能写入子类,但可以接收T的子类

public static void fun1(Plate<? extends Fruit> z){//指定一个容器,存放的类型是Fruit或子类System.out.println(z.get());//    z.set(new apple());
//    z.set(new banana());     设置失败,不能知道传入的是哪个子类Fruit fruit = z.get();      //得到的一定是Fruit的子类System.out.println(fruit);  //成功了,同时打印了apple跟banana}

3、通配符的下界:

采用<? super T>的方式,在该方法中主要用于写入,接收时要用Object类保证安全

public static void main(String[] args) {Plate<Food> x3 = new Plate<>();x3.set(new Food());fun2(x3);}
public static void fun2(Plate<? super Fruit> t){t.set(new Fruit());     //可以放自己以及子类t.set(new apple());t.set(new banana());    //会打印最后一个传入的值//   Food food = new Fruit();
//   Fruit fruit2 = (Fruit) food;     //这样做就安全//    Fruit fruit2=(Fruit) new Food();//但是这样直接指向不安全,打印不出来结果//    Fruit fruit3 = (Fruit) t.get(); //觉得这个写法突兀的就向上看,也不安全Object o = t.get();               //Object来接收就安全了System.out.println(o);
}

小总结:通配符上界不能写入子类但能接收子类

               通配符下界只能写入自己以及子类,只能接收自己以及父类 


三、顺序表

顺序表(Sequential List) 是一种线性表,它用一段地址连续的存储单元依次存储线性表的数据元素

核心比喻:电影院座位

你可以把顺序表想象成电影院里一排连续的座位

  1. 连续存储:这些座位是紧挨着的,一个接一个,拥有固定的座位号(如1排1座、1排2座...)。这就是“顺序”的含义——数据在物理内存中是连续存储的。

  2. 快速“按号找座”:如果你想找第5个座位上坐的是谁,你可以立刻计算出来并直接走过去。

  3. “插队”与“离场”麻烦

    • 插入:如果这排座位已经坐满了,你想在中间加一个人,那么从这个位置开始以后的所有人都需要向后移动一个位置,才能空出一个新的座位。

    • 删除:同理,如果中间有一个人离开了,那么他后面的所有人都需要向前移动一个位置来填补空位,以保持座位的连续性。

这是一个自己实现的顺序表:

public interface IList {void add(int data); // 新增元素,默认在数组最后新增void add(int pos, int data); // 在 pos 位置新增元素boolean contains(int toFind); // 判定是否包含某个元素int indexOf(int toFind); // 查找某个元素对应的位置int get(int pos); // 获取 pos 位置的元素void set(int pos, int value); // 给 pos 位置的元素设为 valuevoid remove(int toRemove); //删除第一次出现的关键字keyint size(); // 获取顺序表长度void clear(); // 清空顺序表void display(); // 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的boolean isFull();boolean isEmpty();}
import java.util.Arrays;public class MyarrayList implements IList{public int[]array;public int useside;public static final int l = 5;public  MyarrayList(){array = new int[l];}//检查是否放满了@Overridepublic boolean isFull() {if(useside == array.length){return true;}return false;}@Overridepublic boolean isEmpty() {if(useside == 0){return true;}return false;}//自己设置的2倍扩容public void grow(){array = Arrays.copyOf(array,2 * array.length);}//在顺序表中,默认在最后位置添加元素,这个没有@Overridepublic void add(int data) {array[useside++] = data;}public void checkpos(int pos){if(pos < 0 || pos > useside){//这里在数组末尾插入是合法的throw new ArrayIndexOutOfBoundsException("pos位置不合法" + pos);}                            //自定义异常}public void checkpos2(int pos){ //一个典型的受检异常if(pos < 0 || pos >= useside){throw new ListEmptyException("获取位置不合法" + pos);}}@Overridepublic void add(int pos,int data) {checkpos(pos);if(isFull()){grow();}                        //移动元素for(int i = useside - 1;i >= pos;i--){array[i+1] = array[i];}array[pos] = data;useside++;             //新加入了元素就更新计数}@Overridepublic boolean contains(int toFind) {for (int i = 0; i < array.length; i++) {if(array[i] == toFind){return true;}}return false;}@Overridepublic int indexOf(int toFind) {for (int i = 0; i < useside; i++) {//这里写成了array.length会打印没用的0if (array[i] == toFind){return i;}}return -1;             //-1肯定不属于下标}@Overridepublic int get(int pos) {if(isEmpty()){throw new ArrayIndexOutOfBoundsException("数组是空的");}checkpos2(pos);return array[pos];}@Overridepublic void set(int pos, int value) {checkpos(pos);array[pos] = value;}@Overridepublic int size() {return array.length;}@Overridepublic void clear() {
//        for (int i = 0; i < array.length; i++) {
//            array[i] = 0/Null;
//        }useside = 0;}@Overridepublic void display() {//这里也是一样,要写useside而不是array.lengthfor (int i = 0; i < useside; i++) {System.out.print(array[i] + " ");}System.out.println();}@Overridepublic void remove(int toRemove) {int v = indexOf(toRemove);if(v == -1){System.out.println("找不到要删除的值");return;             //终止代码}for (int i = v; i < useside-1; i++) {array[i] = array[i+1];}useside--;}public static void main(String[] args) {MyarrayList x = new MyarrayList();x.add(0,9);       //在1位置添加一个9x.add(1,2);x.add(2,3);x.display();
//        try {
//            x.checkpos(100);
//        }catch (ArrayIndexOutOfBoundsException e){
//            e.printStackTrace();
//        }int c = x.get(1);System.out.println(c);x.remove(100);x.display();}}
public class ListEmptyException extends RuntimeException{public ListEmptyException() {}public ListEmptyException(String message) {super(message);}
}

自己实现过后有助于我们更好的理解顺序表


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

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

相关文章

8.23打卡 DAY 50 预训练模型+CBAM模块

DAY 50: 预训练模型与 CBAM 模块的融合与微调 今天&#xff0c;我们将把之前学到的知识融会贯通&#xff0c;探讨如何将 CBAM 这样的注意力模块应用到强大的预训练模型&#xff08;如 ResNet&#xff09;中&#xff0c;并学习如何高效地对这些模型进行微调&#xff0c;以适应我…

北极圈边缘生态研究:从数据采集到分析的全流程解析

原文链接&#xff1a;https://onlinelibrary.wiley.com/doi/10.1111/1744-7917.70142?afR北极圈边缘生态研究&#xff1a;从数据采集到分析的全流程解析简介本教程基于一项在俄罗斯摩尔曼斯克州基洛夫斯克市开展的长期生态学研究&#xff0c;系统讲解如何对高纬度地区特定昆虫…

Excel处理控件Aspose.Cells教程:使用Python将 Excel 转换为 NumPy

使用 Python 处理 Excel 数据非常常见。这通常涉及将数据从 Excel 转换为可高效操作的形式。将 Excel 数据转换为可分析的格式可能非常棘手。在本篇教程中&#xff0c;您将学习借助强大Excel处理控件Aspose.Cells for Python&#xff0c;如何仅用几行代码将 Excel 转换为 NumPy…

python 字典有序性的实现和OrderedDict

文章目录 一、Python 3.7+ 字典有序性的验证 二、如何在字典头部插入键值对 方法 1:创建新字典(推荐) 方法 2:使用 `collections.OrderedDict`(适合频繁头部插入场景) 方法 3:转换为列表操作(不推荐,效率低) 底层核心结构:双数组哈希表 有序性的实现原理 与旧版本(…

JVM 调优全流程案例:从频繁 Full GC 到百万 QPS 的实战蜕变

&#x1f525; JVM 调优全流程案例&#xff1a;从频繁 Full GC 到百万 QPS 的实战蜕变 文章目录&#x1f525; JVM 调优全流程案例&#xff1a;从频繁 Full GC 到百万 QPS 的实战蜕变&#x1f9e9; 一、调优本质&#xff1a;性能瓶颈的破局之道&#x1f4a1; 为什么JVM调优如此…

基于TimeMixer现有脚本扩展的思路分析

文章目录1. 加入数据集到data_loader.py和data_factory.py2. 参照exp_classification.py写自定义分类任务脚本&#xff08;如exp_ADReSS.py&#xff09;3. 接一个MLP分类头4. 嵌入指标计算、绘图、保存训练历史的函数5. 开始训练总结**一、可行性分析****二、具体实现步骤****1…

技术演进中的开发沉思-75 Linux系列:中断和与windows中断的区分

作为一名从 2000 年走过来的老程序员&#xff0c;看着 IT 技术从桌面开发迭代到微服务时代&#xff0c;始终觉得好技术就像老故事 —— 得有骨架&#xff08;知识点&#xff09;&#xff0c;更得有血肉&#xff08;场景与感悟&#xff09;。我想正是我的经历也促成了我想写这个…

【8位数取中间4位数】2022-10-23

缘由请输入一个8位的十进制整数&#xff0c;编写程序取出该整数的中间4位数&#xff0c;分别输出取出的这4位数以及该4位数加上1024的得数。 输入&#xff1a;一个整数。 输出&#xff1a;两个整数&#xff0c;用空格分隔-编程语言-CSDN问答 int n 0;std::cin >> n;std:…

mac电脑使用(windows转Mac用户)

首先&#xff0c;我们学习mac的键盘复制 command c 粘贴 command v 剪切 command xlinux命令行 退出中止 control c 退出后台 control d中英文切换大小写&#xff0c;按住左边向上的箭头 字母鼠标操作 滚轮&#xff1a;2个指头一起按到触摸板&#xff0c;上滑&#xff0c;…

项目中优惠券计算逻辑全解析(处理高并发)

其实这个部分的代码已经完成一阵子了&#xff0c;但是想了一下决定还是整理一下这部分的代码&#xff0c;因为最开始做的时候业务逻辑还是感觉挺有难度的整体流程概述优惠方案计算主要在DiscountServiceImpl类的findDiscountSolution方法中实现。整个计算过程可以分为以下五个步…

支持电脑课程、游戏、会议、网课、直播录屏 多场景全能录屏工具

白鲨录屏大师&#xff1a;支持电脑课程、游戏、会议、网课、直播录屏 多场景全能录屏工具&#xff0c;轻松捕捉每一刻精彩 在数字化学习、娱乐与办公场景中&#xff0c;高质量的录屏需求日益增长。无论是课程内容的留存、游戏高光的记录&#xff0c;还是会议要点的复盘、网课知…

LeetCode算法日记 - Day 20: 两整数之和、只出现一次的数字II

目录 1. 两数之和 1.1 题目解析 1.2 解法 1.3 代码实现 2. 只出现一次的数字II 2.1 题目解析 2.2 解法 2.3 代码实现 1. 两数之和 371. 两整数之和 - 力扣&#xff08;LeetCode&#xff09; 给你两个整数 a 和 b &#xff0c;不使用 运算符 和 - &#xff0c;计算并…

Spring AI 快速接入 DeepSeek 大模型

Spring AI 快速接入 DeepSeek 大模型 文章目录Spring AI 快速接入 DeepSeek 大模型Spring AI 框架概述核心特性适用场景官网与资源AI 提供商与模型类型模型类型&#xff08;Model Type&#xff09;AI提供商&#xff08;Provider&#xff09;两者的关系Spring AI 框架支持哪些 A…

jQuery 知识点复习总览

文章目录jQuery 知识点复习总览一、jQuery 基础1. jQuery 简介2. jQuery 引入3. jQuery 核心函数二、选择器1. 基本选择器2. 层级选择器3. 过滤选择器4. 表单选择器三、DOM 操作1. 内容操作2. 属性操作3. CSS 操作4. 元素操作四、事件处理1. 事件绑定2. 事件对象3. 自定义事件五…

博客系统接口自动化练习

框架图&#xff1a; 详细代码地址&#xff1a;gitee仓库 博客系统接口自动化文档请看文章顶部。

智慧矿山误报率↓83%!陌讯多模态融合算法在矿用设备监控的落地优化

原创声明&#xff1a;本文为原创技术解析文章&#xff0c;核心技术参数与架构设计引用自 “陌讯技术白皮书&#xff08;智慧矿山专项版&#xff09;”&#xff0c;算法部署相关资源适配参考aishop.mosisson.com平台的陌讯视觉算法专项适配包&#xff0c;禁止未经授权的转载与二…

Laravel 使用阿里云OSS S3 协议文件上传

1. 安装 S3 软件包 composer require league/flysystem-aws-s3-v3 "^3.0" --with-all-dependencies2. 配置.env 以阿里云 OSS 地域华东2 上海为例: FILESYSTEM_DISKs3 //设置默认上传到S3AWS_ACCESS_KEY_ID***…

UVM一些不常用的功能

uvm_coreservice_t是什么AI&#xff1a;在 UVM&#xff08;Universal Verification Methodology&#xff09;中&#xff0c;uvm_coreservice_t 是一个核心服务类&#xff0c;它扮演着UVM 框架内部核心服务的 “管理者” 和 “统一入口” 的角色。其主要作用是封装并提供对 UVM …

怎么确定mongodb是不是链接上了?

现有mongosh链接了MongoDB,里面能操作,但是想python进行链接,因为代码需要,现在测试下链接成功了没有。如下: 要确认你的 MongoDB 连接是否成功,可以通过以下方法检查: 1. 使用 list_database_names 方法【测试成功】 python import asyncioasync def test_connecti…

Unity 二进制读写小框架

文章目录前言框架获取与集成使用方法基本配置自动生成序列化方法实战示例技术原理与优势二进制序列化的优势SJBinary的设计特点最佳实践建议适用场景总结前言 在Unity开发过程中&#xff0c;与后台交互时经常需要处理大型数据文件。当遇到一个近2MB的本地JSON文件需要解析为对…