【数据结构与算法-java实现】三 Java数组类实现
- 上一篇文章学习了:最好、最坏、平均、均摊时间复杂度的计算与分析方法.
- 本片文章学习数组这种结构。由于数组这种结构比较简单,本文直接简单介绍,然后给出两种实现数组类的Java代码:整形数组类与通用性的数组类
由于数组是相比于其他数据结构实在太简单,这里我们只做简单的介绍,然后直接给出实现的代码。
文章目录
- 1 数组的概念
- 1.1 Java中数组的越界访问
- 2 整形数组类的实现
- 3 通用型数组类的实现
- 4 总结
1 数组的概念
数组(Array)是一种线性表数据结构。它用一组连续的内存空,来存储一组具有相同类型的数据。对于线性表和非线性表这里不再多说。
我们要注意数组它是连续的内存空间和相同的数据类型。
还有一点就是我们要明白数组是如何做到根据下标来访问数组的元素的。我们拿一个长度为10的int类型的数组int[] a=new int[10];来说明。如下图是申请内存后数组元素的存储方式。
假设上述数组的起始地址为1000.当CPU要访问某一个数组的元素时,将会通过下面的公式进行访问元素:
a[i]_address = base_address + i * data_type_size
其中,base_address 为数组的起始地址。data_type_size为数组元素的类型的大小。
计算机就是通过上述的公式进行数组的随机访问的。不像链表等非线性结构,无法随机访问元素。
- 数组这种结构,虽然具有随机访问的高效性,但是它的插入和删除确实非常的低效。
- 以及数组的访问也是很容易越界的
以上插入和删除的低效,这里不再赘述。
我们注意一下数组访问的越界。
1.1 Java中数组的越界访问
在讲述Java中数组的越界访问之前,先来看一下C语言的越界访问。如下代码:
int main(int argc, char* argv[]){int i = 0;int arr[3] = {0};for(; i<=3; i++){arr[i] = 0;printf("hello world\n");}return 0;
}
上述代码运行后,并非是打印3次hello world,而是无限次的打印hello world。这是为什么?
数组arr的大小是3,但是上面的for循环由于书写错误,访问了arr[3],这就是越界访问。在C语言中,只要不是访问内存受限的地方,所有的内存都是可以访问的。所以由上面的数组访问的公式,a[3]也被定位到一块内存上,而这块内存中存储的刚好是局部变量i。那么arr[3]实际上就是i,这就导致此时又将i赋值为0。此时回到for循环发现i是0,继续循环。。。。。
数组越界在C语言中是一种未决行为,并没有规定数组越界访问时应该如何处理。因为数组访问的本质是访问一段连续的内存,只要数组通过偏移计算得到的内存是可用的,那么程序就可能不会报任何错误。C语言中这种行为,很难debug到错误。
但是不像c语言,Java语言不允许这种越界访问。Java编译器会做越界检查,如果有越界访问,将会抛出异常。如:java.lang.ArrayIndexOutOfBoundsException。
2 整形数组类的实现
由于数组比较简单,上面的内容我觉的就够了。下面直接给出int数组类的实现。可以直接在eclipse编译运行的代码。代码如下:
- Array.java
package Array;/*** 1) 数组的插入、删除、按照下标随机访问操作;* 2)数组中的数据是int类型的;**/public class Array {//定义整形数据保存数据public int data[];//数组的长度private int len;//数组中的实际个数private int cnt;//构造方法,定义数组大小public Array(int capacity) {this.data=new int[capacity];this.len=capacity;this.cnt=0;//一开始一个数据都诶呦,所以为0}//根据索引找到数组中的元素并返回public int find(int index) {if(index<0 || index>=len)return -1;return data[index];}//插入元素,包括头部插入,尾部插入,中间插入public boolean insert(int index, int value) {//数组空间已满if(cnt==len) {System.out.println("数组空间已满,无法插入!");return false;}//插入位置不合法if(index<0 || index>=len) {System.out.println("插入位置不合法!");return false;}//位置合法for(int i=cnt;i>index;--i) {data[i]=data[i-1];}data[index]=value;++cnt;return true;}//根据索引,删除数组中的元素public boolean delete(int index) {if(index<0 || index>=len)return false;//从删除的位置开始,将后面的元素向前移动一位for(int i=index+1;i<len;i++) {data[i-1]=data[i];}--cnt;return true;}public void printAll() {for(int i=0;i<len;i++) {System.out.print(data[i]+" ");}System.out.println();}public static void main(String args[]) {Array array = new Array(5);array.printAll();array.insert(0,3);array.insert(0, 4);array.insert(1, 5);array.insert(2, 2);array.insert(3, 6);array.insert(4, 8);array.printAll();}
}
- 运行结果如下:
以上代码只实现了数组类的插入和删除。更多的方法在下面的通用性数组的实现里面。
3 通用型数组类的实现
下面是实现通用的数组类,也就是大家所知的泛型。C++中叫做模板。
下面的代码已经经过测试,是可以正常使用的。如果你发现有其他bug,请在下方留言评论。
代码如下:
- GenericArray.java
package Array;//这个可能你的不一样public class GenericArray<T>{private T[] data;private int size;//构造函数public GenericArray(int capacity) {data = (T[])new Object[capacity];size=0;}//无参构造方法,默认数组容量为10public GenericArray() {this(10);}//获取数组容量public int getCapacity() {return data.length;}//获取当前元素个数public int count() {return size;}//判断数组是否为空public boolean isEmpty() {return size==0;}//修改index位置的元素public void set(int index, T e) {checkIndex(index);data[index]=e;}//获取对应index位置的元素public T get(int index) {checkIndex(index);return data[index];}//查看数组是否包含元素public boolean contains(T e) {for(int i=0;i<this.size;++i) {if(data[i].equals(e))return true;}return false;}//获取对应元素的下标,未找到则返回-1public int find(T e) {for(int i=0;i<this.size;++i) {if(data[i].equals(e))return i;}return -1;}//在index位置插入元素e,时间复杂度是O(m+n)public void add(int index, T e) {checkIndex(index);//如果当前元素的个数等于数组的容量,则将数组扩容为原来的两倍if(size==data.length) {resize(2*data.length);}for(int i=size-1;i>=index;--i) {data[i+1]=data[i];}data[index]=e;size++;}//向数组头插入元素public void addFirst(T e) {add(0, e);}//向数组尾插入元素public void addLast(T e) {add(size, e);}// 删除index位置的元素并返回public T remove(int index) {chaeckIndexForRemove(index);T ret =data[index];for(int i=index+1;i<size;++i) {data[i-1]=data[i];}--size;data[size]=null;//缩小数组容量if(size == (data.length/4) && (data.length/2)!=0) {resize(data.length/2);}return ret;}//删除第一个元素public T removeFirst() {return remove(0);}//删除末尾元素public T removeLast() {return remove(size-1);}//从数组中删除指定的元素public void removeElement(T e) {int index=find(e);if(index!=-1) {remove(index);}}@Overridepublic String toString() {StringBuilder builder = new StringBuilder();builder.append(String.format("Array size = %d, capacity = %d \n", size, data.length));builder.append('[');for (int i = 0; i < size; i++) {builder.append(data[i]);if (i != size - 1) {builder.append(", ");}}builder.append(']');return builder.toString();}private void chaeckIndexForRemove(int index) {// TODO Auto-generated method stubif(index < 0 || index >= size) {throw new IllegalArgumentException("remove failed! Require index >=0 and index < size.");}}//扩容方法,时间复杂度O(n)private void resize(int capacity) {// TODO Auto-generated method stubT[] newData= (T[])new Object[capacity];for(int i=0;i<size;++i) {newData[i]=data[i];}data=newData;}private void checkIndex(int index) {// TODO Auto-generated method stubif(index<0 || index>size) {throw new IllegalArgumentException("Add failed! Require index >=0 and index <= size.");}}//测试用的main,你可以自己写测试函数public static void main(String args[]) {GenericArray<Integer> a = new GenericArray<Integer>(5);a.add(0, 2);a.add(1, 4);a.add(2, 3);a.add(3, 7);a.add(4, 9);for(int i=0;i<a.size;++i) {System.out.print(a.get(i)+" ");}System.out.println();a.remove(1);for(int i=0;i<a.size;++i) {System.out.print(a.get(i)+" ");}a.addFirst(23);System.out.println();for(int i=0;i<a.size;++i) {System.out.print(a.get(i)+" ");}a.addLast(24);System.out.println();for(int i=0;i<a.size;++i) {System.out.print(a.get(i)+" ");}}
}
- 上述代码在eclipse中运行结果如下:
4 总结
- 注意数组的插入删除的效率以及越界访问
学习交流加
- 个人qq: 1126137994
- 个人微信: liu1126137994
- 学习交流资源分享qq群: 962535112
【数据结构与算法-java实现】三 Java数组类实现相关推荐
- 《学习JavaScript数据结构与算法》第三章 数组
文章目录 前言 一.创建 && 初始化数组 二.操作数组 push-添加元素于末尾 unshift-添加元素于开头 pop-从数组末尾开始删除元素 shift-从数组开头开始删除元素 ...
- 【Python数据结构与算法】(三):递归(Recursion)
[Python数据结构与算法](三):递归(Recursion) ✨本文收录于<Python数据结构与算法>专栏,此专栏主要记录如何python学习数据结构与算法笔记.
- Java数据结构和算法(二):数组
上篇博客我们简单介绍了数据结构和算法的概念,对此模糊很正常,后面会慢慢通过具体的实例来介绍.本篇博客我们介绍数据结构的鼻祖--数组,可以说数组几乎能表示一切的数据结构,在每一门编程语言中,数组都是重要 ...
- Java第三章-数组
一.目标 1.数组的基本概念及作用 2.数组的创建 3.数组的访问与迭代 4.数组排序 5.二维数组 二.数组的基本概念及作用 数组的基本概念及作用 • 数组是相同数据类型元素的集合 • 数组本身是引 ...
- Java 数据结构与算法 (尚硅谷Java数据结构与算法)笔记目录
红色的表示重要,绿色的表示暂时还不懂而且很重要 线性结构和非线性结构 队列 顺序队列 循环队列 链表 链表(Linked List)介绍 链表是有序的列表,但是它在内存中是存储如下 小结: 1) 链表 ...
- JavaScript数据结构与算法(1)(数组、栈、队列、链表)(ES6)
注意:原教学视频:JavaScript(ES6)数据结构和算法 | JavaScript数据结构与算法 (都是CoderWhy老师的教学) 原作者(笔记)链接:JavaScript 数据结构与算法 | ...
- 为什么我要放弃javaScript数据结构与算法(第二章)—— 数组
第二章 数组 几乎所有的编程语言都原生支持数组类型,因为数组是最简单的内存数据结构.JavaScript里也有数组类型,虽然它的第一个版本并没有支持数组.本章将深入学习数组数据结构和它的能力. 为什么 ...
- 【数据结构与算法】第三篇:题型积累
系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 TODO:写完再整理 文章目录 系列文章目录 前言 一.刷题的准备与步骤 (1)第一步:先学会至少一种计算机语言.学习数 ...
- 【Java数据结构与算法】第一章 稀疏数组和队列
第一章 稀疏数组和队列 文章目录 第一章 稀疏数组和队列 一.线性结构和非线性结构 1.线性结构 2.非线性结构 二.稀疏数组 三.队列 1.队列 2.环形队列 一.线性结构和非线性结构 1.线性结构 ...
- 【Java数据结构与算法】第三章 双向链表和约瑟夫问题
第三章 第三章 双向链表.环形链表以及约瑟夫问题 文章目录 第三章 第三章 双向链表.环形链表以及约瑟夫问题 一.双向链表 1.双线链表对比单向链表的优点: 2.分析双向链表的遍历.添加.修改和删除的 ...
最新文章
- 如何对以破折号/连字符开头的字符串进行grep?
- UVA 12166 Equilibrium Mobile
- Java实体映射工具MapStruct
- php三种web开发技术,三种WEB开发主流技术ASP-PHP-JSP的评价
- 【观点】微博的弊端和它的真正意义
- 如何在Vue中添加百度统计代码?
- 使用WebService的方式调用部署在服务器的Wcf服务
- 多云时代-着眼布局开源技术之多云数据管理
- md5校验工具hash
- js实现抽饭系统(类似抽检系统)双按钮控制系统
- php进行url转码,对url中的参数进行转码
- 什么是模式识别,模式识别概念的基本介绍
- 电子设计大赛-无线电类题目分析
- 百度世界地图实现方法
- 招行线上笔试java_今天参加了招行科技的在线笔试
- matlab 数组中的一个值,MATLAB数组元素引用的三种方法
- 队爷的讲学计划 (强连通缩点+最短路)
- 关于linux android sdk配置环境
- php5.0 cms安装教程,MySQL_KingCMS5.0从安装到设置使用教程,1.首先到KingCMS官方下载KingCMS5.0 - phpStudy...
- 利用Amber热力学积分计算相对自由能变化
热门文章
- 第九十六期:JavaScript 中的 4 个相等比较算法的介绍
- java学习(82):静态代码块内部类
- java学习(33):巩固练习
- 递归求和的复习-计算m~n整数和
- solor mysql_solr 同步 mysql
- java 盘符 系统_001-Java再回首开篇-入门基础
- vue mint-ui 弹出框
- 20个常用的Python小技巧
- java中文处理_Java的中文乱码处理
- linux 64位 寻址空间_Ubuntu 20.04(64位)如何配置gcc-3.4用于编译linux-0.11