Рекурсия, итерация и оценки сложности алгоритмов
Массивы в языке Java
Язык Java, так же как и многие другие языки, позволяет работать с массивами элементов различных типов. Массив (array) используют, когда возникает необходимость хранить несколько однотипных значений, например, 50 целых чисел или 100 наименований книг, так как было бы неудобно использовать в таких случаях различные имена для всех этих переменных. В ближайшее время мы будем работать только с одномерными массивами и не будем пользоваться тем, что массивы — динамические структуры данных. Об этом речь пойдет в третьей главе книги.
Рассмотрим следующую простейшую задачу на работу с массивом целых чисел.
Задача 5.6. Напишите программу, которая вводит с клавиатуры непустой массив целых чисел, печатает его, затем инвертирует (то есть меняет местами первый элемент с последним, второй — с предпоследним и т.д.), и вновь печатает.
Текст программы
public class InvArr { public static void main(String[] args) throws Exception { int n, i, a[]; n = Xterm.inputInt("Введите длину массива n -> "); a = new int[n]; for (i=0; i<n; i++) a[i] = Xterm.inputInt("Введите a[" + i + "] -> "); Xterm.print("Введенный массив a ="); for (i=0; i<n; i++) Xterm.print(" " + a[i]); Xterm.print("\nИнвертированный массив a ="); for (i=0; i<n/2; i++) { int j = a[i]; a[i] = a[n-1-i]; a[n-1-i] = j; } for (i=0; i<n; i++) Xterm.print(" " + a[i]); Xterm.print("\n"); } }
Как видно из текста этой программы, для того чтобы завести массив, необходимо объявить его и зарезервировать затем память для его элементов с помощью оператора new. В этом случае все они будут автоматически проинициализированы нулевыми значениями. Массив из трех целых чисел, содержащий величины 3, 7 и 11, можно задать так:
Элементы любого массива нумеруются с нуля, а для доступа к -му его элементу используется выражение . Язык Java отслеживает все попытки обратиться к несуществующему элементу массива — при попытке работать, скажем с , возникает исключительная ситуация ( выход индекса за границу массива ), так как последний элемент имеет индекс , а не .
В качестве более содержательного комментария к программе инвертирования массива заметим, что выполнение цикла, переставляющего элементы, завершается, как только будет достигнута середина массива. Если условие продолжения цикла заменить на , то процесс обмена не завершится после того, как массив уже будет инвертирован, и обмен элементов продолжится, что приведет к двукратному инвертированию массива, что эквивалентно тождественному преобразованию.
Рассмотрим еще одну задачу.
Задача 5.7. Напишите программу, печатающую максимальный элемент непустого массива.
Текст программы
public class MaxArr { public static void main(String[] args) throws Exception { int n, i, a[]; n = Xterm.inputInt("Введите длину массива n -> "); a = new int[n]; for (i=0; i<n; i++) a[i] = Xterm.inputInt("Введите a[" + i + "] -> "); int max = a[0]; for (i=1; i<n; i++) if (a[i] > max) max = a[i]; Xterm.println("Максимальный элемент массива = " + max); } }
В заключение рассмотрим задачу, включающую дополнительное требование на структуру программы.
Задача 5.8. Напишите программу, печатающую количество максимальных элементов непустого массива, в которой используется только один цикл.
Текст программы
public class NumMaxArr { public static void main(String[] args) throws Exception { int n, i, a[]; n = Xterm.inputInt("Введите длину массива n -> "); a = new int[n]; int max = Integer.MIN_VALUE; int nMax = 0; for (i=0; i<n; i++) { a[i] = Xterm.inputInt("Введите a[" + i + "] -> "); if (a[i] > max) { max = a[i]; nMax = 1; } else if (a[i] == max) nMax += 1; } Xterm.println("Количество макс. элементов = " + nMax); } }
Использование константы Integer.MIN_VALUE позволяет избежать необходимости присваивания переменной max значения нулевого элемента массива до начала циклического просмотра остальных элементов.
Можно заметить, что при решении этой задачи массив по существу не используется. Если в этой программе удалить описание массива a, заменив его на описание целой переменной a, и произвести замену всех вхождений выражения a[i] на a, то программа останется работающей.
Задача сортировки является классической задачей на массивы.
Задача 5.9. Напишите программу, которая вводит с клавиатуры непустой массив целых чисел, печатает его, затем сортирует (то есть переставляет его элементы так, чтобы они располагались в неубывающем порядке), и вновь печатает.
Приведенный ниже алгоритм, который последовательно обменивает все соседние пары элементов, расположенных в неправильном порядке, является одним из самых медленных алгоритмов сортировки среди всех широко известных — его асимптотическая сложность является квадратичной ( ).
Текст программы
public class Sort { private static void sort(int[] a, int n) { int i, j, t; for (i=0; i<n-1; i+=1) for (j=n-1; j>i; j-=1) if (a[j] < a[j-1]) { t=a[j]; a[j]=a[j-1]; a[j-1]=t; } } public static void main(String[] args) throws Exception { int n, i, a[]; n = Xterm.inputInt("Введите длину массива n -> "); a = new int[n]; for (i=0; i<n; i++) a[i] = Xterm.inputInt("Введите a[" + i + "] -> "); Xterm.print("Исходный массив\n"); for (i=0; i<n; i++) Xterm.print(" " + a[i]); Xterm.print("\n"); sort(a, n); Xterm.print("Отсортированный массив\n"); for (i=0; i<n; i++) Xterm.print(" " + a[i]); Xterm.print("\n"); } }