自定义数组类

功能

  1. 获取元素个数
  2. 获取数组容量
  3. 动态扩容
  4. 增删改查操作

    注意点

    移除节点

    移除时,索引位置之后的元素全部往前移一位,从前往后移

    1. for (int i = index + 1; i < size; i++) {
    2. data[i - 1] = data[i];
    3. }

    添加节点

    添加时,索引位置开始的元素全部往后移一位,从后往前移

    1. for (int i = size - 1; i >= index; i--) {
    2. data[i + 1] = data[i];
    3. }

    代码

    ```java public class MyArray {

    private T[] data; private Integer size;

    public MyArray(Integer capacity) {

    1. data = (T[]) new Object[capacity];
    2. size = 0;

    }

    public MyArray() {

    1. this(10);

    }

    /**

    • 元素个数 *
    • @return java.lang.Integer
    • @author YangYudi
    • @date 2020/12/25 15:25 */ public Integer getSize() { return size; }

      /**

    • 数组容量 *
    • @return java.lang.Integer
    • @author YangYudi
    • @date 2020/12/25 15:25 */ public Integer getCapacity() { return data.length; }

      /**

    • 判空 *
    • @return boolean
    • @author YangYudi
    • @date 2020/12/28 15:50 */ public boolean isEmpty() { return size == 0; }

      /**

    • 数组扩容 *
    • @param newSize 新大小
    • @return void
    • @author YangYudi
    • @date 2020/12/25 15:46 */ private void resize(Integer newSize) { T[] newData = (T[]) new Object[newSize]; for (int i = 0; i < size; i++) {

      1. newData[i] = data[i];

      } data = newData; }

      public void addLast(T e) { add(size, e); }

      public void addFirst(T e) { add(0, e); }

      /**

    • 添加 *
    • @param index 下标
    • @param e 对象
    • @author YangYudi
    • @date 2020/12/28 15:50 */ public void add(Integer index, T e) { if (size == data.length) {

      1. Integer length = data.length;
      2. //通过位运算得到新长度 借鉴arraylist
      3. Integer resize = length + (length >> 1);
      4. resize(resize);

      } if (index < 0 || index > size) {

      1. throw new IllegalArgumentException("下标不合法");

      } for (int i = size - 1; i >= index; i—) {

      1. data[i + 1] = data[i];

      } data[index] = e; size++; }

      /**

    • 判断有没有 *
    • @param e 对象
    • @author YangYudi
    • @date 2020/12/28 15:50
    • @return boolean */ public boolean contains(T e) { for (int i = 0; i < size; i++) {

      1. if (data[i].equals(e)) {
      2. return true;
      3. }

      } return false; }

      /**

    • 判断对象存不存在 *
    • @param e 对象
    • @author YangYudi
    • @date 2020/12/28 15:51
    • @return java.lang.Integer */ public Integer find(T e) { for (int i = 0; i < size; i++) {

      1. if (data[i].equals(e)) {
      2. return i;
      3. }

      } return -1; }

      public T get(Integer index) { if (index < 0 || index >= size) {

      1. throw new IllegalArgumentException("下标不合法");

      } return data[index]; }

      public T getLast() { return get(size - 1); }

      public T getFirst() { return get(0); }

      public void set(Integer index, T e) { if (index < 0 || index >= size) {

      1. throw new IllegalArgumentException("下标不合法");

      } data[index] = e; }

      public T removeFirst() { return remove(0); }

      public T removeLast() { return remove(size - 1); }

      public void removeElement(T e) { int index = find(e); if (index != -1) {

      1. remove(index);

      } }

      public T remove(Integer index) { if (index < 0 || index >= size) {

      1. throw new IllegalArgumentException("下标不合法");

      } T temp = data[index]; for (int i = index + 1; i < size; i++) {

      1. data[i - 1] = data[i];

      } size—; data[size] = null; return temp; }

      @Override public String toString() { return “MyArray{“ +

      1. "data=" + Arrays.toString(data) +
      2. ", size=" + size +
      3. '}';

      }

}

  1. <a name="vp7G4"></a>
  2. # 基于数组实现栈
  3. <a name="DqAWP"></a>
  4. ## 功能
  5. 先进后出,判空,获取元素个数,查看栈顶
  6. <a name="wj6TR"></a>
  7. ## 代码
  8. 刚好调用之前自定义的数组类,使得自定义栈变得非常简单<br />Stack<E>是自定义接口
  9. ```java
  10. public class ArrayStack<E> implements Stack<E> {
  11. private MyArray<E> array;
  12. public ArrayStack(int capacity){
  13. array = new MyArray<>(capacity);
  14. }
  15. public ArrayStack() {
  16. array = new MyArray<>();
  17. }
  18. @Override
  19. public int getSize() {
  20. return array.getSize();
  21. }
  22. @Override
  23. public boolean isEmpty() {
  24. return array.isEmpty();
  25. }
  26. @Override
  27. public void push(E e) {
  28. array.addLast(e);
  29. }
  30. @Override
  31. public E pop() {
  32. return array.removeLast();
  33. }
  34. @Override
  35. public E peek() {
  36. return array.getLast();
  37. }
  38. @Override
  39. public String toString() {
  40. return "ArrayStack{" +
  41. "array=" + array +
  42. '}';
  43. }
  44. }

