Массивы

From AsIsWiki
Jump to: navigation, search
Форум

Назад | Оглавление | Дальше


Contents

Массивы

Объявить массив можно двумя способами:

int[] a;

int b[];

Для создания массива (выделения под него памяти) используется оператор new:

int[] a = new int[100];

Элементы сформированного выше массива нумеруются от 0 до 99.

После создания, массив можно заполнять (инициализировать):

int[] a = new int[100];

for (int i = 0; i < 100; i++) {
    a[i] = i;
}

Если обратиться к элементу массива с несуществующим индексом (например a[100]), то будет сгенерировано исключение, соответствующее выходу индекса за пределы допустимого диапазона, и программа прекратит работу.

Метод length определяет количество элементов в массиве:

for (int i = 0; i < a.length; i++) {
    System.out.println(a[i]);
}

После создания массива, изменить его размер невозможно.
Для динамического изменения размеров массива следует использовать СПИСКИ.


Цикл "for each"

Этот цикл позволяет перебирать элементы любого набора данных, не применяя счетчик:

for (переменная : набор_данных) {
    выражение
}

В качестве набора данных может использоваться массив или экземпляр класса, реализующий интерфейс Iterable (например ArrayList).

Пример использования цикла "for each":

int[] a = new int[100];

for (int element : a) {
    System.out.println(element);
}

Действия данного цикла можно кратко охарактеризовать как "обработка каждого элемента из a".
Переменная цикла в выражении "for each" перебирает не значения индекса, а элементы массива.


Инициализация массивов и анонимные массивы

Для одновременного создания и инициализации массива используется следующая синтаксическая конструкция:

int[] smallPrimes = {2, 3, 5, 7, 11, 13};

В этом случае оператор new не нужен.

Кроме того, можно инициализировать массив, не имеющий имени - анонимный массив:

new int[] {16, 19, 23, 29, 31, 37};

Данное выражение выделяет память для нового массива и заполняет его числами.
Такую конструкцию удобно применять для повторной инициализации массива без создания новой переменной, например:

int[] smallPrimes = {2, 3, 5, 7, 11, 13};

smallPrimes = new int[] {16, 19, 23, 29, 31, 37};

Повторная инициализация аналогична следующим действиям:

int[] anonymous = {16, 19, 23, 29, 31, 37};

smallPrimes = anonymous;

При необходимости можно создать массив нулевого размера:

new тип_элементов[0]

Нулевой массив может быть полезен при написании метода, периодически возвращающего пустой массив.

Нулевой массив не эквивалентен объекту null.


Копирование массивов

Массивы можно копировать, при этом копии будут ссылаться на один и тот же массив:

int[] luckyNumbers = smallPrimes;

luckyNumbers[5] = 12;  // теперь smallPrimes[5] также равен 12

Метод arraycopy() из класса System копирует все элементы одного массива в другой:

System.arraycopy(from, fromIndex, to, toIndex, count);

Массив to должен иметь достаточный размер, чтобы в нем поместились все копируемые элементы.

Пример копирования массивов:

int[] smallPrimes = {2, 3, 5, 7, 11, 13};

int[] luckyNumbers = {1001, 1002, 1003, 1004, 1005, 1006, 1007};

System.arraycopy(smallPrimes, 2, luckyNumbers, 3, 4);

for (int i = 0; i < luckyNumbers.length; i++) {
    System.out.println(i + ": " + luckyNumbers[i]);
}

Результат:

0: 1001
1: 1002
2: 1003
3: 5
4: 7
5: 11
6: 13

Массив Java можно условно сравнить с указателем на динамически созданный массив C++:

int[] a = new int[100];  // Java

int* a = new int[100];   // C++

Однако следующие выражения существенно различаются:

int[] a = new int[100];  // Java

int a[100];              // C++

В Java оператор [] по умолчанию проверяет диапазон изменения индексов.
В Java нельзя увеличить указатель "a", чтобы обратиться к следующему элементу массива (не поддерживается арифметика указателей).


