Массивы
Форум |
Назад | Оглавление | Дальше
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
Форум |
Назад | Оглавление | Дальше