package com.learn.datastructure;/*** 线性接口表* 我怎么觉得这些方法我们都学过,* 是不是都学过,大同小异,* 注意这是一个接口,和存储结构无关* 无论是顺序表还是链表,都要把这些功能给我实现,* 首先我们来讲顺序表啦,* @author Leon.Sun**/
public interface List {// 返回线性表的大小,即数据元素的个数。/*** 线性表里又几个元素* @return*/public int size();// 返回线性表中序号为 i 的数据元素/*** 获取第i个元素* @param i* @return*/public Object get(int i);// 如果线性表为空返回 true,否则返回 false。/*** 线性表是不是空的,* @return*/public boolean isEmpty();// 判断线性表是否包含数据元素 e/*** 线性表是不是包括某个元素* 是不是查找* @param e* @return*/public boolean contains(Object e);// 返回数据元素 e 在线性表中的序号/*** 某个元素在线性表的索引* @param e* @return*/public int indexOf(Object e);// 将数据元素 e 插入到线性表中 i 号位置/*** 添加* 这是加到指定位置,线性表的插入操作* @param i* @param e*/public void add(int i, Object e);// 将数据元素 e 插入到线性表末尾/*** 这两个添加有什么区别,* 这是加到最后,又插入就有添加* @param e*/public void add(Object e);// 将数据元素 e 插入到元素 obj 之前/*** 在谁谁之前加* @param obj* @param e* @return*/public boolean addBefore(Object obj, Object e);// 将数据元素 e 插入到元素 obj 之后/*** 在谁谁之后加* 这个大家自己都可以来写* @param obj* @param e* @return*/public boolean addAfter(Object obj, Object e);// 删除线性表中序号为 i 的元素,并返回之/*** 删除第几个,这是删除第几个元素* 比如我删除第5个元素* @param i* @return*/public Object remove(int i);// 删除线性表中第一个与 e 相同的元素/*** 删除指定值的元素* 比如我删除值是30的元素* @param e* @return*/public boolean remove(Object e);// 替换线性表中序号为 i 的数据元素为 e,返回原数据元素/*** 修改,把第几个元素改成新的值* @param i* @param e* @return*/public Object replace(int i, Object e);}
package com.learn.datastructure;import java.util.Arrays;/*** 现在这个代码有没有缺点,有* * 这里头有两个属性,一个是elementData,一个是size* * 我们只写了添加,那删除的时候呢,那更新的时候呢,他不用扩容,* 他只要后移前移,删除的话前移就可以了,不要扩容,* @author Leon.Sun**/
public class ArrayList implements List {private Object[] elementData;private int size;/*** 构造方法,默认长度是4,JAVA的源码默认是0*/public ArrayList() {this(4);        // elementData = new Object[] {};}/*** 可以指定默认长度* @param initialCapacity*/public ArrayList(int initialCapacity) {/*** 这一个给他赋值了,给他分配了4个空间,*/elementData = new Object[initialCapacity];// size = 0;}/*** 获取元素个数都非常的简单*/@Overridepublic int size() {return size;}/*** 我们也简单的模拟了获取第i个 元素* 当然要考虑完整的话,就考虑到越界了* 我们还自定义了一个异常*/@Overridepublic Object get(int i) {
//      if(i<0 || i>=size) {
//          throw new RuntimeException("数组索引越界异常:" + i);
//      }if(i<0 || i>=size) {throw new MyArrayIndexOutOfBoundsException("数组索引越界异常:" + i);}return elementData[i];}/*** 判断是否为空*/@Overridepublic boolean isEmpty() {return size==0;}@Overridepublic boolean contains(Object e) {return false;}@Overridepublic int indexOf(Object e) {return 0;}/*** 数组满了要扩容这段代码还是要有,这是我们讲的数组一个扩容的原理*/@Overridepublic void add(int i, Object e) {/*** 要是想更严谨一些,i加到最后就是size,* 判断一下,i的位置要正确,* 如果i小于0,或者大于size*/if(i<0 || i>size) {/*** 把我们自定义的数组再写一下* 索引就是i*/throw new MyArrayIndexOutOfBoundsException("数组指针越界异常!" + i);}/*** 首先数组满了就要先扩容,扩容之后才考虑添加的问题,*/if(size==elementData.length) {grow();}/*** 假如在678这个位置要添加一个666,首先把678后面的元素都往后移一个位置* 然后空出678这个位置,把666放进去,移动的首先从最后一个位置往后移动* 不能直接移动678,因为直接移动是把678后面一个元素直接覆盖了,不可以的,* 后移元素,从最后一个元素开始,后面i后面的元素,并从最后一个元素开始* */      for(int j=size;j>i;j--) {elementData[j] = elementData[j-1];}/*** 给数组的第i个位置赋值*/elementData[i] = e;size++;}/*** 做这个操作是有前提的* * 这个add只是往最后加的*/@Overridepublic void add(Object e) {/*** 这个添加到最后是添加到指定位置的特殊情况,* 加到最后就是加到size,*/this.add(size, e);/*** 如果数组满了,就扩容就可以了*/
//      if(size==elementData.length) {
//          /**
//           * 新创建一个新的数组,长度是旧数组的2倍,
//           * 写elementData.length这个更容易理解
//           */
//          Object[] newArr = new Object[elementData.length*2];
//          /**
//           * 将旧数组的数据拷贝到新数组,
//           */
//          for(int i=0;i<size;i++) {
//              newArr[i] = elementData[i];
//          }
//          /**
//           * 这个时候elementData还是指向原来的数组,这样添加元素还是往旧数组里面添加,
//           * 这个时候堆里面的对象不能再指向旧数组地址0X2012,应该写0X3012了,
//           * 这样就指向了新数组0X3012了,这个时候就会往新数组的后面添加了,这个时候就是把栈里的newArr变量
//           * 指向堆里的地址,这个就是一个赋值语句,让elementData指向新数组,
//           * newArr的赋给elementData
//           *
//           * 我们这里一共写了三条语句,实际上这一条语句用一条语句就可以搞定了,
//           */
//          elementData = newArr;/*** 旧数组是谁,旧数组是elementData* 新数组长度是多少newLength,然后在赋值给elementData* 把旧的数组扩容到原来的2倍,让旧的引用指向它,扩容并复制,然后再指向,只要这一条语句就够了* 我们是扩了一倍,我们看一下真正的ArrayList是扩了多少呢,* JDK里面的int newCapacity = oldCapacity + (oldCapacity >> 1);* JDK是每次增长50%,java.util.ArrayList每次增长50%,* 增长50%是比较合适的,增加1倍可能会导致浪费,*/// elementData = Arrays.copyOf(elementData, elementData.length*2);/*** 越来越像真正的ArrayList*/
//          grow();
//      }/*** 我们每次都输出一下数组的长度,我要看一下这个length等于几* 每次添加都会输出*/
//      System.out.println("length="+elementData.length);//     elementData[size] = e;
//
//      size++;// elementData[size++] = e;}/*** JDK里面的是叫grow*/private void grow() {elementData = Arrays.copyOf(elementData, elementData.length*2);}@Overridepublic boolean addBefore(Object obj, Object e) {return false;}@Overridepublic boolean addAfter(Object obj, Object e) {return false;}@Overridepublic Object remove(int i) {return null;}@Overridepublic boolean remove(Object e) {return false;}@Overridepublic Object replace(int i, Object e) {return null;}/*** 我们要产生[123,321,456,678,....]这个结构* */@Overridepublic String toString() {/*** 如果长度等于0,你还那么费劲干嘛* 如果size等于0,一个元素也没有*/if(size==0) {return "[]";}/*** 创建一个StringBuilder,因为它便于追加* 这个应该有一个初始值"["*/StringBuilder builder = new StringBuilder("[");/*** 开始循环了*/for(int i=0;i<size;i++) {builder.append(elementData[i]);if(i!=size-1) {builder.append(",");}}/*** 他应该有个结尾的值*/builder.append("]");return builder.toString();}}
package com.learn.datastructure;/*** 他们在内存里面是怎么实现的,首先画一个栈内存,然后要画一个堆内存* * @author Leon.Sun**/
public class TestArrayList {public static void main(String[] args) {// java.util.ArrayList list;/*** 当我们执行这行的时候,我们new ArrayList,* 在堆里面创建了一个对象,这里面有两个属性,* 第一个属性是elementData,第二个属性是size,* elementData这个初始值是null,size这个初始值是0,* 我们这个对象在堆里的地址是0X1012,当我们执行这个无参构造方法的时候是空的* 里面调用了this(4),在这里面分配了连续的空间,4个空间,这个地址叫0X2012,* 我们熟练以后就不用写这个地址了,你看他就这么指向了,结果这个数组就不为空,* 就指向了这个数组,然后我们在栈里开辟一个空间,main方法在栈里面,里面定义一个变量,* 这个变量叫list,他的值是0X1012,栈里面的list变量指向堆里面的0X1012,* 堆里面创建了一个对象指向了堆里面的一个数组,当然目前这个数组里面都是有值的,* 初始值是null,因为是Object,对象都是null,我加123,456,678,什么意思,* 我们看一下add里面的代码,size是0,先把123加到这儿,把123压到数组0这个位置* size++这样size就变成1了,当我们加789的时候行不行,不行了,为什么这个时候不行了,* 因为这个数组已经满了,下面就要扩容了,扩容的条件是什么,数组满了,你怎么知道数组满了,* 就是size等于elementData.length,这就满了,下面一个如何扩容,扩容的策略,* 4个不够了,下次变成6个,还是8个,还是100个,总得有一个特点吧,比如增长一倍,那就是4变成8,* 还有增长一半,就是4个变6个了,扩容的步骤,不可以在原来的数组后面直接加2个,第一步,我们是调用的add方法* 我们在栈里面分配一个空间,这是add方法,第一步不是四个吗,再创建一个新的数组,这个长度我们就写成8呗,* 给新数组的地址X3012,在栈里面定义一个新的变量newArr,给一个地址0X3012,扩容的第二步复制原来数组* 的内容到新数组,后边还剩下4个,是不是有空间了吗* * 刚才我们添加第5个就报错,现在我们看一下,没报错,长度变成5了,*/List list = new ArrayList();list.add(123);list.add(321);list.add(456);list.add(678);/*** 当我们的元素添加超过4个的时候,马上就报错了* 这个是数组要动态的扩容,这个扩容我们已经看的很清楚了*/list.add(789);list.add(111);list.add(222);list.add(111);/*** 超过8个的时候又会扩容,*/list.add(222);/*** 我在678这个位置要新加一个数* * 我们加到20,我们没有20个元素* 就会报我们自定义的数组异常错误* 核心就是数组的一个扩容* 包括元素的前移和后移* 我们扩展了自定义异常,还有一些方法的提取* 然后结合了ArrayList真正的源码来写的* 对ArrayList底层的原理有一个掌握了*/list.add(20, 666);System.out.println(list.size());System.out.println(list.isEmpty());System.out.println(list.get(2));System.out.println(list.get(0));/*** 这个8我们先改成3*/System.out.println(list.get(3));/*** 输出一下list,因为你直接调用list相当于直接调用toString* 我想把所有的元素都输出出来,按照顺序,没有重写它的toString方法* */System.out.println(list);}   }
package com.learn.datastructure;/*** 这个叫自定义异常,他要继承RuntimeException* 这里面也非常的简单,只要实现两个构造方法,* 我们要一个无参的,和一个带有异常信息的* @author Leon.Sun**/
public class MyArrayIndexOutOfBoundsException extends RuntimeException {public MyArrayIndexOutOfBoundsException() {super();}public MyArrayIndexOutOfBoundsException(String message) {super(message);}}

模拟实现顺序表ArrayList2(三级)相关推荐

