目录
顺序表其实就是一个数组 ,数组本身又是连续的一块内存,操作数组,在数组上进行增删查改。
实现顺序表
基本骨架
创建一个arraylist的包->创建一个类MyArrayList、异常类(位置不合法)、测试类->定义一个接口(含要实现的方法)
java
package arraylist;
interface IList {
// 新增元素,默认在数组最后新增
void add(int data);
// 在 pos 位置新增元素
void add(int pos, int data);
// 判定是否包含某个元素
boolean contains(int toFind);
// 查找某个元素对应的位置
int indexOf(int toFind);
// 获取 pos 位置的元素
int get(int pos);
// 给 pos 位置的元素设为 value
void set(int pos, int value);
//删除第一次出现的关键字key
void remove(int toRemove);
// 获取顺序表长度
int size();
// 清空顺序表
void clear();
// 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
void display();
//判断数组是否满
Boolean isFull();
}
java
package arraylist;
public class MyArrayList implements IList{
public int[] elem;//定义一个elem数组
int usedSize;//记录数组中所存的个数
public MyArrayList() {
this.elem = new int[10];
}
@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() {
}
@Override
public Boolean isFull() {
return null;
}
}
java
package arraylist;
//异常类的处理 更多内容请看专栏JavaSE语法
public class PosNotLegalException extends RuntimeException {
public PosNotLegalException() {
}
public PosNotLegalException(String msg) {
super(msg);
}
}
java
package arraylist;
public class Test {
public static void main(String[] args) {
//实现之后 有两种方法来使用此顺序表
MyArrayList myArrayList = new MyArrayList();
IList iList = new MyArrayList();
}
}
各个方法的实现
判断数组是否满
java
@Override
public Boolean isFull() {
return usedSize == elem.length;
}
在数组最后新增元素
1、先要判断数组是否满了
2、如果满了进行扩容
3、没满则elem[usedSize]=data;
java
@Override
public void add(int data) {
if (isFull()) {
this.elem = Arrays.copyOf(elem, 2 * elem.length);
} else this.elem[usedSize] = data;
this.usedSize++;
}
在pos位置插入元素
1、先判断pos位置是否合法
2、再判断数组元素是否已满
3、找到pos位置,再移动元素(从最后一个元素向前遍历)elem[i]=elem[i-1];i>=pos+1;
4、插入元素elem[pos]=data;
java
@Override
public void add(int pos, int data) {
try {
checkPosOfAdd(pos);
} catch (PosNotLegalException e) {
e.printStackTrace();
}
if (isFull()) {
this.elem = Arrays.copyOf(elem, 2 * elem.length);
}
for (int i = this.usedSize - 1; i >= pos; i--) {
this.elem[i] = this.elem[i - 1];
}
this.elem[pos] = data;
this.usedSize++;
}
//该方法用来判断插入元素的pos位置是否合法
private void checkPosOfAdd(int pos) throws PosNotLegalException {
if (pos < 0 || pos > usedSize)
throw new PosNotLegalException("pos位置不合法");
}
判断是否包含某个元素
java
@Override
public boolean contains(int toFind) {
for (int i = 0; i < usedSize; i++) {
if (this.elem[i] == toFind)
return true;
}
return false;
}
查找某个元素对应的位置
1、遍历找到这个元素并返回对应的位置
2、找不到返回-1
java
@Override
public int indexOf(int toFind) {
for (int i = 0; i < usedSize; i++) {
if (this.elem[i] == toFind)
return i;
}
return -1;
}
获取/改变pos位置的元素
先判断pos位置是否合法
java
@Override
public int get(int pos) {
try {
checkPosGetAndSet(pos);
} catch (PosNotLegalException e) {
e.printStackTrace();
}
return this.elem[pos];
}
@Override
public void set(int pos, int value) {
try {
checkPosGetAndSet(pos);
} catch (PosNotLegalException e) {
e.printStackTrace();
}
this.elem[pos] = value;
}
private void checkPosGetAndSet(int pos) throws PosNotLegalException {
if (pos < 0 || pos >= usedSize)
throw new PosNotLegalException("get/set pos位置不合法");
}
删除第一次出现的元素
1、先找到这个元素所在的位置
2、再从这个位置开始往后进行遍历elem[i]=elem[i+1];i<usedSize-1;
java
@Override
public void remove(int toRemove) {
int pos = indexOf(toRemove);
if (pos == -1) {
System.out.println("没有找到要删除的元素!");
return;
}
for (int i = pos; i < usedSize - 1; i++) {
this.elem[i] = this.elem[i + 1];
}
usedSize--;
}
获取顺序表的长度
java
@Override
public int size() {
return this.usedSize;
}
清空顺序表
引用类型和基本数据类型不一样,引用类型会引用一个对象,如果只是将usedSize置为0,里面的对象还在引用着之前的对象---"内存泄漏"(本来不需要的对象还有元素在引用)。
java
@Override
public void clear() {
// for (int i = 0; i < usedSize; i++) {
// elem[i]=null;
// }
this.usedSize = 0;
}
打印顺序表
java
@Override
public void display() {
for (int i = 0; i < this.usedSize; i++) {
System.out.print(this.elem[i] + " ");
}
System.out.println();
}
注意事项
使用usedSize来记录当前有效数据个数,在增加了元素或删除了元素时要随时对usedSize++/--。
使用顺序表
以后在使用顺序表的时候,不可能再重头搭建一个顺序表。在Java当中已经实现了一个顺序表,我们只需来使用这个集合类。
此时仍然有两种方法来使用
public static void main(String[] args) { ArrayList<Integer> arrayList = new ArrayList<>(); List<Integer> list = new ArrayList<>(); }
通过list访问的方法比通过arrayList访问的方法少,因为前者只能访问接口中特有的方法,而后者为对象可以访问arrayList自己的方法。
认识构造方法
无参构造
只是一个数组引用
数组的长度为0
当调用一个不带参数的构造方法的时候,并没有给数组分配大小,数组的长度为0。那为什么可以add元素?
当调用不带参数的构造方法进行add时,第一次add会分配大小为10的内存。扩容机制为1.5倍扩容。
利用其他Collection构建ArrayList
1、ArrayList是实现了Collection接口的
2、参数的类型是当前arrayList2指定的泛型类型本身
指定顺序表初始容量
初始化指定数组大小
ArrayList常见操作
ArrayList的遍历
java
public class Test1 {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(10);
arrayList.add(3);
arrayList.add(9);
arrayList.add(7);
arrayList.add(23);
for (int i = 0; i < arrayList.size(); i++) {
System.out.print(arrayList.get(i) + " ");
}
System.out.println();
System.out.println("================");
for (Integer x : arrayList) {
System.out.print(x + " ");
}
System.out.println();
System.out.println("================");
Iterator<Integer> it = arrayList.iterator();
while (it.hasNext()) {
System.out.print(it.next() + " ");
}
System.out.println();
System.out.println("================");
ListIterator<Integer> it1 = arrayList.listIterator();
while (it1.hasNext()) {
System.out.print(it1.next() + " ");
}
System.out.println();
System.out.println("================");
//从指定位置开始打印(倒着打印)
ListIterator<Integer> it2 = arrayList.listIterator(arrayList.size());
while (it2.hasPrevious()) {
System.out.print(it2.previous() + " ");
}
System.out.println();
System.out.println("================");
}
}
顺序表的优缺点
优点:在给定下标的情况下,访问速度比较快-O(1)。适用于经常进行下标查找或更新的操作。
缺点:
- 对于ArrayList来说不方便插入和删除因为要移动数组元素,最坏情况下,0下标插入,得移动所有元素,删除0下标也得移动所有元素。
- 扩容可能会浪费空间。假设现在100个长度放满了,还有一个元素没放,假设此时扩容,多了50个,但是实际只需要一个。