数组(Array)是一种线性表数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据。

  1. public class Array<E> {
  2. private E[] data;
  3. private int size;
  4. // 构造函数,传入数组的容量capacity构造Array
  5. public Array(int capacity){
  6. data = (E[])new Object[capacity];
  7. size = 0;
  8. }
  9. // 无参数的构造函数,默认数组的容量capacity=10
  10. public Array(){
  11. this(10);
  12. }
  13. // 获取数组的容量
  14. public int getCapacity(){
  15. return data.length;
  16. }
  17. // 获取数组中的元素个数
  18. public int getSize(){
  19. return size;
  20. }
  21. // 返回数组是否为空
  22. public boolean isEmpty(){
  23. return size == 0;
  24. }
  25. // 在index索引的位置插入一个新元素e
  26. public void add(int index, E e){
  27. if(size == data.length)
  28. throw new IllegalArgumentException("Add failed. Array is full.");
  29. if(index < 0 || index > size)
  30. throw new IllegalArgumentException("Add failed. Require index >= 0 and index <= size.");
  31. for(int i = size - 1; i >= index ; i --)
  32. data[i + 1] = data[i];
  33. data[index] = e;
  34. size ++;
  35. }
  36. // 向所有元素后添加一个新元素
  37. public void addLast(E e){
  38. add(size, e);
  39. }
  40. // 在所有元素前添加一个新元素
  41. public void addFirst(E e){
  42. add(0, e);
  43. }
  44. // 获取index索引位置的元素
  45. public E get(int index){
  46. if(index < 0 || index >= size)
  47. throw new IllegalArgumentException("Get failed. Index is illegal.");
  48. return data[index];
  49. }
  50. // 修改index索引位置的元素为e
  51. public void set(int index, E e){
  52. if(index < 0 || index >= size)
  53. throw new IllegalArgumentException("Set failed. Index is illegal.");
  54. data[index] = e;
  55. }
  56. // 查找数组中是否有元素e
  57. public boolean contains(E e){
  58. for(int i = 0 ; i < size ; i ++){
  59. if(data[i].equals(e))
  60. return true;
  61. }
  62. return false;
  63. }
  64. // 查找数组中元素e所在的索引,如果不存在元素e,则返回-1
  65. public int find(E e){
  66. for(int i = 0 ; i < size ; i ++){
  67. if(data[i].equals(e))
  68. return i;
  69. }
  70. return -1;
  71. }
  72. // 从数组中删除index位置的元素, 返回删除的元素
  73. public E remove(int index){
  74. if(index < 0 || index >= size)
  75. throw new IllegalArgumentException("Remove failed. Index is illegal.");
  76. E ret = data[index];
  77. for(int i = index + 1 ; i < size ; i ++)
  78. data[i - 1] = data[i];
  79. size --;
  80. data[size] = null; // loitering objects != memory leak
  81. return ret;
  82. }
  83. // 从数组中删除第一个元素, 返回删除的元素
  84. public E removeFirst(){
  85. return remove(0);
  86. }
  87. // 从数组中删除最后一个元素, 返回删除的元素
  88. public E removeLast(){
  89. return remove(size - 1);
  90. }
  91. // 从数组中删除元素e
  92. public void removeElement(E e){
  93. int index = find(e);
  94. if(index != -1)
  95. remove(index);
  96. }
  97. @Override
  98. public String toString(){
  99. StringBuilder res = new StringBuilder();
  100. res.append(String.format("Array: size = %d , capacity = %d\n", size, data.length));
  101. res.append('[');
  102. for(int i = 0 ; i < size ; i ++){
  103. res.append(data[i]);
  104. if(i != size - 1)
  105. res.append(", ");
  106. }
  107. res.append(']');
  108. return res.toString();
  109. }
  110. }

查找

时间复杂度 数组支持随机访问,根据下标随机访问的时间复杂度为 O(1)
查找元素快:通过索引,可以快速访问指定位置的元素。

插入

时间复杂度为 O(n),假设数组的长度为 n,现在,如果我们需要将一个数据插入到数组中的第 k 个位置。为了把第 k 个位置腾出来,给新来的数据,我们需要将第 k~n 这部分的元素都顺序地往后挪一位。

删除

时间复杂度为 O(n),

动态扩容

ArrayList是Java集合框架类的一员,可以称它为一个动态数组。它还有一个优势就是将数组的操作封装起来,比如增删查,以及动态扩容。
扩容

    // 在index索引的位置插入一个新元素e
    public void add(int index, E e){

        if(index < 0 || index > size)
            throw new IllegalArgumentException("Add failed. Require index >= 0 and index <= size.");

        if(size == data.length)
            resize(2 * data.length);

        for(int i = size - 1; i >= index ; i --)
            data[i + 1] = data[i];

        data[index] = e;

        size ++;
    }

缩容

 // 从数组中删除index位置的元素, 返回删除的元素
    public E remove(int index){
        if(index < 0 || index >= size)
            throw new IllegalArgumentException("Remove failed. Index is illegal.");

        E ret = data[index];
        for(int i = index + 1 ; i < size ; i ++)
            data[i - 1] = data[i];
        size --;
        data[size] = null; // loitering objects != memory leak

        if(size == data.length / 2)
            resize(data.length / 2);
        return ret;
    }

具体操作函数

 // 将数组空间的容量变成newCapacity大小
    private void resize(int newCapacity){

        E[] newData = (E[])new Object[newCapacity];
        for(int i = 0 ; i < size ; i ++)
            newData[i] = data[i];
        data = newData;
    }

越界

一般数组的下标是从0开始,因此数组的第一个数下标是0 最后一个数的下标是size-1
数组越界在 C 语言中是一种未决行为,并没有规定数组访问越界时编译器应该如何处理。因为,访问数组的本质就是访问一段连续内存,只要数组通过偏移计算得到的内存地址是可用的,那么程序就可能不会报任何错误。
而大多数语言例如JAVA中如果越界则会抛出java.lang.ArrayIndexOutOfBoundsException