Массивы
From AsIsWiki
| Вопросы и ответы |
Большие числа | Основные конструкции Java | Введение в объектно-ориентированное программирование
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
| Вопросы и ответы |
Большие числа | Основные конструкции Java | Введение в объектно-ориентированное программирование