数据结构——用Java实现数组

一、什么是数据结构?

概念:

数据结构是一门基础的学科,是研究数据如何在计算机中进行组织和存储,使得我们可以高效的获取数据和修改数据的。

数据结构可以分为三类:

1.线性结构:数组、队列、栈、链表、哈希表…

2.树形结构:二叉树、二分搜索树、AVL树,红黑树、堆、Trie、线段树、并查集…

3.图结构:邻接矩阵、邻接表

为什么要学习数据结构?

好的程序是数据结构+算法来实现的:数据结构+算法=程序

在遇到不同的问题时,选择对应的数据结构方法,能更快更好的进行解决。

学习数据结构还可以锻炼我们的代码和思维能力。

二、数组

1.数组基础

  • 数组是用来存储一组类型相同的数据的集合
  • 在内存中,分配连续的空间,数组创建时要指定容量(大小)
  • 数据类型[] 数组名 int[] arr = new int[10] int[] arr2 = {1,2,3,4}
  • 索引---访问数组时通过索引进行操作 索引从0开始,最大为 arr.length -1
  • 常见的错误: NullPointException ArrayIndexOutOfBoundsException
  • 常见的数组: 字符串, 对象数组,哈希表

使用数组时,最重要的就是数组的索引,通过索引可以对数组进行改和查操作。

数组最大的优点:快速查询。

数组最好应用于索引有语义的情况。例如:通过学生学号进行查询等

2.向数组中添加元素

