程序布局 - 通过System.in.read创建适当大小的数组

时间:2012-11-21 23:17:50

标签: java arrays loops

以下显然是非常不切实际的,但我的讲师坚持教我们对编程的基本理解。他给我们的练习是这样的:

仅使用System.in.read,int,char和循环,创建一个读取的方法    用户从命令行输入并返回一个与金额完全一样大的char []    输入的字符数。不要使用System.arraycopy()或其他库方法。

我很无能为力。由于似乎无法缓冲System.in.read输入,因此在解析任何字符之前,数组必须具有完美的大小。这个世界应该如何运作?

3 个答案:

答案 0 :(得分:1)

  

创建一个从命令行读取用户输入并返回char []

的方法

再想一想,我假设您应该通过自己种植char[]数组来进行自己的输入缓冲。这应该是提到System.arraycopy()的原因。

增长数组就像

一样
  • 创建一个比现有数组长1个项目的新数组。
  • 表示旧数组中的每个字符
    • 将字符从旧数组复制到新数组,保持位置
  • 用成长的数组替换旧数组。

如果你将它与一个读取输入流中所有字符的循环结合起来,你可以得到以下内容,并且应该完成你的任务。

  • 从长度为0的数组开始
  • while inputstream中提供的字符
    • 将数组增大一个
    • 将输入流中的字符放入数组的最后一个插槽
  • 返回数组

甚至可以在没有循环和增长数组的情况下完成它。只需创建一次正确大小的新数组。

private static char[] readToCharArray(int length) throws IOException {
    int read = System.in.read();
    char[] result;
    if (read == -1 || read == '\r' || read == '\n' ) {
        result = new char[length];
    } else {
        result = readToCharArray(length + 1);
        result[length] = (char) read;
    }
    return result;
}

char[] myArray = readToCharArray(0);

答案 1 :(得分:0)

手动阵列复制怎么样,文中没有说什么呢?如果允许你可以做这样的事情:

    private static char[] readInput() throws IOException {
      System.out.println("type something terminated with '|'");
      char[] input = new char[0];
      int count = 0;
      int read;
      for (; ; ) {
        read = System.in.read();
        if (read == '|') {
          break;
        } else {
          char[] tmp = new char[input.length + 1];
          for (int i = 0; i < input.length; i++) {
            tmp[i] = input[i];
          }
          input = tmp;
        }
        input[count] = (char) read;
        count++;
      }
      return input;
    }

您还可以检查read == -1而不是read == '|',但输入结束字符因系统而异。您可以在每次迭代中复制char [],而不是在每次迭代时复制char [],然后在最后创建一个正确大小的数组。你也可以使用while循环...

但是如果建议zapl返回一个正确大小的空数组肯定会更有趣:)

答案 2 :(得分:0)

我将假设你的讲师意味着:

  • char []应该包含从System.in读取的字符(不仅仅是正确的大小)
  • System.in.read”仅指InputStream#read()而不是read上的其他重载InputStream方法,因此您一次只能阅读一个字符。

您应该看看ArrayList的实施方式。它由一个数组支持,但该列表可以任意调整大小。当列表的大小超过数组大小时,ArrayList会创建一个更大的新数组,然后将旧数组的内容复制到其中。以下是ArrayList的一些相关摘录:

/**
 * Appends the specified element to the end of this list.
 *
 * @param e element to be appended to this list
 * @return <tt>true</tt> (as specified by {@link Collection#add})
 */
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

private void ensureCapacityInternal(int minCapacity) {
    modCount++;
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

/**
 * Increases the capacity to ensure that it can hold at least the
 * number of elements specified by the minimum capacity argument.
 *
 * @param minCapacity the desired minimum capacity
 */
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

由于您无法使用System.arraycopy(),因此您需要编写自己的方法来执行此操作。这只是一个for循环。

这实际上并不是效率低下的。正如javadoc所描述的那样,ArrayList#add(E)以分摊的常量时间运行。

如果您完全遵循ArrayList策略,那么您生成的数组将大于它需要的数量,所以最后,您需要在结尾处再做一次数组调整以将其截断为确切的输入大小。或者,每次读取一个字符时,你可以将数组增加1,但是输入长度的运行时间将是二次(n ^ 2)而不是线性(n)。