基于数组实现队列

功能

先进先出,判空,获取元素个数,获取队头队尾

代码

同样使用自定义数组类实现起来变得很简单
Queue是自定义的接口

  1. public class ArrayQueue<E> implements Queue<E> {
  2. private MyArray<E> array;
  3. public ArrayQueue(int capacity) {
  4. array = new MyArray<>(capacity);
  5. }
  6. public ArrayQueue() {
  7. array = new MyArray<>();
  8. }
  9. @Override
  10. public int getSize() {
  11. return array.getSize();
  12. }
  13. @Override
  14. public boolean isEmpty() {
  15. return array.isEmpty();
  16. }
  17. @Override
  18. public void enqueue(E e) {
  19. array.addLast(e);
  20. }
  21. @Override
  22. public E dequeue() {
  23. return array.removeFirst();
  24. }
  25. @Override
  26. public E getFirst() {
  27. return array.getFirst();
  28. }
  29. @Override
  30. public E getEnd() {
  31. return array.getLast();
  32. }
  33. @Override
  34. public String toString() {
  35. return "ArrayQueue{" +
  36. "array=" + array +
  37. '}';
  38. }

此队列不是循环队列
测试一下每次出队完,后面的元素也覆盖
image.png

问题

出队时,移出队头元素,然后每个元素向前挪一位,时间复杂度是O(N),所以要使用循环队列进行改善

循环队列

注意点

需要定义两个变量front和tail用于指向队头元素和队尾元素下标,tail指向队尾元素的下一个下标

循环队列定义:
队空 front == tail
队满 (tail + 1) % data.length == front
出队 front = (front + 1) % data.length
入队 tail = (tail + 1) % data.length
需要浪费一个空间用于判断
image.png

代码

  1. public class LoopQueue<E> implements Queue<E> {
  2. private E[] data;
  3. private int front;
  4. private int tail;
  5. private int size;
  6. public LoopQueue(int capacity) {
  7. //因为要有意浪费一个数组所以容量要比传来的+1
  8. data = (E[]) new Object[capacity + 1];
  9. front = 0;
  10. tail = 0;
  11. size = 0;
  12. }
  13. public LoopQueue() {
  14. this(10);
  15. }
  16. private int getCapacity() {
  17. return data.length - 1;
  18. }
  19. @Override
  20. public int getSize() {
  21. return size;
  22. }
  23. @Override
  24. public boolean isEmpty() {
  25. return front == tail;
  26. }
  27. @Override
  28. public void enqueue(E e) {
  29. if ((tail + 1) % data.length == front) {
  30. resize(getCapacity() * 2);
  31. }
  32. data[tail] = e;
  33. tail = (tail + 1) % data.length;
  34. size++;
  35. }
  36. private void resize(int newSize) {
  37. E[] newData = (E[]) new Object[newSize + 1];
  38. for (int i = 0; i < size; i++) {
  39. //原数组要通过偏移量获取下标
  40. newData[i] = data[(i + front) % data.length];
  41. }
  42. data = newData;
  43. front = 0;
  44. tail = size;
  45. }
  46. @Override
  47. public E dequeue() {
  48. if (isEmpty()) {
  49. throw new IllegalArgumentException("队列为空");
  50. }
  51. E temp = data[front];
  52. data[front] = null;
  53. front = (front + 1) % data.length;
  54. size--;
  55. //如果数组元素个数为数组容量的4分之1就进行缩容
  56. if (size == getCapacity() / 4 && getCapacity() / 2 != 0) {
  57. resize(getCapacity() / 2);
  58. }
  59. return temp;
  60. }
  61. @Override
  62. public E getFirst() {
  63. if (isEmpty()) {
  64. throw new IllegalArgumentException("队列为空");
  65. }
  66. return data[front];
  67. }
  68. @Override
  69. public E getEnd() {
  70. return data[tail - 1];
  71. }
  72. @Override
  73. public String toString() {
  74. return "LoopQueue{" +
  75. "data=" + Arrays.toString(data) +
  76. ", front=" + front +
  77. ", tail=" + tail +
  78. ", size=" + size +
  79. '}';
  80. }
  81. }