• 算法与数据结构(第三周)——数据结构基础:动态数组


    目录

    数组

    使用 Java 中的数组

    二次封装属于我们自己的数组

    向数组中添加元素

    数组末添加元素

    指定位置添加元素

    查询元素和修改元素

    数组中包含和搜索

    数组中删除

    泛型类

    动态数组

    简单的复杂度分析


    数组

    使用 Java 中的数组

    声明十个元素的数组,并进行赋值操作

    1. int[] arr = new int[10];
    2. for (int i = 0; i < arr.length; i++) {
    3. arr[i] = i;
    4. }

    数组在声明的时候就有初始值

    1. int[] scores = new int[]{100,99,66};
    2. for(int i=0;i< scores.length ; i ++)
    3. System.out.println(scores[1]);
    4. for(int score: scores)//增强for
    5. System. out. println(score);

    二次封装属于我们自己的数组

            数组最大的优点:快速查询,例如scores[2]表名学号为2的学生分数,所以数组最好应用于“索引有语意'的情况。但并非所有有语意的索引都适用于数组,例如身份证号不适合作索引。

            JAVA原本的数组是静态数组,我们将其二次封装为动态数组。我们将会创建Array类,对其中的data数组进行增删改查。

    size:数组实际使用的容量。capacity:数组容量。

    构造函数初始化数组,并进行简单的操作:

    1. public class Array {
    2. private int[] data;
    3. private int size;
    4. //构造函数,传入数组的容量capacity构造Array
    5. public Array(int capacity) {
    6. data = new int[capacity];
    7. size = 0;
    8. }
    9. //无参数的构造函数,默认数组的容量capacity=10
    10. public Array() {
    11. this(10); //用户没必要非要传入一个容量参数,我们将其默认设定
    12. }
    13. //获取数组中的元素个数
    14. public int getSize(){
    15. return size;
    16. }
    17. //获取数组的容量
    18. public int getCapacity(){
    19. return data.length;
    20. }
    21. //判空
    22. public boolean isEmpty(){
    23. return size == 0;
    24. }
    25. }

    向数组中添加元素

    数组末添加元素

    1. //向所有元素后添加一个新元素
    2. public void addLast(int e){
    3. if(size == data.length)
    4. throw new IllegalArgumentException("AddLast failed. Array is full.");
    5. data [size] = e;
    6. size++;
    7. //data [size++] = e;
    8. }

    指定位置添加元素

    注意:

    1.不能直接在指定位置添加元素,否则会对原有元素覆盖

    2.对指定位置及其之后的元素后移

    3.添加之后记得size++

    1. //在第Index个位置插入一个新元素e
    2. public void add(int index, int e) {
    3. if (size == data.length)
    4. throw new IllegalArgumentException("Add faiLed. Array is full.");
    5. if (index < 0 || index > size)
    6. throw new IllegalArgumentException("Add failed. Require index >= 0 and index <= size");
    7. //每一个元素都向后挪一个位置,直到挪到index这个元素
    8. //注意此时index位置上并不是没有元素,index位置上还是原来的元素,只是现在可以放心的将这个位置上的元素覆盖掉了
    9. for (int i = size - 1; i >= index; i--) {
    10. data[i + 1] = data[i];//后一个索引位置赋上前一个索引元素
    11. }
    12. data[index] = e;
    13. size++;
    14. }

    addLast方法也可以复用add方法:

    1. //向所有元素后添加一个新元素
    2. public void addLast(int e){
    3. add(size, e);
    4. }

    查询元素和修改元素

    toString方法打印数组:

    1. @Override
    2. public String toString(){
    3. StringBuilder res = new StringBuilder();
    4. res.append(String. format("Array: size = %d,capacity = %d\n", size, data));
    5. res. append('[');
    6. for(int i=0 ;1< size ;i ++){
    7. res.append(data[i]);
    8. if(i != size-1)
    9. res.append(", ");
    10. }
    11. res.append(']');
    12. return res.toString();
    13. }

    测试:

    1. public class Main {
    2. public static void main(String[] args) {
    3. Array arr = new Array(20);
    4. for (int i = 0; i < 10; i++)
    5. arr.addLast(i);
    6. System.out.println(arr);
    7. arr.add(1, 100);
    8. System.out.println(arr);
    9. }
    10. }

    获取和修改:

    1. //获取index索引位置的元素
    2. int get(int index){
    3. if (index<0||index>=size)
    4. throw new IllegalArgumentException("Get failed. Index is illegal");
    5. return data[index];
    6. }
    7. //修改index索引位置的元素
    8. void set(int index,int e){
    9. if (index<0||index>=size)
    10. throw new IllegalArgumentException("Set failed. Index is illegal");
    11. data[index] = e;
    12. }

    数组中包含和搜索

    1. //查找数组中是否有元素e
    2. public boolean contains(int e){
    3. for(int i=0;i
    4. if(data[i] == e)
    5. return true;
    6. }
    7. return false;
    8. }
    9. //查找数组中元素e所在的索引,如果不存在元素e,则返回-1
    10. public int find(int e){
    11. for(int i=0 ;i
    12. if(data[i] == e)
    13. return i;
    14. }
    15. return -1;
    16. }

    数组中删除

    指定索引:

    1. //从数组中删除index位置的元素,返回删除的元素
    2. public int remove(int index){
    3. if (index<0||index>=size)
    4. throw new IllegalArgumentException("Remove failed.Index id illegal.");
    5. int ret = data[index];
    6. for(int i = index+1; i < size; i++) {
    7. data[i-1] = data[i];
    8. }
    9. size--;
    10. return ret;
    11. }
    12. //从数组中删除第一个元素,返回删除的元素
    13. public int removeFirst(){
    14. return remove(0);
    15. }
    16. //从数组中删除最后一个元素,返回删除的元素
    17. public int removeLast(){
    18. return remove(size - 1);
    19. }
    20. //从数组中删除元素e
    21. public void removeElement(int e){
    22. int index = find(e);
    23. if(index != -1)
    24. remove( index);
    25. }

    注意:

    1.要删除的这个元素的位置后面的元素都要上左移动

    2.删除任务结束之后size--

            size既表示有多少元素,又表示第一个没有元素的位置,也就是说如果要向整个数组末尾添加元素的时候,就要添加到size的位置。

    2.size下有元素是没有问题的,因为用户是看不到size所指元素的(用户指定的索引要满足index>=0&&index

    测试:

    1. arr.remove(2):
    2. System.out.println(arr);
    3. arr.removeELement(4);
    4. System.out.println(arr);
    5. arr.removeFirst();
    6. System.out.println(arr);

    泛型类

    表示Array盛放的数据类型为E,至于这个E是什么,则可以在具体使用的时候再进行声明。

    修改为泛型之后的完整代码:

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

    再次声明:Array arr = new Array<>(20);

    将Student类作为泛型:

    动态数组

            假设现在有一个空间为4的数组并且已经装满了,如果再添加元素将会抛出异常。但是我们可以进行其他操作。

            我们可以再开创一个新数组,新数组的容量比原来要大一些,capacity变为8,size不变,将data指向新数组,此时data和newdata指向的是同一片内存空间。这一整个过程封装在一个函数当中,当函数执行完毕之后newdata就失效了,而data是全局变量,保持指向新数组。那么原来的旧数组因为没人指着了,JAVA的垃圾回收机制会将其回收。

    1. //私有方法,用户不能自己来调用
    2. private void resize(int newCapacity){
    3. E[] newData = (E[]) new Object[newCapacity];
    4. for (int i = 0; i < size; i++)
    5. newData[i] = data[i];
    6. data = newData;
    7. }

     添加元素:

    1. //在第Index个位置插入一个新元素e
    2. public void add(int index, E e) {
    3. if (index < 0 || index > size)
    4. throw new IllegalArgumentException("Add failed. Require index >= 0 and index <= size");
    5. if (size == data.length)
    6. // throw new IllegalArgumentException("Add faiLed. Array is full.");//当数组满了之后不载抛出异常,而是将其增加空间
    7. resize(2* data.length); //扩容
    8. //每一个元素都向后挪一个位置,直到挪到index这个元素
    9. for (int i = size - 1; i >= index; i--) {
    10. data[i + 1] = data[i];//后一个索引位置赋上前一个索引元素
    11. }
    12. data[index] = e;
    13. size++;
    14. }

    测试:

    1. public class Main {
    2. public static void main(String[] args) {
    3. Array arr = new Array<>(10);
    4. for (int i = 0; i < 10; i++)
    5. arr.addLast(i);
    6. System.out.println(arr);
    7. arr.add(1, 100);//满了之后再次增加元素
    8. System.out.println(arr);
    9. }
    10. }

    在删除操作当中也可以resize:

    1. //从数组中删除index位置的元素,返回删除的元素
    2. public E remove(int index){
    3. if (index<0||index>=size)
    4. throw new IllegalArgumentException("Remove failed.Index id illegal.");
    5. E ret = data[index];
    6. for(int i = index+1; i < size; i++) {
    7. data[i-1] = data[i];
    8. }
    9. size--;
    10. data[size] = null;
    11. //当数组删除到只剩下数组空间的二分之一时
    12. if (size == data.length/2)
    13. resize(data.length/2);//缩小容量
    14. return ret;
    15. }

    简单的复杂度分析

            对于增删的操作,如果只对最后一个元素操作则是只需要O(1),之所以还是O(n),是因为还有resize操作,需要把整个数组元素复制一遍。 

  • 相关阅读:
    初次接触Sharding-JDBC并实际应用
    redis之发布与订阅
    微生物共现网络可视化:实现布局自由
    扩展欧几里得(acwing877)
    剖析虚幻渲染体系(14)- 延展篇:现代渲染引擎演变史Part 1(萌芽期)
    vue3使用echarts5.3.3无法正常使用折线图
    概率论介绍
    腾讯云数据库公有云市场稳居TOP 2!
    VM虚拟机 13.5 for Mac
    一个简单利用WebGL绘制频谱瀑布图示例
  • 原文地址:https://blog.csdn.net/m0_52601969/article/details/127106735