问题
- 实现一个支持动态扩容的数组
- 实现一个大小固定的有序数组,支持动态增删改操作
- 实现两个有序数组合并为一个有序数组
简单总结
- 首先练习了基本的数组
- 动态数组没涉及到什么算法,应该是让我们纯粹练手的,因为自己设计,所以每次扩容至当前数组大小的2倍(显然不合理,后续会改进,不过也算是实现了动态扩容)。
- 有序数组涉及到的简单算法:二分查找、折半插入排序。
- 将两个有序数组合并为一个有序数组:归并排序的合并部分。
代码实现
- 码云代码链接
- 由于二者都需要封装起来,需要提供的方法也不尽相同,所以,先做了一个简单的接口
MyList
,如下。
package solve;
/**
* 默认只实现了增删改查
* @author 淡墨青衫
* @date 2019/11/14 - 11:32
*/
public interface MyArray<E> {
/**
* 向数组中添加元素
* @param value 待添加元素
* @throws ArrayIndexOutOfBoundsException 越界异常
*/
void add(E value);
/**
* 向数组中指定位置添加元素
* @param index 位置
* @param value 待添加元素
* @throws ArrayIndexOutOfBoundsException 越界异常
*/
void add(int index, E value);
/**
* 删除指定位置的元素
* @param index 位置
* @return 删除后的元素
* @throws ArrayIndexOutOfBoundsException 越界异常
*/
E delete(int index);
/**
* 更新指定位置元素
* @param index 位置
* @param newValue 新元素
* @throws ArrayIndexOutOfBoundsException 越界异常
*/
void set(int index, E newValue);
/**
* 更新指定值为新值
* @param original 旧值
* @param newValue 新值
* @return 更新成功返回true,如果未找到旧值返回false
*/
boolean update(E original, E newValue);
/**
* 获取指定位置的元素
* @param index 位置
* @throws ArrayIndexOutOfBoundsException 越界异常
*/
E get(int index);
/**
* 通过值获取指定元素的索引
* @param value 值
* @return 索引,如果查找不到返回-1
*/
int indexOf(E value);
/**
* 转换为数组
* @return Object 数组
*/
Object[] toArray();
/**
* 得到当前数组大小
* @return 数组大小
*/
int getSize();
}
- 动态数组实现
package solve;
import java.util.Arrays;
/**
* 一个支持动态扩容的数组
* 增,删,改,查
* @date 2019/11/9 - 16:14
*/
public class DynamicArray<E> implements MyArray<E>{
private Object[] elements;
/**
* 数组当前大小
*/
private int size;
private static final int DEFAULT_CAPACITY = 10;
private static final int DEFAULT_INCREMENT = 2;
private int index;
public DynamicArray(E[] elements) {
this.elements = elements;
}
public DynamicArray(int capacity) {
this.elements = new Object[capacity];
}
public DynamicArray() {
this.elements = new Object[10];
}
@Override
public void add(E value) {
this.ensureSize();
this.elements[size++] = value;
}
@Override
public void add(int index, E value) {
// 如果是向末尾添加元素,允许添加,否则再检测越界异常
if (index == this.size) {
this.add(value);
return ;
}
this.checkRange(index);
this.ensureSize();
int moveNumber = this.size - index;
if (moveNumber > 0) {
System.arraycopy(this.elements, index, this.elements, index + 1,
moveNumber);
}
this.elements[index] = value;
this.size++;
}
@SuppressWarnings("unchecked")
@Override
public E get(int index) {
this.checkRange(index);
return (E) this.elements[index];
}
@Override
public int indexOf(E value) {
if (value == null) {
for (int i = 0; i < this.elements.length; i++) {
if (this.elements[i] == null) {
return i;
}
}
return -1;
} else {
for (int i = 0; i < this.elements.length; i++) {
if (value.equals(this.elements[i])) {
return i;
}
}
return -1;
}
}
@SuppressWarnings("unchecked")
@Override
public void set(int index, E newValue) {
this.checkRange(index);
this.elements[index] = newValue;
}
@SuppressWarnings("unchecked")
@Override
public E delete(int index) {
this.checkRange(index);
E result = (E) this.elements[index];
// 将删除元素后的所有元素向前移动一个位置。
int moveNumber = this.size - 1 - index;
if (moveNumber > 0) {
System.arraycopy(this.elements, index + 1, this.elements, index,
moveNumber);
}
// 将最后一个位置赋值为null。
this.elements[--size] = null;
return result;
}
@Override
public boolean update(E original, E newValue) {
int originalIndex = this.indexOf(original);
if (originalIndex == -1) {
return false;
}
this.elements[originalIndex] = newValue;
return true;
}
/**
* 转换为Object数组
* @return Object数组
*/
@Override
public Object[] toArray() {
return Arrays.copyOf(this.elements, this.size);
}
/**
* 让数组缩减到已有元素大小。
*/
public void trimToSize() {
this.elements = Arrays.copyOf(this.elements, this.size, Object[].class);
}
@Override
public int getSize() {
return this.size;
}
/**
* 检查大小,不够则扩容
*/
private void ensureSize() {
if (this.size >= this.elements.length || index > this.elements.length) {
this.elements = Arrays.copyOf(this.elements,
this.elements.length * DEFAULT_INCREMENT);
}
}
/**
* 检查是否越界
* @param index 索引
* @throws ArrayIndexOutOfBoundsException 数组越界异常
*/
private void checkRange(int index) {
if (index >= this.size) {
throw new ArrayIndexOutOfBoundsException(index);
}
}
}
测试
package solve;
import java.util.Arrays;
import java.util.Random;
/**
* @author 淡墨青衫
* @date 2019/11/14 - 10:35
*/
public class DynamicTest {
public static void main(String[] args){
DynamicArray<Integer> array = new DynamicArray<>();
Random random = new Random();
for (int i = 0; i < 15; i++) {
array.add(random.nextInt(30));
}
print("初始化完成", array);
System.out.println("正确部分");
array.add(0, 0);
print("在索引为0处增加元素0", array);
array.add(10, 0);
print("在索引为10处增加元素0", array);
array.delete(0);
print("删除索引为0的元素", array);
array.delete(10);
print("删除索引为10的元素", array);
array.set(0, -1);
print("修改索引为0的值为-1", array);
System.out.println("索引为0的值为:" + array.get(0));
array.add(15, 15);
print("在索引为15处增加元素15", array);
int temp = random.nextInt(30);
boolean result = array.update(temp, -5);
print("更新值为" + temp + "的元素值为 -5", array);
System.out.println("更新结果" + result);
int test = random.nextInt(14);
System.out.println("值为" + array.get(test) + "的索引为:" + array.indexOf(array.get(test)));
System.out.println("错误部分");
// array.add(20, 20);
// array.delete(20);
// array.set(16, 20);
// array.indexOf(16);
}
private static void print(String message, DynamicArray<?> array) {
System.out.println("=====");
System.out.println(message);
System.out.println(Arrays.toString(array.toArray()));
System.out.println("=====");
}
}
- 有序数组实现
package solve;
import java.util.Arrays;
/**
* @author 淡墨青衫
* @date 2019/11/14 - 11:29
*/
public class OrderArray<E extends Comparable> implements MyArray<E> {
private Object[] elements;
private static final int DEFAULT_SIZE = 10;
private int size;
public OrderArray(Object[] elements) {
this.elements = elements;
}
public OrderArray(int size) {
this(new Object[size]);
}
public OrderArray() {
this(DEFAULT_SIZE);
}
@SuppressWarnings("unchecked")
@Override
public void add(E value) {
if (this.size >= this.elements.length) {
throw new OutOfSpaceException("数组已满,当前数组大小为" + this.elements.length);
}
// 使用二分查找到要插入的位置
int resultIndex = binarySearch(value, false);
// 移动元素
moveElements(resultIndex);
this.elements[resultIndex] = value;
this.size++;
}
@Override
public void add(int index, E value) {
this.add(value);
}
@SuppressWarnings("unchecked")
@Override
public E delete(int index) {
rangeCheck(index);
E result = (E) this.elements[index];
int moveNumber = this.size - 1 - index;
if (moveNumber > 0) {
System.arraycopy(this.elements, index + 1, this.elements, index,
moveNumber);
}
this.elements[--size] = null;
return result;
}
@Override
public void set(int index, E newValue) {
rangeCheck(index);
this.delete(index);
this.add(newValue);
}
@SuppressWarnings("unchecked")
@Override
public E get(int index) {
rangeCheck(index);
return (E) this.elements[index];
}
@Override
public int indexOf(E value) {
return binarySearch(value, true);
}
@Override
public boolean update(E original, E newValue) {
int originalIndex = indexOf(original);
if (originalIndex == -1) {
return false;
}
this.delete(originalIndex);
this.add(newValue);
return true;
}
@Override
public Object[] toArray() {
return Arrays.copyOf(this.elements, this.size);
}
@Override
public int getSize() {
return this.size;
}
/**
* 合并两个有序数组,对于null值,统一将其移至合并后的数组末尾
* @param array 需要合并的数组
* @return 合并后的结果
*/
@SuppressWarnings("unchecked")
public Object[] mergeArray(OrderArray<E> array) {
Object[] result = new Object[this.size + array.toArray().length];
// 数组1的索引
int x = 0;
// 数组2的索引
int y = 0;
// 新数组null值索引
int z = result.length - 1;
int i = 0;
while (i < result.length) {
// 对于null值,统一将其放至末尾
if (this.elements[x] == null) {
x++;
result[z--] = null;
}
if (array.get(y) == null) {
y++;
result[z--] = null;
}
// 小的放前面
if (array.get(y).compareTo(this.elements[x]) <= 0) {
result[i++] = array.get(y++);
} else {
result[i++] = this.elements[x++];
}
// 如果其中一个已经空了,另一个没空
if (x == this.size && y != array.getSize()) {
System.arraycopy(array.toArray(), y, result, i,
z - i + 1);
break;
} else if (y == array.getSize() && x != this.size) {
System.arraycopy(this.elements, x, result, i,
z - i + 1);
break;
}
}
return result;
}
/**
* 检测数组索引范围
* @param index
*/
private void rangeCheck(int index) {
if (index >= this.elements.length) {
throw new ArrayIndexOutOfBoundsException(index);
}
}
/**
* 移动元素
* @param index 起始点
*/
private void moveElements(int index) {
int moveNumber = this.size - index;
if (moveNumber > 0) {
System.arraycopy(this.elements, index, this.elements, index + 1,
moveNumber);
}
}
/**
* 使用二分查找到指定值的位置,或者指定值需要插入的位置
* @param value 值
* @param isSearch 是否为查找
* @return 如果是查找,找不到返回-1,如果是找插入的位置,返回插入的位置
*/
@SuppressWarnings("unchecked")
private int binarySearch(E value, boolean isSearch) {
// 对无元素做处理
if (this.size == 0) {
if (isSearch) {
return -1;
} else {
return 0;
}
}
// 对空做处理
if (value == null) {
for (int i = 0; i < this.elements.length; i++) {
if (this.elements[i] == null) {
return i;
}
}
if (isSearch) {
return -1;
} else {
return this.elements.length - 1;
}
}
// 二分查找
int start = 0;
int end = this.size - 1;
int mid;
do {
mid = (start + end) / 2;
if (value.compareTo(this.elements[mid]) == 0) {
return mid;
} else if (value.compareTo(this.elements[mid]) < 0) {
end = mid - 1;
} else {
start = mid + 1;
}
} while (start <= end);
if (isSearch) {
return -1;
} else {
return start;
}
}
}
// 涉及到的自定义异常
package solve;
/**
* @author 淡墨青衫
* @date 2019/11/14 - 16:43
*/
public class OutOfSpaceException extends RuntimeException {
public OutOfSpaceException() {
super();
}
public OutOfSpaceException(String message) {
super(message);
}
public OutOfSpaceException(String message, Throwable cause) {
super(message, cause);
}
public OutOfSpaceException(Throwable cause) {
super(cause);
}
protected OutOfSpaceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
测试
package solve;
import java.util.Arrays;
import java.util.Random;
/**
* @author 淡墨青衫
* @date 2019/11/14 - 16:48
*/
public class OrderArrayTest {
public static void main(String[] args){
OrderArray<Integer> array = new OrderArray<>();
System.out.println("正常操作");
Random random = new Random();
for (int i = 0; i < 9; i++) {
array.add(random.nextInt(30));
}
print("初始化完毕", array);
array.add(4, 20);
print("在index = 4处增加元素20", array);
array.delete(5);
print("删除索引为5的元素", array);
array.set(4, 20);
print("修改索引为4的值为20", array);
System.out.println("索引为3的值为:" + array.get(3));
int temp = random.nextInt(30);
boolean result = array.update(temp, -5);
print("更新值为" + temp + "的元素值为 -5", array);
System.out.println("更新结果" + result);
int test = random.nextInt(8);
System.out.println("值为" + array.get(test) + "的索引为" + array.indexOf(array.get(test)));
System.out.println("错误检测");
// System.out.println("值为-2的索引为" + array.indexOf(-2));
// System.out.println("索引为11的值为" + array.get(11));
// array.add(35);
// print("添加到满", array);
// array.add(36);
// print("添加至溢出", array);
}
private static void print(String message, OrderArray<?> array) {
System.out.println(message + "\n" + Arrays.toString(array.toArray()));
}
}