☕目录☕
前言
思维导图
一、线性表
二、顺序表
2.1 实现一个简单的顺序表
2.2 对顺序表的一些相关操作
2.2.1 打印顺序表
2.2.2 新增元素,默认在数组最后新增
2.2.3 在pos位置新增元素
2.2.4 判定是否包含某个元素
2.2.5 查找某个元素对应的位置
2.2.6 获取pos位置的元素
2.2.7 给pos元素的位置设(更新)为value
2.2.8 删除第一次出现的关键字key
2.2.9 获取顺序表长度
2.2.10 清空顺序表
三、顺序表中的代码模拟实现
写在最后
前两篇博客,已经介绍了 学习数据结构 所需要知道的 两个前置知识;
那么,现在 我们来正式介绍 Java数据结构 的知识;
数据结构很重要,希望大家在看完这篇博客以后,收获满满!!!!!!
现在,正文开始......
线性表(linear list) 是n个具有相同特性的 数据元素的 有限序列;
线性表 是一种在实际中 广泛使用的数据结构,常见的线性表有:顺序表、链表、栈、队列、串......
线性表在逻辑上是线性结构,即 一条连续的直线;
但是在物理结构(真实的内存)上 并不一定是连续的,线性表 在物理上存储时,通常以数组和链式结构的形式存储。
顺序表 是用一段 物理地址连续 的存储单元 依次存储元素的 线性结构;
一般情况下 采用数组存储;
在数组上完成数据的 增删改查。
提出问题:
既然说顺序表 底层是一个数组,那么 为什么不直接操作数组 进行增删改查,还要单独写一个类说底层其实是数组呢?
解答:
我们根本不知道,在Java里面,数组当中,有多少个数据是有效的数据:
在Java中,没有填的数据 默认为0;
所以说,单单只有一个数组是搞不定的,还需要有一些与它配合的东西,提供一些方法等等......
所以说,顺序表 有两个属性:
- 数组Array;
- usedSize
然后接下来的步骤 就是对数组进行 CURD(增删查改)操作,数据结构 本身就是对数据进行操作的......
当然,以后要实现这个顺序表 可以不用自己去实现,Java所提供的 ArrayList 就是专门实现这种操作的;
而现在,要从无到有的实现顺序表,还需要自己去实现实现的......
public class MyArrayList {
//定义一个整型数组elem 和 计数器usedSize
public int[] elem;
public int usedSize;
//可以不用给 usedSize 进行初始化,默认是0
//对 数组elem 进行初始化
public MyArrayList() {
this.elem = new int[10];
}
}
测试一下下:
嗯,对,如果想要观察扩容的情况,可以自己去把数组elem长度调小一点,或者自己再去添加几个数据进去,然后自己再去调试调试看看!
这里就不展示了!
调试在数据结构很重要!!!!!!
目前这个图当中,是否可以在7下标添加元素?
——不可以,在数据结构中,每次存储元素的时候,一定要有一个前驱信息的(即 每一次存储元素的时候,不可以跳着插,前面一个位置必须要有一个元素)。
当然,判断下标是否合法,我们也可以 抛出一个自定义异常:
小小测试一下:
如果当前的数组存放的不是 简单类型,而是类类型(如Person,String,Integer,......),那么此时能否直接使用 == 来进行判断?
——如果是引用类型,我们只是判断两个是不是相等,不是来比较大小;
所以在这里我们需要重写equals方法。
【注意】
不是比较大小(>、 <、 ==(数值上的等于),重写比较的接口:如comparable<>),
而是判断是不是相等(==(内容上的相等),重写内容上的相等:如equals)。
这个地方,pos=usedSize的时候也是不合法的:
此时,usedSize是2,而我们也获取不了2下标的元素,因为2下标就没有有效的数据......
所以,当pos==usedSize的时候,pos的位置就不合法了。
也可以来抛出异常:
下面来小小测试一下:
取下标为-1:
取下标为0:
顺序表为空的情况:
把上面的判断抛出异常屏蔽:
小小的来测试一下:
如果存放的是基本类型,最简单的方式是这样的:
小小的测试一下:
如果是引用类型,那么就可以这样来做:
//引用类型清空
//如果是引用数据类型,那么得一个一个置为空,然后再把usedSize置为0,这样做才是最合适的
public void clear2() {
for (int i = 0; i < this.usedSize; i++) {
this.elem[i] = null;
}
this.usedSize = 0;
}
不过我这个顺序表示基本类型的,所以就不展示了。
如果,把elem置为null的话,也是可以的;
但是,这样做很暴力;
这就相当于,顺序表只玩了一次就没有了,下次再玩,就需要重新申请内存了;
不建议把elem置为null......
MyArrayList:package sqlist; import java.util.Arrays; public class MyArrayList { public int[] elem; public int usedSize; //可以不用给 usedSize 进行初始化,默认是0 //对 数组elem 进行初始化 public MyArrayList() { this.elem = new int[4]; } /** * 打印顺序表 * 需要根据usedSize来进行判断, * 不可以根据elem数组来进行判断(其所存储的有效数据<=elem数组的长度) */ public void display() { for (int i = 0; i < this.usedSize; i++) { System.out.print(this.elem[i]+" "); } System.out.println(); } //此时,usedSize == 0,所以此时调用 display接口 一个元素都没有 /** * 新增元素,默认在数组的最后新增 * 思路: * 1.把 新增的元素data 放到 elem的 第usedSize个位置 * 2.usedSize++ * 注意:还需要去完成一个判断数组是不是已经满了的方法, * 判断需不需要扩容 */ public void add(int data) { //1.判断是不是满的,如果满的,那么需要进行扩容 if (isFull()){ //扩容 this.elem = Arrays.copyOf(this.elem,2*this.elem.length); } //2.如果不是满的,那么就可以进行插入 this.elem[this.usedSize] = data; this.usedSize++; } public boolean isFull() { //如果 elem数组的长度 与 usedSize的长度一样,说明 已经满了 //满了,则返回 true; //没有满,则返回 false if(this.elem.length == this.usedSize) { return true; }else { return false; } } /** * 在pos位置新增元素 * 思路: * 1.判断 pos位置的合法性 * 2.判断 顺序表是否满了 * 3.插入数据 * 3.1 挪动数据 * 3.2 插入 */ private boolean checkPosInAdd(int pos) { //true 代表合法 //false 代表不合法 if(pos < 0 || pos > usedSize) { System.out.println("pos位置不合法"); return false; } return true; } public void add(int pos,int data) { //判断下标是否合法 if (!checkPosInAdd(pos)){ //!checkPosInAdd(pos) 等价于 checkPosInAdd(pos) == false //return; throw new MyArrayListIndexOutOfException("添加方法的pos位置不合理!"); } if(isFull()){ //扩容 this.elem = Arrays.copyOf(this.elem,2*this.elem.length); } //挪动数据 for (int i = this.usedSize-1; i >=pos ; i--) { this.elem[i+1] = this.elem[i]; } //挪完了数据,插入 this.elem[pos] = data; this.usedSize++; } //判定是否包含某个元素 public boolean contains(int toFind) { //遍历整个数组就好 //包含了 返回true //没包含 返回false for (int i = 0; i < this.usedSize; i++) { if (this.elem[i] == toFind) { return true; } } return false; } //查找某个元素对应的位置 public int indexOf(int toFind) { //找到了 返回i下标 //找不到 返回-1(数组无-1下标) for (int i = 0; i < this.usedSize; i++) { if (this.elem[i] == toFind) { return i; } } return -1; } //获取pos的位置 private boolean checkPosInGet(int pos) { //true 代表合法 //false 代表不合法 if(pos < 0 || pos >= usedSize) { System.out.println("pos位置不合法"); return false; } return true; } public boolean isEmpty() { return this.usedSize == 0; } public int get(int pos) { if (!checkPosInGet(pos)) { throw new MyArrayListIndexOutOfException("获取pos下标时,位置不合法"); } //这个也可以不用去写顺序表是否为空的情况 if (isEmpty()) { throw new MyArrayListEmptyException("获取元素的时候,顺序表为空"); } return this.elem[pos]; } //给 pos元素的位置设(更新)为 value public void set(int pos,int value) { if (!checkPosInGet(pos)) { throw new MyArrayListIndexOutOfException("更新pos下标的元素,位置不合法"); } //如果合法,那么其实不用判断顺序表为空的状态 if (isEmpty()) { throw new MyArrayListEmptyException("顺序表为空"); } //顺序表为满的情况下也可以更新 this.elem[pos] = value; } /** * 删除第一次出现的关键字key * 思路: * 1.顺序表不能为空 * 2.顺序表当中要有所要删除的数字 key * 3.找到 key的下标i * 4.把后面的数值覆盖掉前面的 */ public void remove(int key) { //顺序表不能为空 if(isEmpty()) { throw new MyArrayListEmptyException("顺序表为空,不能删除"); } //上面已经写好了indexOf()方法 int index = indexOf(key); if (index == -1){ System.out.println("不存在你要删除的数据"); return; } for (int i = index; i < this.usedSize-1; i++) { this.elem[i] = this.elem[i+1]; } //删除完成 this.usedSize--; //this.elem[usedSize] == null; 如果这里是 引用类型,这里需要置空 } /** * 获取顺序表长度 */ public int size() { return this.usedSize; } /** * 清空顺序表 */ //基本类型 public void clear1() { this.usedSize = 0; //this.elem = null; } //引用类型 // public void clear2() { // for (int i = 0; i < this.usedSize; i++) { // this.elem[i] = null; // } // this.usedSize = 0; // } }
MyArrayListIndexOutOfException:
package sqlist; public class MyArrayListIndexOutOfException extends RuntimeException{ public MyArrayListIndexOutOfException() { } public MyArrayListIndexOutOfException(String message) { super(message); } }
MyArrayListEmptyException:
package sqlist; public class MyArrayListEmptyException extends RuntimeException{ public MyArrayListEmptyException() { } public MyArrayListEmptyException(String message) { super(message); } }
测试类可以自己去测试测试......
这个是 数据结构 中的第一个比较简单的数据结构 —— 顺序表,它的底层是一个数组;
并且上面的其实是对Java中顺序表的模拟;
而在实际中,Java中的源码,它的顺序表 —— ArrayList,将在下一篇博客介绍。
由于博主水平有限,可能会出现一些表达不清楚,或者出现一些其他的情况,
欢迎各位铁汁们指出来,和博主一起改正,
一起努力,共同进步;
好了,如果这篇博客对铁汁们有帮助的话,可以送一个免费的 赞 嘛;
当然,顺手点个关注是再好不过的了......