  1. java如何给顺序表赋值_JAVA模拟新增顺序表及单链表

    最近在回顾大学学的数据结构,这里给大家用javwww.cppcns.coma模拟顺序表和单链表的新增 1顺序表新增 /** * 顺序www.cppcns.com表 * * @author cjd * ...

  2. 模拟实现顺序表ArrayList1(三级)

    package com.learn.datastructure;/*** 线性接口表* 我怎么觉得这些方法我们都学过,* 是不是都学过,大同小异,* 注意这是一个接口,和存储结构无关* 无论是顺序表还 ...

  3. 【DS】3.顺序表链表万字全总结!

    文章目录 一.关于List 为什么要提List 什么是List List怎么用 二.关于线性表 三.关于顺序表 什么是顺序表 顺序表我们常用的功能: ArrayList的简化模拟实现: 四.Array ...

  4. JAVA顺序表的简单实现

    import java.util.Scanner;class DATA{ //模拟一个班级的学生记录String key;String name;int age;}class SLType{stati ...

  5. 顺序表应用8:最大子段和之动态规划法

    Description 给定n(1<=n<=100000)个整数(可能为负数)组成的序列a[1],a[2],a[3],-,a[n],求该序列如a[i]+a[i+1]+-+a[j]的子段和的 ...

  6. C语言用数组(顺序表)实现大小固定的队列的方法

    顺序队列,即采用顺序表模拟实现的队列结构. 我们知道,队列具有以下两个特点: 1.数据从队列的一端进,另一端出: 2.数据的入队和出队遵循"先进先出"的原则: 因此,只要使用顺序表 ...

  7. 【JAVA】顺序表与ArrayList

    顺序表与ArrayList 顺序表与ArrayList 一.线性表 二.顺序表 接口的实现 三.ArrayList简介 四.ArrayList使用 1. ArrayList的构造 2. ArrayLi ...

  8. 【数据结构】顺序表和链表的优缺点

    1.顺序表 优点: 1.物理空间是连续的,方便使用下标随机访问. 缺点: 1.由于需要物理空间连续,空间不够需要扩容.扩容本身有一定消耗,其次扩容机制还存在一定的空间浪费. 2.头部或者中部的插入.删 ...

  9. Java数据结构(1.1):数据结构入门+线性表、算法时间复杂度与空间复杂度、线性表、顺序表、单双链表实现、Java线性表、栈、队列、Java栈与队列。

    数据结构与算法入门 问题1:为什么要学习数据结构          如果说学习语文的最终目的是写小说的话,那么能不能在识字.组词.造句后就直接写小说了,肯定是不行的, 中间还有一个必经的阶段:就是写作 ...

最新文章

  1. SAP HUM 如何查询一个HU号码是否被软分配给了某个销售订单 ?
  2. 教你怎么修改个性开机画面
  3. MassTransit Get Started-
  4. [css] 用CSS实现tab切换
  5. LintCode: Search A 2d Matrix
  6. c语言文件压缩与解压缩实验报告,哈弗曼树的文件压缩和解压实验报告(C语言).doc...
  7. 使用javafx百行代码搞定多边形面积计算(可下载)
  8. 读者写者问题详解 操作系统
  9. python关闭对象语法_用Python打开和关闭文件
  10. 智能一代云平台(四十二):关于异常的一些事
  11. Mac 常用快捷键与操作
  12. 【机器学习】基础之线性代数(超详细总结)
  13. Linux 档案属性与目录配置
  14. 升级数据库增加字段之OrmLite
  15. 树莓派编译安装完整版本ROS
  16. [Codeforces757E]Bash Plays with Functions数学
  17. 通过 api 和 keycloak 理解OIDC认证
  18. 高德地图基础教程超详细版
  19. 2019-11-29-win10-UWP-Controls-by-function
  20. Android-Application被回收引发空指针异常分析(消灭全局变量)

热门文章

  1. WCF 客户端调用服务操作的两种方法
  2. i2c--ioctl--主机控制器驱动(i2c_adapter)--外设驱动(i2c_driver)
  3. Java过滤掉map集合中key或value为空的值
  4. 【Spring学习】spring注解自动注入bean
  5. imx8m开发板资料
  6. AJAX(Asynchronous JavaScript And XML)
  7. 使用kotlin遇到的问题
  8. “爸爸,什么是机器学习呀?”
  9. 基于httpd建立私有CA实现https加密连接
  10. SharePoint designer 文件--新建中没有工作流