public void add(int item) {//this.size 指向的是待插入元素的位置this.data[this.size] = item;this.size++;}

3.向指定位置添加元素

public void addInIndex(int index, int val) {if (index < 0 || index > this.size) {throw new IllegalArgumentException("index is invalid.");}//从index位置开始元素需要进行后移for (int i = this.size - 1; i >= index; i--) {this.data[i + 1] = this.data[i];}this.data[index] = val;//更新this.sizethis.size++;}

有了向指定位置添加元素的方法后,就可以修改上面所写的尾部添加元素的方法:

public void add(int item) {//this.size 指向的是待插入元素的位置addInIndex(this.size, item);}

也可以写一个头部添加的方法:

 public void addHead(int item) {addInIndex(0, item);}

4.获取指定位置的元素和修改指定位置的元素

//修改指定位置的值public void modifyValueByIndex(int index, int value) {//入参一定要判断if (index < 0 || index >= this.size) {throw new IllegalArgumentException("index is invalid.");}this.data[index] = value;}//获取指定位置的值public int getValueByIndex(int index) {if (index < 0 || index >= this.size) {throw new IllegalArgumentException("index is invalid.");}return this.data[index];}

5.包含、搜索和删除元素

//查询指定的值在数组中是否存在,如查存在,获取索引,否则返回-1public int containsValue(int val) {//遍历数组for (int i = 0; i < this.size; i++) {if (val.equals(this.data[i])) {return i;}}return -1;}//删除操作public int removeByIndex(int index) {if (index < 0 || index >= this.size) {throw new IllegalArgumentException("index is invalid.");}//删除操作的核心/*1.找到删除的位置2.删除位置之后的元素要前移 arr[j-1]=arr[j]*/int delValue = this.data[index];for (int i = index + 1; i < this.size; i++) {this.data[i - 1] = this.data[i];}this.size--;return delValue;}

6.打印数组

打印数组前提是重写toString方法:

 @Overridepublic String toString() {StringBuilder sb = new StringBuilder("[");for (int i = 0; i < this.size; i++) {sb.append(this.data[i]);if (i != this.size - 1) {sb.append(",");}}sb.append("]");return sb.toString();}

然后写主函数,对所写的数组的方法进行调用和输出:

 public static void main(String[] args) {Random random = new Random();//向数组中添加元素for (int i = 0; i < 10; i++) {myArr.add(random.nextInt(100));}//遍历数组System.out.println(myArr.toString());//查询//1.索引为2的位置值是多少int result = myArr.getValueByIndex(2);System.out.println("index=2,value=" + result);//2.获取值为57的元素的索引int index = myArr.containsValue(57);System.out.println("57元素的索引是" + index);//删除值为57的元素if (index != -1) {result = myArr.removeByIndex(index);System.out.println(result);}System.out.println(myArr);//向数组中指定位置添加元素(3,99)myArr.addInIndex(3, 99);System.out.println(myArr);}

7.出现的问题和解决方法:

  1. 向数组中继续添加一个元素,就会出错(解决方法:扩容)
  2. 删除元素后,空间利用率低--(解决办法:缩容)
  3. 现在只能处理int类型,如何处理多种类型--(解决办法:泛型)

新增了一个改变容积的方法

//向数组中指定位置添加元素public void addInIndex(int index, int val) {if (index < 0 || index > this.size) {throw new IllegalArgumentException("index is invalid.");}//判断数组是否满if (this.size == this.capacity) {//扩容resize(this.capacity * 2);}//从index位置开始元素需要进行后移for (int i = this.size - 1; i >= index; i--) {this.data[i + 1] = this.data[i];}this.data[index] = val;//更新this.sizethis.size++;}private void resize(int newCapacity) {System.out.println("resize:" + newCapacity);T[] newData = (T[]) (new Object[newCapacity]);//将原数组驾到新数组里for (int i = 0; i < this.size; i++) {newData[i] = this.data[i];}//改变容器this.data = newData;this.capacity = newCapacity;}

既然扩容可以,当然也可以进行缩容:

 //删除操作public int removeByIndex(int index) {if (index < 0 || index >= this.size) {throw new IllegalArgumentException("index is invalid.");}//删除操作的核心/*1.找到删除的位置2.删除位置之后的元素要前移 arr[j-1]=arr[j]*/T delValue = this.data[index];for (int i = index + 1; i < this.size; i++) {this.data[i - 1] = this.data[i];}this.size--;//判断是否缩容if (this.size < this.capacity / 2 && this.capacity / 2 > 0) {resize(this.capacity / 2);}return delValue;}

注意:这样缩容会出现一个问题:复杂度的震荡

复杂度震荡:

以本次的数组为例,在删除一定的元素,打到缩容的条件,进行缩容,但是下一步如果添加元素的话,又要进行扩容,时间复杂度就会增加,这就是复杂度的震荡

如何解决:

 //判断是否缩容if (this.size < this.capacity / 4 && this.capacity / 2 > 0) {resize(this.capacity / 2);}return delValue;}

缩容条件改为容积的1/4,这样留有空间进行添加元素,实在是不需要的情况下,再进行缩容。

处理多种类型的方法就是添加泛型:泛型 把类型当做参数

完整代码:

package com.algo.lesson.lesson01;import java.util.Random;/*
基于Java中的数组进行二次封装,制作一个可变数组*/
//泛型:就是类型作为参数
public class MyArr<T> {private T[] data;//保存数据private int size;//数组中实际存放元素的个数int capacity;//容积//构造函数public MyArr(int capacity) {if (capacity <= 0) {this.capacity = 10;} else {this.capacity = capacity;}this.size = 0;this.data = (T[]) (new Object[this.capacity]);}//获取数组中实际存放元素的个数public int getSize() {return this.size;}//获取数组的容积public int getCapacity() {return this.capacity;}//判断数组是否为空public boolean isEmpty() {return this.size == 0;}//向数组中添加元素(尾部)public void add(T item) {//this.size 指向的是待插入元素的位置addInIndex(this.size, item);}//向数组中添加元素(头部)public void addHead(T item) {addInIndex(0, item);}//向数组中指定位置添加元素public void addInIndex(int index, T val) {if (index < 0 || index > this.size) {throw new IllegalArgumentException("index is invalid.");}//判断数组是否满if (this.size == this.capacity) {//扩容resize(this.capacity * 2);}//从index位置开始元素需要进行后移for (int i = this.size - 1; i >= index; i--) {this.data[i + 1] = this.data[i];}this.data[index] = val;//更新this.sizethis.size++;}private void resize(int newCapacity) {System.out.println("resize:" + newCapacity);T[] newData = (T[]) (new Object[newCapacity]);//将原数组驾到新数组里for (int i = 0; i < this.size; i++) {newData[i] = this.data[i];}//改变容器this.data = newData;this.capacity = newCapacity;}//修改指定位置的值public void modifyValueByIndex(int index, T value) {//入参一定要判断if (index < 0 || index >= this.size) {throw new IllegalArgumentException("index is invalid.");}this.data[index] = value;}//获取指定位置的值public T getValueByIndex(int index) {if (index < 0 || index >= this.size) {throw new IllegalArgumentException("index is invalid.");}return this.data[index];}//查询指定的值在数组中是否存在,如查存在,获取索引,否则返回-1public int containsValue(T val) {//遍历数组for (int i = 0; i < this.size; i++) {if (val.equals(this.data[i])) {return i;}}return -1;}//删除操作public T removeByIndex(int index) {if (index < 0 || index >= this.size) {throw new IllegalArgumentException("index is invalid.");}//删除操作的核心/*1.找到删除的位置2.删除位置之后的元素要前移 arr[j-1]=arr[j]*/T delValue = this.data[index];for (int i = index + 1; i < this.size; i++) {this.data[i - 1] = this.data[i];}this.size--;//判断是否缩容if (this.size < this.capacity / 4 && this.capacity / 2 > 0) {resize(this.capacity / 2);}return delValue;}@Overridepublic String toString() {StringBuilder sb = new StringBuilder("[");for (int i = 0; i < this.size; i++) {sb.append(this.data[i]);if (i != this.size - 1) {sb.append(",");}}sb.append("]");return sb.toString();}public static void main(String[] args) {MyArr<Integer> myArr = new MyArr<>(10);Random random = new Random();//向数组中添加元素for (int i = 0; i < 10; i++) {myArr.add(random.nextInt(100));}//遍历数组System.out.println(myArr.toString());//查询//1.索引为2的位置值是多少int result = myArr.getValueByIndex(2);System.out.println("index=2,value=" + result);//2.获取值为57的元素的索引int index = myArr.containsValue(57);System.out.println("57元素的索引是" + index);//删除值为57的元素if (index != -1) {result = myArr.removeByIndex(index);System.out.println(result);}System.out.println(myArr);//向数组中指定位置添加元素(3,99)myArr.addInIndex(3, 99);System.out.println(myArr);/*1.向数组中继续添加一个元素,就会出错(解决方法:扩容)2.现在只能处理int类型,如何处理多种类型--(解决办法:泛型)3.删除元素后,空间利用率低--(解决办法:缩容)*/}}

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

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

相关文章

运筹说 第104期 | 2023全球高被引科学家名单发布!

2023年11月15日&#xff0c;全球领先的专业信息服务提供商科睿唯安发布2023年度“全球高被引科学家”名单&#xff0c;遴选全球高校、研究机构和商业组织中对所在研究领域具有重大和广泛影响的顶尖科学人才。最终&#xff0c;来自全球67个国家和地区1300多个机构的6849名科学家…

第二百六十四回

文章目录 概念介绍使用方法示例代码 我们在上一章回中介绍了SliverPadding组件相关的内容&#xff0c;本章回中将介绍Sliver综合示例.闲话休提&#xff0c;让我们一起Talk Flutter吧。 概念介绍 我们在前面的章回中介绍了各种Sliver相关的组件&#xff1a;SliverList,SliverGr…

linux配置DNS主从服务器

实验设备 主服务器:OpenElur Linux IP地址为192.168.188.129 从服务器:RedHat Linux IP地址为192.168.188.128 实验步骤 1.进行主服务器的基础配置 #安装DNS对应工具 [rootlocalhost ~]# yum install bind -y#编辑DNS系统配置信息 [rootlocalhost ~]# vim /etc/named.conf…

【算法题】55. 跳跃游戏

题目 给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff…

Node cool 跨域问题的解决

1.问题 自己在写后端接口的时候 发现一个接口在抖音小程序上可以调用 浏览器上也可以直接打开 但是在H5 的请求中 一直就是cors error 前端报这个跨域问题 在后端 报not Found 一开始以为是找不到 经过确定 发现是跨域问题 2.解决 在全局 configuration.ts 文件里有个全局…

申请开启|成为亚马逊云科技 Community Builder,共建云端社区!

在探索由技术打造的云端世界时&#xff0c;和同行者一起学习&#xff0c;与技术专家共同探讨是开发者成长的最佳助力&#xff01; 亚马逊云科技开发者社区 Community Builders 为技术爱好者和新兴思想领袖提供技术资源、学习和交流机会&#xff0c;帮助开发者探索、分享技术相关…

详解SpringCloud微服务技术栈:Gateway网关(断言、过滤器、跨域问题)

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;详解SpringCloud微服务技术栈&#xff1a;Feign远程调用、最佳实践、错误排查 &#x1f4da;订阅专栏&#xff1a;微服务技术全家…

学习记录1.13

闭包&#xff1a; 可以访问外部函数的变量&#xff0c;在内层函数中访问到外层函数的作用域. 她可以创建私有变量&#xff0c;延长变量的生命周期。 function father() { Var name “baiyun”; function son() { Console.log(name,”name”); } son() } father(); 柯里…

用springboot mybatis写一个增删改查

首先&#xff0c;在pom.xml文件中添加Spring Boot、MyBatis和MySQL的相关依赖&#xff1a; <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency&g…

PuTTY的ppk密钥与OpenSSH密钥之间的相互转换

几个概念说明&#xff1a;id_rsa、id_rsa.pub、ppk、pem 目前有两个主流的密钥格式&#xff1a;OpenSSH格式的密钥 和 PuTTY格式的密钥。 id_rsa和id_rsa.pub 都是OpenSSH格式的密钥。 id_rsa是OpenSSH格式的SSH私钥。 id_rsa.pub是OpenSSH格式的SSH公钥。ppk文件 ppk文件是P…

c++基础2

一、c的引用 引用和指针的的区别&#xff1f; 引用是一种更安全的指针&#xff1a; 1. 引用必须初始化&#xff0c;指针可以不用初始化 int a 10; int *p; // 指针可能是野指针 int &b a;//引用赋值"&#xff0c;通常指的是直接修改引用所引用的对象的值&#xff0…

【每日随笔】远离美女 ② ( 各个时代的择偶需求 | 美女的社交溢价 | 颜值保质期 )

文章目录 一、各个时代的择偶需求1、原始社会择偶需求2、古代社会择偶需求3、现代社会择偶需求 二、美女的社交溢价与颜值保质期1、美女的社交溢价2、颜值保质期 一、各个时代的择偶需求 1、原始社会择偶需求 在之前提到过 , 美女 基因稳定 , 原始社会 婴儿 夭折率太高 , 只有…

JavaScript之视频相关API

目录 一、视频标签基本API1. play(开始)2.muted(静音)3. pause(暂停)4. volume(声音控制)5. webkitRequestFullScreen(全屏) 二、视频标签进度条API1. 总时间API&#xff08;duration&#xff09;2.当前时间API&#xff08;currentTime&#xff09; 二、进度条拉动效果 一、视频…

Qt/QML编程之路:小键盘keyboard(36)

小键盘对于qml应用是经常用到的,在qml里面,就如一个fileDialog也要自己画一样,小键盘keyboard也是要自己画的,对于相应的每个按键的clicked都要一一实现的。 这里有一个示例: 代码如下: import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Window 2.0 im…

yum仓库以及NFS共享

yum实现过程 1.光驱里自带yum 2.网络下载到本地 3.直接通过网络 如何实现安装服务 yum客户端找到yum服务端&#xff0c;找到yum的仓库位置&#xff0c;下载元信息&#xff0c;因为里面有软件的位置&#xff0c;因此可以找到软件包的位置&#xff0c;然后下载到本地 仓库的类…

25考研英语复习计划

Hello各位小伙伴大家好&#xff0c;今天要给大家分享的是英语备考计划&#xff0c;大家可以作为参考&#xff0c;制定适合自己的备考计划。 【英一/二】 英语分为英一、英二&#xff0c;一般学硕英一&#xff0c;专硕英二。 英一要比英二难度大。 【复习计划】 1-2月&#xf…

图深度网络浅层理解

图神经网络 1.输入&#xff1a; 图网络 2.输出&#xff1a; 节点类别、某两个节点的新连接、产生新的图或子图 3.端到端表示学习&#xff08;Representation Learning&#xff09;/图嵌入&#xff1a; 将节点映射为d维的向量&#xff0c;d维向量就包含了这个节点的连接关系…

H5小游戏如何提升APP变现收益?

在当前用户规模稳定但变现压力增加的背景下&#xff0c;开发者需要挖掘用户价值&#xff0c;提高营收&#xff0c;这成为开发者关注的重点话题。对于那些“用户用完即走”的APP产品来说&#xff0c;接入H5游戏能够吸引停留&#xff0c;为其带来收入上的增长。 一、什么是H5游戏…

小程序学习-17

attached最常用 推荐使用 lilfetimes 这种方法