Параметры командной строки

Используя параметр "String[] args", метод main() получает из командной строки массив параметров.
Рассмотрим этот механизм на примере следующей программы:

public class Message {

    public static void main(String[] args) {

        if (args[0].equals("-h")) {
            System.out.print("Hello, ");
        } else {
            if (args[0].equals("-g")) {
                System.out.print("Goodbye, ");
            }
        }

        // Вывод остальных параметров командной строки.
        for (int i = 1; i < args.length; i++) {
            System.out.print(" " + args[i]);
        }

        System.out.print("!");
    }
}

При следующем вызове программы:

java Message -g cruel world

массив args будет состоять из таких элементов:

args[0]: "-g"
args[1]: "cruel"
args[2]: "world"

Слова "java" и "Message" параметрами командной строки не считаются и в массив args не передаются.
После запуска, программа выведет сообщение:

Goodbye, cruel world!


Сортировка массива

Метод sort() из класса Arrays упорядочивает массив чисел:

int[] a = new int[10000];

Arrays.sort(a);

Следующая программа создает массив и генерирует случайную комбинацию чисел для лотереи:

import java.util.*;

public class LotteryDrawing {

    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);

        System.out.print("Число номеров? ");
        int k = in.nextInt();

        System.out.print("Максимальный номер? ");
        int n = in.nextInt();

        // Заполнение массива числами 1 2 3 ... n
        int[] numbers = new int[n];

        for (int i = 0; i < numbers.length; i++) {
            numbers[i] = i + 1;
        }

        // Выбор k номеров и запись их в другой массив
        int[] result = new int[k];

        for (int r, i = 0; i < result.length; i++) {
            // Генерация случайного индекса между 0 и n - 1
            r = (int) (Math.random() * n);

            // Выбор случайного элемента
            result[i] = numbers[r];

            // Копирование последнего элемента
            numbers[r] = numbers[n - 1];
            n--;  // в следующей итерации
                  // диапазон генерации случайного числа уменьшается на 1
        }

        // Вывод отсортированного массива
        Arrays.sort(result);

        System.out.println("Попробуйте такую комбинацию: ");

        for (int r : result) {
            System.out.println(r);
        }
    }
}

Например, если нужно выиграть 6 из 49, программа может вывести сообщение:

Попробуйте такую комбинацию:
4
7
8
19
30
44

Метод Math.random() возвращает случайное вещественное число из диапазона: 0 <= x < 1

Метод random() может сгенерить индекс повторно.
Для избежания дубликатов в результирующем массиве, каждый скопированный номер исходного массива перезаписывается номером, который еще не был скопирован.
В данном случае берется номер с индексом n - 1, после чего диапазон генерации очередного индекса уменьшается: n--


Многомерные массивы

Объявление двумерного массива (матрицы):

double[][] balances;

Инициализация матрицы:

balances = new double[NYEARS][NRATES];

Если элементы массива известны, можно инициализировать его без оператора new:

int[][] magicSquare = {
    {16, 3, 2, 13},
    {5, 10, 11, 8},
    {9, 6, 7, 12},
    {4, 15, 14, 1}
};

Обращение к отдельным элементам матрицы:

balances[i][j]

Следующая программа создает таблицу, показывающую, как возрастает первоначальная инвестиция объемом $10000 при разных процентных ставках, если прибыль ежегодно выплачивается и реинвестируется:

public class CompoundInterest {

