数据结构和算法之美专栏练习1之动态数组和有序数组

问题

  1. 实现一个支持动态扩容的数组
  2. 实现一个大小固定的有序数组,支持动态增删改操作
  3. 实现两个有序数组合并为一个有序数组

简单总结

  1. 首先练习了基本的数组
  2. 动态数组没涉及到什么算法,应该是让我们纯粹练手的,因为自己设计,所以每次扩容至当前数组大小的2倍(显然不合理,后续会改进,不过也算是实现了动态扩容)。
  3. 有序数组涉及到的简单算法:二分查找、折半插入排序
  4. 将两个有序数组合并为一个有序数组:归并排序的合并部分

代码实现

  1. 码云代码链接
  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();
}

  1. 动态数组实现
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("=====");
    }
}

  1. 有序数组实现
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()));
    }
}

发布了76 篇原创文章 · 获赞 53 · 访问量 4162

猜你喜欢

转载自blog.csdn.net/qq_42254247/article/details/103075606