目录
功能菜单
Java数据结构中顺序表的功能有:
- 新增元素
- 判断是否包含某个元素
- 查找某个元素对应的位置
- 获取对应位置的元素
- 给对应位置的元素设为指定值
- 删除某一位置的值
- 清空顺序表
- 打印顺序表
功能的具体实现
搭建框架
首先是要把初始的框架搭建出来,顺序表的本质是关于数组的调用,所以首先我们要进行数组方面的初始化
MyArrayList类
public int[] array;
public int useSize;
public static final int DEAULT_CAPACITY = 10;
public MyArrayList(){
this.array = new int[DEAULT_CAPACITY];
}
注意:useSize用来记录数组中元素个数
因为其中需要实现的方法有很多,所以我们可以采取使用接口,在MyArrayList类中重写接口中的方法
IList接口
public interface IList {
// 新增元素,默认在数组最后新增
public void add(int data);
// 在 pos 位置新增元素
public void add(int pos, int data);
// 判定是否包含某个元素
public boolean contains(int toFind);
// 查找某个元素对应的位置
public int indexOf(int toFind);
// 获取 pos 位置的元素
public int get(int pos);
// 给 pos 位置的元素设为 value
public void set(int pos, int value);
//删除第一次出现的关键字key
public void remove(int toRemove);
// 获取顺序表长度
public int size();
// 清空顺序表
public void clear();
// 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
public void display();
}
在MyArrayList类中重写其中的方法
@Override
public void add(int data) {
}
@Override
public void add(int pos, int data) {
}
@Override
public boolean contains(int toFind) {
return false;
}
@Override
public int indexOf(int toFind) {
return 0;
}
@Override
public int get(int pos) {
return 0;
}
@Override
public void set(int pos, int value) {
}
@Override
public void remove(int toRemove) {
}
@Override
public int size() {
return 0;
}
@Override
public void clear() {
}
@Override
public void display() {
}
功能实现
接下来的方法都是在MyArrayList类里面重写接口的方法,都是在MyArrayList类中进行的。
打印顺序表
display方法
该方法不是顺序表中的方法,是为了方便看测试结果。这个方法和遍历数组很像,把数组中的元素都给打印出来。
public void display() {
for (int i = 0; i < this.useSize; i++) {
System.out.print(array[i] + " ");
}
}
获取顺序表长度
size方法
前面有说到useSize代表着数组中元素个数,所以这里返回useSize的值就行了。
public int size() {
return this.useSize;
}
数组最后新增元素
add方法
这里我一开始想到的是这样的一段代码:
public void add(int data) {
this.array[this.useSize] = data;
this.useSize++;
}
但后面想到如果新增元素时数组满了,那是不是要进行判断?如果满了之后,如何扩容数组来变得能放进去元素?
首先要解决的问题,是关于判满,数组里元素满的时候应该是useSize的值和数组的长度一样,可以从这点出发来写一个isFull方法。
public boolean isFull(){
return this.useSize == array.length;
}
如果数组中的元素满了,我们需要对数组进行扩容后才能继续放元素进去,这时候可以调用copyOf方法来进行扩容,再写一个grow方法。
private void grow(){
this.array = Arrays.copyOf(this.array,
2*this.array.length);
}
这里的grow方法的访问修饰限定符是private,是因为它是给isFull方法用的,对于其他的方法来说不是很需要,所以不需要使用public。
最终的add方法是如下:
public void add(int data) {
if(isFull()){
grow();
}
this.array[this.useSize] = data;
this.useSize++;
}
public boolean isFull(){
return this.useSize == array.length;
}
private void grow(){
this.array = Arrays.copyOf(this.array,
2*this.array.length);
}
在指定位置新增元素
add方法
这个方法和上面 数组最后新增元素 构成了方法的重载。
数组中,在指定位置pos上出入元素,这时候我们可以通过后一个元素来覆盖前一个元素的方式来让指定位置空出来,然后新增元素。不过一开始还是要对数组进行判满。
public void add(int pos, int data) {
if(isFull()){
grow();
}
//挪动元素
for (int i = useSize - 1; i >= pos; i--) {
this.array[i+1] = this.array[i];
}
array[pos] = data;
useSize++;
}
关于i是从useSize - 1 开始的,是因为是从后面开始进行元素的覆盖的,然后i >= pos,是为让pos位置的元素空出来。
这里其实细想来还是有些问题。哈哈,数据结构的学习有两个特点:
- 数据结构会抽象一点
- 其中的逻辑严谨,简单但是代码一大堆
在这里的问题在于,我们无法判断 插入元素pos位置是否合法。
细细琢磨,我们能想到pos位置有以下几种情况:
- pos < 0 不可以插入
- pos > useSize 不可以插入
- pos = useSize 可以插入
这时候可以有 checkPos方法 的一个框架
private void checkPos(int pos) {
if(pos < 0 || pos > this.useSize){
}
}
问题到这,如果pos的位置不合理,我们该如何提示使用者这个信息呢?这就可以联系到前面了解过的异常方面的知识,这时候我们可以通过 抛出一个异常 提示使用者pos位置不合理。
通过新创建一个PosIllegal类
PosIllegal类
public class PosIllegal extends Exception{
public PosIllegal(){
}
public PosIllegal(String msg){
super(msg);
}
}
补充完整checkPos方法
private void checkPos(int pos) throws PosIllegal{//告诉会抛出一个异常
if(pos < 0 || pos > this.useSize){
throw new PosIllegal("Pos位置不合法!!!");
}
}
再在add方法中使用try-catch来进行异常的判断
try {
checkPos(pos);
}catch (PosIllegal e){
System.out.println("插入元素pos位置不合法");
e.printStackTrace();
}
最终,该add方法的完整如下
private void checkPos(int pos) throws PosIllegal{//告诉会抛出一个异常
if(pos < 0 || pos > this.useSize){
throw new PosIllegal("Pos位置不合法!!!");
}
}
@Override
public void add(int pos, int data) {
try {
checkPos(pos);
}catch (PosIllegal e){
System.out.println("插入元素pos位置不合法");
e.printStackTrace();
}
if(isFull()){
grow();
}
//挪动元素
for (int i = useSize - 1; i >= pos; i--) {
this.array[i+1] = this.array[i];
}
array[pos] = data;
useSize++;
}
判断是否含有某个元素
contains方法
这部分其实和遍历数组差不多,通过遍历数组来看其中是否有对应的元素,找到返回true,没找到返回false。
public boolean contains(int toFind) {
for (int i = 0; i < array.length; i++) {
if(array[i] == toFind){
return true;
}
}
return false;
}
查找元素对应位置
indexOf方法
该部分和上面的contains方法很像,只不过这个是返回元素对应的下标。
public int indexOf(int toFind) {
for (int i = 0; i < array.length; i++) {
if(array[i] == toFind){
return i;
}
}
return 0;
}
获取指定位置的元素
get方法
这里提到了指定位置,所以也是要判断pos位置是否合理,pos不合理的情况有两种:
- pos < 0
- pos >= useSize
此时的checkPos2方法如下:
private void checkPos2(int pos) throws PosIllegal{//告诉会抛出一个异常
if(pos < 0 || pos >= this.useSize){
throw new PosIllegal("Pos位置不合法!!!");
}
}
这次就不卖关子了,还有一个要考虑的地方,就是该数组是否是空数组。我们可以写一个isEmpty方法来进行判断。
public boolean isEmpty(){
return useSize == 0;
}
同样的,我们也可以写出一个异常类来告知操作者数组是空数组,具体的操作和上面的大同小异,所以下面直接给出代码部分:
EmptyException类
public class EmptyException extends RuntimeException{
public EmptyException(){
}
public EmptyException(String msg){
super(msg);
}
}
checkEmpty方法
private void checkEmpty(){
if(isEmpty()){
throw new EmptyException("顺序表为空!!!");
}
}
get方法完整部分
private void checkPos2(int pos) throws PosIllegal{//告诉会抛出一个异常
if(pos < 0 || pos >= this.useSize){
throw new PosIllegal("Pos位置不合法!!!");
}
}
private void checkEmpty(){
if(isEmpty()){
throw new EmptyException("顺序表为空!!!");
}
}
public boolean isEmpty(){
return useSize == 0;
}
@Override
public int get(int pos) {
try {
checkEmpty();
checkPos2(pos);
return array[pos];
}catch (PosIllegal e){
e.printStackTrace();
}catch (EmptyException e){
e.printStackTrace();
}
return -1;
}
更新数组中的元素
set方法
更新数组中的元素是指更改指定位置上的元素的值。这里要需要判断pos指定位置是否合理以及数组是否为空,和get方法中抛出的异常是一样的,其中多了一步 array[pos] = value。
public void set(int pos, int value) {
try {
checkEmpty();
checkPos2(pos);
array[pos] = value;
}catch (PosIllegal e){
e.printStackTrace();
}catch (EmptyException e){
e.printStackTrace();
}
}
移除数组中的元素
remove方法
这里我们可以用前面写过的indexOf方法来定位需要移除元素的位置。然后从数组后面进行元素的覆盖。其中也需要判断数组是否为空,以及其中是否有要删去的元素。
public void remove(int toRemove) {
try {
checkEmpty();
int pos = indexOf(toRemove);
if(pos == -1){
return;
}
for (int i = pos; i < useSize - 1; i++) {
array[i] = array[i + 1];
}
useSize--;
}catch (EmptyException e){
e.printStackTrace();
}
}
清空顺序表
clear方法
数组中是通过useSize来进行元素个数的统计,这时候我们就可以通过让useSize的值为0来清空顺序表。
public void clear() {
//引用类型
/* for (int i = 0; i < useSize ; i++) {
array[i] = null;
}*/
useSize = 0;
}
若是引用类型的元素,则需要通过for循环使其称为null,再使useSize=0。
完整代码
MyArrayList类
import java.util.Arrays;
public class MyArrayList implements IList{
public int[] array;
public int useSize;
public static final int DEAULT_CAPACITY = 10;
public MyArrayList(){
this.array = new int[DEAULT_CAPACITY];
}
@Override
public void add(int data) {
if(isFull()){
grow();
}
this.array[this.useSize] = data;
this.useSize++;
}
public boolean isFull(){
return this.useSize == array.length;
}
private void grow(){
this.array = Arrays.copyOf(this.array,
2*this.array.length);
}
private void checkPos(int pos) throws PosIllegal{//告诉会抛出一个异常
if(pos < 0 || pos > this.useSize){
throw new PosIllegal("Pos位置不合法!!!");
}
}
@Override
public void add(int pos, int data) {
try {
checkPos(pos);
}catch (PosIllegal e){
System.out.println("插入元素pos位置不合法");
e.printStackTrace();
}
if(isFull()){
grow();
}
//挪动元素
for (int i = useSize - 1; i >= pos; i--) {
this.array[i+1] = this.array[i];
}
array[pos] = data;
useSize++;
}
@Override
public boolean contains(int toFind) {
for (int i = 0; i < array.length; i++) {
if(array[i] == toFind){
return true;
}
}
return false;
}
@Override
public int indexOf(int toFind) {
for (int i = 0; i < array.length; i++) {
if(array[i] == toFind){
return i;
}
}
return 0;
}
private void checkPos2(int pos) throws PosIllegal{//告诉会抛出一个异常
if(pos < 0 || pos >= this.useSize){
throw new PosIllegal("Pos位置不合法!!!");
}
}
public boolean isEmpty(){
return useSize == 0;
}
@Override
public int get(int pos) {
try {
checkEmpty();
checkPos2(pos);
return array[pos];
}catch (PosIllegal e){
e.printStackTrace();
}catch (EmptyException e){
e.printStackTrace();
}
return -1;
}
private void checkEmpty(){
if(isEmpty()){
throw new EmptyException("顺序表为空!!!");
}
}
@Override
public void set(int pos, int value) {
try {
checkEmpty();
checkPos2(pos);
array[pos] = value;
}catch (PosIllegal e){
e.printStackTrace();
}catch (EmptyException e){
e.printStackTrace();
}
}
@Override
public void remove(int toRemove) {
try {
checkEmpty();
int pos = indexOf(toRemove);
if(pos == -1){
return;
}
for (int i = pos; i < useSize - 1; i++) {
array[i] = array[i + 1];
}
useSize--;
}catch (EmptyException e){
e.printStackTrace();
}
}
@Override
public int size() {
return this.useSize;
}
@Override
public void clear() {
//引用类型
/* for (int i = 0; i < useSize ; i++) {
array[i] = null;
}*/
useSize = 0;
}
@Override
public void display() {
for (int i = 0; i < this.useSize; i++) {
System.out.print(array[i] + " ");
}
}
}
IList接口类
public interface IList {
// 新增元素,默认在数组最后新增
public void add(int data);
// 在 pos 位置新增元素
public void add(int pos, int data);
// 判定是否包含某个元素
public boolean contains(int toFind);
// 查找某个元素对应的位置
public int indexOf(int toFind);
// 获取 pos 位置的元素
public int get(int pos);
// 给 pos 位置的元素设为 value
public void set(int pos, int value);
//删除第一次出现的关键字key
public void remove(int toRemove);
// 获取顺序表长度
public int size();
// 清空顺序表
public void clear();
// 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
public void display();
}
EmptyException异常类
public class EmptyException extends RuntimeException{
public EmptyException(){
}
public EmptyException(String msg){
super(msg);
}
}
PosIllegal异常类
public class PosIllegal extends Exception{
public PosIllegal(){
}
public PosIllegal(String msg){
super(msg);
}
}