..

如何构造类似数组的数据结构?_System

介绍

在开始解决数组问题之前,理解并实现类似数组的数据结构是一个很好的实践。

本课教您如何实现常见的数组操作,例如插入元素、删除元素、获取元素、求数组长度以及打印数组元素。

我们正在建设什么?

我们将从头开始构建一个数组,其中包含一些最常见的数组操作,如上所述。

我们还将学习如何通过调整方法将固定大小的数组转换为动态数组。这就是动态数组的概念:LinkedListArrayList、 以及一些更复杂的数据结构。

软件中的每个需求都被分成几个部分,我们对每个部分进行处理,最后将它们组合在一起。那么让我们分解一下需求。

问题陈述

从头开始构建一个数组并将元素存储在其中。该数组应该允许插入、删除、获取和打印元素。

Input:
CREATE -> 10 // create an array with capacity 10
INSERT -> {1, 2, 3, 4, 5} // insert these elements
DELETE -> 2 // remove 2nd index element
GET -> 0 // print 0th element
SIZE -> `.size()` // should print how many items currently an array has
PRINT -> // print all elements shown in output

Output: 
{1, 2, 4, 5, 0, 0, 0, 0, 0, 0}


需求细目

当被问到或遇到问题时,将要求写在纸上。

我们的要求是:

  1. 创建一个数组。
  2. 该数组应该具有以下方法。
  • insert()
  • remove()
  • get()
  • size()
  • print()
  1. 使数组自动调整大小(在下一篇文章中介绍)。
  2. 错误处理(可选,但当您与面试官一起构建数组时,它会增加价值)。我们有我们的要求。让我们来分解一下这个问题。

始终将问题分解为更小的块。构建较小的零件并将它们组合起来以完成要求将很容易。

阵列构建

创建数组

创建一个具有两个字段/属性的数组int[] datasize. 用于初始化数组大小的构造函数。

public class Array {
  private int[] data;
  private int size;

  public Array(int capacity) {
    data = new int[capacity];
    size = 0;
  }
}


我们size = 0为基于零索引的数组初始化了 , 。当我们将元素插入数组时,我们是从索引插入它们0

我们创建了一个基Array类,我们需要编写一些需要在我们创建的自定义数组数据结构上执行的基本数组操作。

插入一个元素

我们需要编写一个将项目插入数组的方法。

public void insert(int element) {  
  data[size] = element;  
  size += 1;  
}


或者您可以使用指定简写语法:

public void insert(int element) {  
  data[size++] = element; 
}


0我们在构造函数中初始化了数组大小。因此第一个元素存储在0索引中。

当我们调用 时data[size] = element,我们将一个项目存储在数组中的第0th 索引处。

在下一行中,我们有size += 1,它将大小变量从0增加到1。因此下一个项目将存储在下一个槽中。

如果我们想在中间索引或起始索引插入元素怎么办?我们需要替换该槽中的该元素吗?或者我们应该移动元素并在槽中插入一个元素?

在接下来的课程中,您将学习如何在数组中编写移位算法来插入元素。😅

删除特定索引处的元素

我们的类似数组的数据结构应该处理删除项目。

index如果提供给该remove()方法的值为负数或大于数组的大小怎么办?我们遇到了ArrayIndexOutOfBoundsException

如果提供的索引为负数或大于数组的大小,我们会故意抛出IndexOutOfBoundsException()。或者,我们可以通过提供在控制台或应用程序日志上打印的错误消息来向记录器添加消息。

if (index < 0 || index >= size) {  
  throw new IndexOutOfBoundsException();
}


错误处理到位后,我们可以从索引中删除一个元素,并将所有数组元素向左移动。

还有什么需要我们照顾的吗?我们需要使用size来减少变量值。1size--

完成所有这些更改后,remove()方法如下所示:

public void remove(int index) {  
  if (index < 0 || index >= size) {  
    throw new IndexOutOfBoundsException();  
  }

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


那么我们为什么要改变元素呢?

假设我们要删除/删除中间或起始索引中的元素?如上所述。在这种情况下,我们需要从给定索引中删除该元素,并将所有右侧元素向左移动一位以填充已删除的槽。

在接下来的课程中,您将学习如何在数组中编写移位算法。😅

获取特定索引处的项目

这与上面的解释没有什么不同。我们需要检查给定的值是否为负数或大于数组的大小。无论哪种情况,我们都会遇到ArrayIndexOutOfBoundsException

该方法如下所示:

public int get(int index) {
  if (index < 0 || index >= size) {
    throw new IndexOutOfBoundsException();
  }

  return data[index];
}


数组大小

这非常简单。在所有数组操作中,当我们需要删除/删除元素时,我们会减少大小,而当我们向数组添加新元素时,我们会增加大小。所以直接返回size给我们结果。

public int size() {  
  return size;  
}


打印数组项

一个简单的 for 循环,用于迭代所有数组元素并显示它们。

public void print() {
  for (int i = 0; i < data.length; i += 1) {
    System.out.println(data[i]);
  }
}


具有增强的 for 循环的相同代码是:

public void print() {
  for (int el : data) {
    System.out.println(el);
  }
}


最后看看我们定制的类似阵列的 DS

所有这些较小的块被组合起来,我们构建的最终数组是:

package dev.ggorantala.ds.arrays;

public class Array {
  private int[] data;
  private int size;

  public Array(int capacity) {
    data = new int[capacity];
    size = 0;
  }

  public void insert(int element) {
    data[size] = element;
    size++;
  }

  public boolean isOutOfBounds(int index) {
    return index < 0 || index >= size;
  }

  public void remove(int index) {
    if (isOutOfBounds(index)) {
      throw new IndexOutOfBoundsException();
    }

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

  public int get(int index) {
    if (index < 0 || index >= size) {
      throw new IndexOutOfBoundsException();
    }
    return data[index];
  }

  public int size() {
    return size;
  }

  public void print() {
    for (int i = 0; i < data.length; i += 1) {
      System.out.print(data[i] + ", ");
    }
  }
}


数组执行类

capacity让我们用as创建一个数组并在其中10插入数字,数组的 就变成了。5size5

插图的

简单说明如下:

如何构造类似数组的数据结构?_ci_02

另一个阐明数组capacitysize数组之间差异的插图。

如何构造类似数组的数据结构?_System_03

你认为索引5到索引9存储了什么?答案是零

所以0的存储是从索引59。因此,当您访问时,A[6]您会得到0,因为A[2]您会得到3,等等。

在上面,我们构建了一个Array类和基本操作insertremovegetsize。让我们测试每个方法以确保我们的代码没有任何问题。

代码

以下是执行类

package dev.ggorantala.ds.arrays;

public class ArrayExecution {
  private static final int[] INPUT = new int[] {1, 2, 3, 4, 5};

  public static void main(String[] args) {
    Array array = new Array(10);
    for (int value : INPUT) {
      array.insert(value);
    }

    array.remove(2); // removed element `3` from array

    System.out.println(array.get(0)); // 1
    System.out.println(array.size()); // 4

    // The extra o's are because of the array capacity which is 10
    array.print(); // 1, 2, 4, 5, 0, 0, 0, 0, 0, 0
  }
}


解释

Array array = new Array(10);创建一个容量为 的数组10

我们声明的输入数组保存5元素。

private static final int[] INPUT = new int[] {1, 2, 3, 4, 5};


使用简单的 for 循环,我们将INPUT数据存储到新创建的array实例变量中。

for (int value : INPUT) {
  array.insert(value);
}


2我们使用删除了索引处的元素array.remove(2);

最后,我们调用get,sizeprint方法在控制台上显示数据。