    public static void main(String[] args) {

        final int STARTRATE = 10;
        final int NRATES = 6;
        final int NYEARS = 10;

        // Установка процентной ставки 10 ... 15%
        double[] interestRate = new double[NRATES];

        for (int j = 0; j < interestRate.length; j++) {
            interestRate[j] = (STARTRATE + j) / 100.0;
        }

        double[][] balances = new double[NYEARS][NRATES];

        // Исходная сумма равна $10000
        for (int j = 0; j < balances[0].length; j++) {
            balances[0][j] = 10000;
        }

        // Вычисление баланса на следующие годы
        for (int i = 1; i < balances.length; i++) {
            for (int j = 0; j < balances[i].length; j++) {
                // Извлечение баланса за прошлый год
                double oldBalance = balances[i - 1][j];

                // Вычисление процентного дохода
                double interest = oldBalance * interestRate[j];

                // Вычисление баланса за текущий год
                balances[i][j] = oldBalance + interest;
            }
        }

        // Вывод процентных ставок
        for (int j = 0; j < interestRate.length; j++) {
            System.out.printf("%9.0f%%", 100 * interestRate[j]);
        }

        System.out.println();

        // Вывод таблицы
        for (double[] row : balances) {
            // Вывод строки таблицы
            for (double b : row) {
                System.out.printf("%10.2f", b);
            }

            System.out.println();
        }
    }
}

Результат:

     10%       11%       12%       13%       14%       15%
10000,00  10000,00  10000,00  10000,00  10000,00  10000,00
11000,00  11100,00  11200,00  11300,00  11400,00  11500,00
12100,00  12321,00  12544,00  12769,00  12996,00  13225,00
13310,00  13676,31  14049,28  14428,97  14815,44  15208,75
14641,00  15180,70  15735,19  16304,74  16889,60  17490,06
16105,10  16850,58  17623,42  18424,35  19254,15  20113,57
17715,61  18704,15  19738,23  20819,52  21949,73  23130,61
19487,17  20761,60  22106,81  23526,05  25022,69  26600,20
21435,89  23045,38  24759,63  26584,44  28525,86  30590,23
23579,48  25580,37  27730,79  30040,42  32519,49  35178,76

Программа сохраняет процентные ставки в массиве interest, а баланс для каждого года и каждой процентной ставки - в матрице balance.
Первая строка матрицы инициализируется исходной суммой:

for (int j = 0; j < balances[0].length; j++) {
    balances[0][j] = 10000;
}

Далее подсчитывается содержимое остальных строк:

for (int i = 1; i < balances.length; i++) {
    for (int j = 0; j < balances[i].length; j++) {
        double oldBalance = balances[i - 1][j];
        double interest = oldBalance * interestRate[j];
        balances[i][j] = oldBalance + interest;
    }
}

Цикл "for each" не способен управлять двумерным массивом, он лишь перебирает строки матрицы (одномерные массивы).
Для обработки всех элементов матрицы требуется два цикла "for each":

for (double[] row : balances) {
    for (double b : row) {
        System.out.printf("%10.2f", b);
        System.out.println();
    }
}


"Неровные" массивы

Многомерные массивы Java - это "массивы массивов".

В предыдущем примере, массив balances состоял из 10 одномерных массивов, содержащих вещественные числа.

Выражение balances[i] определяет i-й подмассив (строку таблицы), а выражение balances[i][j] ссылается на j-й элемент этой строки.

Строки матрицы можно легко переставлять:

double[] temp = balances[i];

balances[i] = balances[i + 1];

balances[i + 1] = temp;

В Java можно создавать "неровные" массивы, имеющие строки разной длины.

Следующая программа создает массив, каждый элемент которого равен количеству возможностей "выбрать" j чисел из i:

public class LotteryArray {

    public static void main(String[] args) {

        final int NMAX = 10;

        // Выделение памяти для треугольной матрицы
        int[][] odds = new int[NMAX + 1][];

        for (int n = 0; n <= NMAX; n++) {
            odds[n] = new int[n + 1];
        }

        // Заполнение треугольной матрицы
        for (int n = 0; n < odds.length; n++) {
            for (int k = 0; k < odds[n].length; k++) {
                /*
                 * Вычисление выражения
                 * n * (n - 1) * (n - 2) * ... * (n - k + 1)
                 * -----------------------------------------
                 *            1 * 2 * 3 * ... * k
                 */

                int lotteryOdds = 1;

                for (int i = 1; i <= k; i++) {
                    lotteryOdds = lotteryOdds * (n - i + 1) / i;
                }

                odds[n][k] = lotteryOdds;
            }
        }

        // Вывод треугольной матрицы
        for (int[] row : odds) {
            for (int odd : row) {
                System.out.printf("%4d", odd);
            }

            System.out.println();
        }
    }
}

Результат:

    0   1   2   3   4   5   6   7   8   9   10
  |-------------------------------------------
0 | 1
1 | 1   1
2 | 1   2   1
3 | 1   3   3   1
4 | 1   4   6   4   1
5 | 1   5  10  10   5   1
6 | 1   6  15  20  15   6   1
7 | 1   7  21  35  35  21   7   1
8 | 1   8  28  56  70  56  28   8   1
9 | 1   9  36  84 126 126  84  36   9   1
10| 1  10  45 120 210 252 210 120  45  10   1

Т.к. j не может превышать i, получается треугольная матрица.
В i-ой строке матрицы находится i+1 элементов.
Единственным способом можно выбрать и 0 элементов.

Первым шагом создается массив для хранения строк:

int[][] odds = new int[NMAX + 1][];

Далее, в него помещаются строки:

for (int n = 0; n <= NMAX; n++) {
    odds[n] = new int[n + 1];
}

Теперь можно обращаться к элементам массива, при условии, что индексы не выходят за пределы допустимого диапазона:

for (int n = 0; n < odds.length; n++) {
    for (int k = 0; k < odds[n].length; k++) {
        // Вычисление вариантов
        ...
        odds[n][k] = lotteryOdds;
    }
}

В Java объявление:

double[][] balances = new double[10][6];  // Java

не эквивалентно объявлению:

double balances[10][6];  // C++

и даже не соответствует:

double (*balances)[6] = new double[10][6];  // C++

Вместо этого, в памяти размещается массив из 10 указателей. В C++ это выглядит так:

double** balance = new double*[10];  // C++

Далее, каждый элемент в массиве указателей заполняется массивом из 6 чисел:

for (i = 0; i < 10; i++) {
    balances[i] = new double[6];
}

Данный цикл выполняется автоматически, при объявлении массива с помощью оператора new double[10][6].
В случае "неровных" массивов, строки следует формировать отдельно.


Справочник

java.lang.System

static void arraycopy(Object from, int fromIndex, Object to, int toIndex, int count)  // копирует массив from в массив to

Параметры:
  from - исходный массив любого типа
  fromIndex - индекс, с которого начинается копирование
  to - массив, имеющий тот же тип, что и массив from
  toIndex - индекс, с которого заносятся элементы в целевой массив
  count - количество копируемых элементов


java.util.Arrays

static void sort(тип[] a)  // упорядочивает массив с помощью алгоритма быстрой сортировки

Параметры:
  a - массив типа int, long, short, char, byte, boolean, float, double
static int binarySearch(тип[] a, тип v)  // бинарный поиск величины v (возвращается его индекс)

Если элемент не найден, то возвращается отрицательное значение r
(индекс |r| - 1 место гипотетического расположения значения v в массиве a)

Параметры:
  a - упорядоченный массив типа int, long, short, char, byte, boolean, float, double
  v - значение того же типа, что и элементы массива a
static void fill(тип[] a, тип v)  // заполняет массив a значением v

Параметры:
  a - массив типа int, long, short, char, byte, boolean, float, double
  v - значение того же типа, что и элементы массива a
static boolean equals(тип[] a, тип[] b)  // возвращает true, если массивы имеют одинаковую длину
                                           и элементы с соответствующими индексами совпадают
Параметры:
  a, b - массивы типа int, long, short, char, byte, boolean, float, double



Форум

Назад | Оглавление | Дальше

Personal tools
Namespaces

Variants
Actions
Navigation
Tools