Двумерный массив
Двумерный массив отличается от одномерного массива тем, что для доступа к его элементам используется два индекса. Для того, чтобы задать какую-либо ячейку двумерной таблицы указывают номер строки и номер столбца.
Описание двумерного массива:
Var X: array[1..5,1..4] of integer;
Ввод-вывод матриц
1) Ввод элементов матрицы осуществляют с помощью вложенных циклов for:
for i:=1 to 5 do
for j:=1 to 4 do Read(а[i,j]);
2) Вывод элементов матрицы можно осуществлять по строкам или по столбцам, но лучше, если они будут выводиться в виде таблицы, например
for i:=1 to 4 do

Свойства элементов матрицы:
если номер строки элемента совпадает с номером столбца (i=j), это означает что элемент лежит на главной диагонали матрицы.
если номер строки превышает номер столбца (i>j), то элемент находится ниже главной диагонали.
если номер столбца больше номера строки (i<j), то элемент находится выше главной диагонали.
элемент лежит на побочной диагонали, если его индексы удовлетворяют равенству i + j – 1 = n.
Вопросы для самопроверки:
Что такое массив?
Как определить местоположения элемента в массиве?
Что такое индекс?
Как задается массив?
В каких операциях могут участвовать массивы в целом?
Каким образом задается обращение к элементу массива?
Как осуществляется ввод массива?
Как осуществляется вывод массива?
Что называется инициализацией массива?
Как осуществляется сортировка элементов в массиве?
Чем отличается двухмерный массив от одномерного массива?
Как определить местоположения элемента в двухмерном массиве?
Как задается двухмерный массив?
Каким образом задается обращение к элементам двухмерного массива?
Как осуществляется ввод элементов двухмерного массива?
Как осуществляется вывод элементов двухмерного массива?
Как вычисляется сумма элементов строк двухмерного массива?
Как вычисляется сумма элементов столбцов двухмерного массива?
Как вычисляется произведение элементов строк двухмерного массива?
Как вычисляется произведение элементов столбцов двухмерного массива?
Как находятся максимальные элементы в строках матрицы?
Как находятся минимальные элементы в строках матрицы?
Как находятся максимальные элементы в столбцах матрицы?
Как находятся минимальные элементы в столбцах матрицы?
Назовите свойства элементов матрицы.
Как осуществляется сортировка элементов в каждой строке матрицы по убыванию?
Как осуществляется сортировка элементов в каждой строке матрицы по возрастанию?
Как осуществляется сортировка элементов в каждом столбце матрицы по убыванию?
Как осуществляется сортировка элементов в каждом столбце матрицы по возрастанию?
Как осуществляется ввод элементов массива с помощью генератора случайных чисел?
Name already in use
java_for_beginners_book / c5.md
- Go to file T
- Go to line L
- Copy path
- Copy permalink
1 contributor
Users who have contributed to this file
- Open with Desktop
- View raw
- Copy raw contents Copy raw contents
Copy raw contents
Copy raw contents
Дополнительные сведения о типах данных и операторах
Основные навыки и понятия
- Представление о массивах
- Создание многомерных массивов
- Создание нерегулярных массивов
- Представление об альтернативном синтаксисе объявления массивов
- Присваивание ссылок на массивы
- Применение переменной экземпляра length
- Использование разновидности for-each цикла for
- Манипулирование символьными строками
- Употребление аргументов командной строки
- Использование поразрядных операторов
- Применение оператора ?
В этой главе мы возвращаемся к обсуждению типов данных и операторов Java. В ней речь пойдет, в частности, о массивах, классе String, поразрядных операторах и тернарном операторе ?. Кроме того, мы рассмотрим разновидность цикла for, реализованную лишь в самых последних версиях языка. Внимание также будет уделено аргументам командной строки.
Массив представляет собой совокупность однотипных переменных с общим для обращения к ним именем. В Java массивы могут быть как одномерными, так и многомерными, хотя чаще всего применяются одномерные массивы. Массивы служат самым разным целям, поскольку они предоставляют удобные средства для объединения связанных вместе переменных. Например, в массиве можно хранить максимальные суточные температуры, зарегистрированные в течение месяца, перечень биржевых курсов или же названия книг по программированию из домашней библиотеки.
Главное преимущество массива — в организации данных таким образом, чтобы ими было проще манипулировать. Так, если имеется массив, содержащий дивиденды, выплачиваемые по избранной группе акций, то, организовав циклическое обращение к элементам этого массива, можно без особого труда рассчитать средний доход от этих акций. Кроме того, массивы позволяют организовать данные таким образом, чтобы легко отсортировать их.
Массивами в Java можно пользоваться практически так же, как и в других языках программирования. Тем не менее у них имеется одна особенность: они реализованы в виде объектов. Именно поэтому их рассмотрение было отложено до тех пор, пока в этой книге не были представлены объекты. Реализация массивов в виде объектов дает ряд существенных преимуществ, и далеко не самым последним среди них является возможность утилизировать неиспользуемые массивы средствами “сборки мусора”.
Одномерный массив представляет собой список связанных переменных. Такие списки часто применяются в программировании. Например, в одномерном массиве можно хранить учетные номера активных пользователей сети или текущие средние уровни достижений бейсбольной команды.
Для объявления одномерного массива обычно применяется следующая общая форма:
где тип объявляет конкретный тип элемента массива. Тип элемента, называемый также базовым, определяет тип данных каждого элемента, составляющего массив. А размер определяет число элементов массива. В связи с тем что массивы реализованы в виде объектов, создание массива происходит в два этапа. Сначала объявляется переменная, ссылающаяся на массив, затем выделяется память для массива, а ссылка на нее присваивается переменной массива. Следовательно, память для массивов в Java динамически распределяется с помощью оператора new.
Проиллюстрируем все сказанное выше на конкретном примере. В следующей строке кода создается массив типа int, состоящий из 10 элементов, а ссылка на него присваивается переменной sample:
Объявление массива происходит так же, как и объявление объекта. В переменной sample сохраняется ссылка на область памяти, выделяемую для массива оператором new. Этой памяти должно быть достаточно для размещения в ней 10 элементов типа int.
Как и объявление объектов, приведенное выше объявление массива можно разделить на две отдельные составляющие следующим образом:
В данном случае сначала создается переменная sample, которая пока что не ссылается на конкретный объект. А затем переменная sample получает ссылку на конкретный массив.
Доступ к отдельным элементам массива осуществляется с помощью индексов. Индекс обозначает положение элемента в массиве. В Java индекс первого элемента массива равен нулю. Так, если массив sample содержит 10 элементов, их индексы находятся в пределах от 0 до 9. Индексирование массива осуществляется по номерам его элементов, заключенным в квадратные скобки. Например, для доступа к первому элементу массива sample следует указать sample [ 0 ], а для доступ к последнему элементу этого массива — sample [9]. В приведенном ниже примере программы в массиве sample сохраняются числа от 0 до 9.
Результат выполнения данной программы выглядит следующим образом:
Структура массива sample наглядно показана на приведенном ниже рисунке.
Массивы часто употребляются в программировании, поскольку они позволяют обрабатывать в цикле большое количество переменных. Например, в результате выполнения следующего примера программы определяется минимальное и максимальное значения из всех, хранящихся в массиве nums. Элементы этого массива перебираются в цикле for.
Ниже приведен результат выполнения данной программы.
В приведенном выше примере программы массив nums заполняется вручную в десяти операторах присваивания. И хотя в этом нет ничего неверного, существует более простой способ решения той же самой задачи. Массивы можно инициализировать в процессе их создания. Для этой цели служит приведенная ниже общая форма инициализации массива.
где vall-valN обозначают первоначальные значения, которые присваиваются элементам массива по очереди, слева направо и по порядку индексирования. Для хранения инициализаторов массива в Java автоматически распределяется достаточный объем памяти. А необходимость пользоваться оператором new явным образом отпадает сама собой. В качестве примера ниже приведена улучшенная версия программы, в которой определяются максимальное и минимальное значения в массиве.
Границы массива в Java строго соблюдаются. Если границы массива не достигаются или же превышаются, при выполнении программы возникает ошибка. Для того чтобы убедиться в этом, попробуйте выполнить приведенную ниже программу, в которой намеренно превышаются границы массива.
Как только значение переменной i достигнет 10, будет сгенерировано исключение ArraylndexOutOfBoundsException и выполнение программы прекратится.
Пример для опробования 5.1. Сортировка массива
Как пояснялось выше, данные в одномерном массиве организованы в виде индексируемого линейного списка. Такая структура как нельзя лучше подходит для сортировки. В этом проекте предстоит реализовать простой алгоритм сортировки массива. Вам, вероятно, известно, что существуют разные алгоритмы сортировки, в том числе быстрая сортировка, сортировка перемешиванием, сортировка методом Шелла. Но самым простым и общеизвестным алгоритмом является пузырьковая сортировка. Этот алгоритм не очень эффективен, но отлично подходит для сортировки небольших массивов.
- Создайте новый файл Bubble. j ava.
- В алгоритме пузырьковой сортировки соседние элементы массива сравниваются и меняются, если требуется, местами. При этом малые значения сдвигаются к одному краю массива, а большие значения — к другому. Этот процесс напоминает всплывание пузырьков воздуха на разные уровни в емкости с жидкостью, откуда и произошло название данного алгоритма. Пузырьковая сортировка предполагает обработку массива в несколько проходов. Элементы, взаимное расположение которых отличается от требуемого, меняются местами. Число проходов должно быть таким, чтобы все элементы непременно встали на свои места. Максимальное количество проходов должно быть на один меньше, чем число элементов в массиве. Ниже приведен исходный код, составляющий основу алгоритма пузырьковой сортировки. Сортируемый массив называется nums.
Несмотря на то что одномерные массивы употребляются чаще всего, в программировании, безусловно, применяются и многомерные (двух-, трехмерные и т.д.) массивы. В Java многомерные массивы представляют собой массивы массивов.
Среди многомерных массивов наиболее простыми являются двумерные массивы. Двумерный массив, по существу, представляет собой ряд одномерных массивов. Для того чтобы объявить двумерный целочисленный табличный массив table размерами 10×20, следует написать такое выражение:
Обратите особое внимание на объявление этого массива. В отличие от некоторых других языков программирования, где размеры массива разделяются запятыми, в Java они заключаются в отдельные квадратные скобки. Так, для обращения к элементу массива table по индексам 3 и 5 следует указать table [ 3 ] [ 5 ].
В следующем примере двумерный массив заполняется числами от 1 до 12:
В данном примере элемент table [0] [0] будет содержать значение 1, элемент table [0] [ 1 ] — значение 2, элемент table [0] [2] — значение 3 и так далее, а элемент table [2 ] [ 3 ] — значение 12. Структура данного массива наглядно показана на рис. 5.1. 
Выделяя память под многомерный массив, достаточно указать лишь первый (крайний слева) размер. А память под остальные размеры массива можно выделять по отдельности. Например, в приведенном ниже фрагменте кода память выделяется только под первый размер двумерного массива table. А под второй его размер она выделяется вручную.
Объявляя массив подобным образом, мы не получаем никаких преимуществ, но в некоторых случаях такое объявление оказывается вполне оправданным. Это, в частности, дает возможность установить разную длину массива по каждому индексу. Как упоминалось выше, многомерный массив реализован в виде массива массивов, что позволяет контролировать длину каждого из них. Допустим, требуется написать программу, в процессе работы которой будет сохраняться число пассажиров, перевезенных автобусом-экспрессом в аэропорт. Если автобус-экспресс делает по десять рейсов в будние дни и по два рейса в субботу и воскресенье, то массив riders можно объявить так, как показано в приведенном ниже фрагменте кода. Обратите внимание на то, что длина массива по второму размеру для первых пяти элементов равна 10, а для двух последних элементов — 2.
Для большинства приложений использовать нерегулярные массивы не рекомендуется, поскольку это затрудняет восприятие кода другими программистами. Но в некоторых случаях такие массивы вполне уместны и могут существенно повысить эффективность программ. Так, если вам требуется создать большой двумерный массив, в котором используются не все элементы, то нерегулярный массив позволит существенно сэкономить память.
Трехмерные, четырехмерные и многомерные массивы
В Java допускаются массивы размерностью больше двух. Ниже приведена общая форма объявления многомерного массива.
В качестве примера ниже приведено объявление трехмерного целочисленного массива размерами 4x10x3.
Инициализация многомерных массивов
Многомерный массив можно инициализировать, заключая инициализирующую последовательность для каждого размера массива в отдельные фигурные скобки, как показано ниже.
где val обозначает начальное значение, которым инициализируются элементы многомерного массива. Каждый внутренний блок многомерного массива соответствует отдельной строке. В каждой строке первое значение сохраняется в первом элементе подмассива, второе значение — во втором элементе и т.д. Обратите внимание на запятые, разделяющие блоки инициализаторов многомерного массива, а также на точку с запятой после закрывающей фигурной скобки.
В следующем фрагменте кода двумерный массив sqrs инициализируется числами от 1 до 10 и их квадратами:
Выполнение этого фрагмента кода дает следующий результат:
Альтернативный синтаксис объявления массивов
Помимо рассмотренной выше общей формы, для объявления массива можно также пользоваться следующей синтаксической конструкцией:
Здесь квадратные скобки указываются после спецификатора типа, а не имени переменной. Поэтому следующие два объявления равнозначны:
Равнозначными являются и приведенные ниже строки кода.
Альтернативный синтаксис объявления массива оказывается удобным в тех случаях, если требуется объявить несколько массивов одного типа. Например:
В этом объявлении создаются три переменные, ссылающиеся на массивы типа int. Тот же результат можно получить с помощью следующей строки кода:
Альтернативный синтаксис объявления массива оказывается удобным и в тех случаях, если в качестве типа, возвращаемого методом, требуется указать массив. Например:
В этой строке кода объявляется метод someMeth(), возвращающий целочисленный массив.
Обе рассмотренные выше формы объявления массивов широко распространены в программировании на Java, и поэтому они употребляются в примерах, представленных в этой книге.
Присваивание ссылок на массивы
Присваивание значения одной переменной ссылки на массив другой переменной, по существу, означает, что обе переменные ссылаются на один и тот же массив, и в этом отношении массивы ничем не отличаются от любых других объектов. Такое присваивание не приводит ни к созданию копии массива, ни к копированию содержимого одного массива в другой. В качестве примера рассмотрим следующую программу:
Выполнение этой программы дает следующий результат:
Нетрудно заметить, что в результате присваивания ссылки на массив numsl переменной nums 2 обе переменные ссылаются на один и тот же массив.
Применение переменной экземпляра length
В связи с тем что массивы реализованы в виде объектов, в каждом массиве содержится переменная экземпляра length. Значением этой переменной является число элементов, которые может содержать массив. (Иными словами, в переменной length содержится размер массива.) Ниже приведен пример программы, демонстрирующий данное свойство массивов.
Выполнение этой программы дает следующий результат:
Обратите особое внимание, каким образом переменная length используется в двумерном массиве. Как пояснялось ранее, двумерный массив представляет собой массив массивов. Поэтому приведенное ниже выражение позволяет определить число массивов, содержащихся в массиве table,
Число таких массивов равно 3. Для того чтобы получить длину отдельного массива, содержащегося в массиве table, потребуется выражение, аналогичное следующему:
Это выражение возвращает длину первого массива.
Анализируя код класса LengthDemo, следует также заметить, что выражение list. length используется в цикле for для определения требуемого количества итераций. Учитывая то, что у каждого подмассива своя длина, пользоваться таким выражением удобнее, чем отслеживать вручную размеры массивов. Но не следует забывать, что переменная length не имеет никакого отношения к количеству фактически используемых элементов массива. Она содержит лишь данные о том, сколько элементов может содержать массив.
Использование переменной экземпляра length позволяет упростить многие алгоритмы. Так, в приведенном ниже примере программы эта переменная используется при копировании одного массива в другой и предотвращает возникновение при выполнении программы исключительной ситуации в связи с превышением границ массива.
В данном примере переменная экземпляра length помогает решить две важные задачи. Во-первых, позволяет убедиться в том, что размера целевого массива достаточно для хранения содержимого исходного массива. И во-вторых, с ее помощью формируется условие завершения цикла, в котором выполняется копирование массива. Конечно, в столь простом примере размеры массивов нетрудно отследить и без переменной экземпляра length, но подобный подход может быть применен для решения более сложных задач.
В данном примере переменная экземпляра length помогает решить две важные задачи. Во-первых, позволяет убедиться в том, что размера целевого массива достаточно для хранения содержимого исходного массива. И во-вторых, с ее помощью формируется условие завершения цикла, в котором выполняется копирование массива. Конечно, в столь простом примере размеры массивов нетрудно отследить и без переменной экземпляра length, но подобный подход может быть применен для решения более сложных задач.
Пример для опробования 5.2. Создание класса очереди
Вам, вероятно, известно, что структура данных — это способ их организации. Одной из самых простых структур является массив, который представляет собой линейный список элементов, допускающий произвольный доступ к ним. Нередко массивы используются в качестве основания для создания более сложных структур вроде стеков или очередей. Стек — это набор элементов с организацией доступа по принципу “первым пришел — последним обслужен”, А очередь — это набор элементов с организацией доступа по принципу “первым пришел — первым обслужен”. Стек можно сравнить со стопкой тарелок на столе: первая тарелка снизу стопки используется последней. А очередь можно сравнить с выстроившейся очередью к окошку в банке: клиент, стоящий в очереди первым, обслуживается первым.
В очередях и стеках нас больше всего интересует способ хранения информации и обращения к ней. И стеки, и очереди представляют собой механизмы доступа к данным, в которых хранение и извлечение информации поддерживается самой структурой, а не реализуется в программе. Такое сочетание способов хранения и обработки данных лучше всего реализуется в рамках класса, поэтому в данном проекте предстоит создать простой класс очереди.
В очереди поддерживаются две основные операции: размещение и извлечение. При выполнении операции размещения новый элемент помещается в конец очереди, а при операции извлечения очередной элемент извлекается из начала очереди. Операции с очередью являются истощающими: элемент, однажды извлеченный из очереди, не может быть извлечен из нее повторно. Очередь может быть переполнена, когда в ней не остается места для новых элементов. Но очередь может быть и пуста, когда в ней нет ни одного элемента.
И последнее замечание: существуют два типа очередей — циклические и нециклические. В циклической очереди элементы массива, на основе которого она создана, могут использоваться повторно по мере удаления данных. Нециклическая очередь не позволяет повторно использовать элементы, поэтому со временем пространство для хранения новых элементов исчерпывается. Нециклическую очередь создать намного проще, чем циклическую, поэтому именно ее мы и реализуем в данном примере для опробования. Но если немного подумать, то нециклическую очередь можно без особого труда превратить в циклическую.
- Создайте новый файл QDemo.java.
- Очередь можно организовать разными способами. Мы создадим ее на основании массива, выступающего в роли хранилища данных, помещаемых в очередь. Для доступа к массиву будут использованы два индекса. Индекс размещения данных определяет, в каком месте будет размещен следующий элемент очереди. А индекс извлечения данных указывает место, откуда должен быть извлечен очередной элемент очереди. Напомним, что операция извлечения является истощающей и не позволяет извлечь один и тот же элемент дважды. Создаваемая здесь очередь предназначена для хранения символов, но та же самая логика ее организации может быть использована для размещения данных любых типов, в том числе объектов. Итак, начните создание класса очереди Queue со следующих строк кода:
Сначала в данном методе проверяется, пуста ли очередь. Если значения индексов в переменных getloc и putloc совпадают, то в очереди нет ни одного элемента. Именно поэтому в конструкторе Queue переменные getloc и putloc инициализируются нулевыми значениями. Если очередь не пуста, то переменная getloc инкрементируется и из нее извлекается очередной элемент. Следовательно, переменная getloc содержит индекс последнего извлеченного элемента. 6. Ниже приведен весь исходный код программы из файла QDemo.java. «` /* Пример для опробования 5.2. Класс, реализующий очередь, для хранения символов. */ class Queue < char q[]; // Массив для хранения элементов очереди int putloc, getloc; // Индексы размещения и извлечения элементов очереди
- Ниже приведен результат выполнения данной программы.
Разновидность for-each цикла for
При выполнении операций с массивами очень часто возникают ситуации, когда должен быть обработан каждый элемент массива. Например, для расчета суммы всех значений, содержащихся в массиве, нужно обратиться ко всем его элементам. То же самое приходится делать при расчете среднего значения, поиске элемента и решении многих других задач. В связи с тем что задачи, предполагающие обработку всего массива, встречаются очень часто, в Java была реализована еще одна разновидность цикла for, рационализирующая подобные операции с массивами.
Вторая разновидность оператора for реализует цикл типа for-each. В этом цикле происходит последовательное обращение к каждому элементу совокупности объектов (например, массива). За последние годы циклы for-each появились практически во всех языках программирования. Изначально в Java подобный цикл не был предусмотрен и был реализован лишь в пакете JDK 5. Разновидность for-each цикла for называется также расширенным циклом for. В данной книге употребляются оба эти термина.
Ниже приведена общая форма разновидности for-each цикла for.
где тип обозначает конкретный тип intr_var — итерационной переменной, в которой сохраняются перебираемые по очереди элементы набора данных, обозначенного как коллекция. В данной разновидности цикла for могут быть использованы разные типы коллекций, но в этой книге рассматриваются только массивы. На каждом шаге цикла очередной элемент извлекается из коллекции и сохраняется в итерационной переменной. Выполнение гщкла продолжается до тех пор, пока не будут получены все элементы коллекции. Таким образом, при обработке массива размером N в расширенном цикле for будут последовательно извлечены элементы с индексами от 0 до N—1.
Итерационная переменная получает значения из коллекции, и поэтому ее тип должен совпадать (или, по крайней мере, быть совместимым) с типом элементов, которые содержит коллекция. В частности, при обработке массива тип итерационной переменной должен совпадать с типом массива.
Для того чтобы стали понятнее причины, побудившие к внедрению разновидности for-each цикла for в Java, рассмотрим приведенный ниже фрагмент кода, в котором традиционный цикл for используется для вычисления суммы значений элементов массива.
Для того чтобы вычислить упомянутую выше сумму, придется перебрать все элементы массива nums от начала до конца. Перебор элементов осуществляется благодаря использованию переменной цикла i в качестве индекса массива nums. Кроме того, нужно явно указать начальное значение переменной цикла, шаг приращения и условие завершения цикла.
При использовании разновидности for-each данного цикла некоторые перечисленные выше действия выполняются автоматически. В частности, отпадает необходимость в использовании переменной цикла, задании ее исходного значения и условия завершения цикла, а также в индексировании массива. Вместо этого массив автоматически обрабатывается в цикле от начала до конца. Код, позволяющий решить ту же самую задачу с помощью разновидности for-each цикла for, выглядит следующим образом:
На каждом шаге этого цикла переменная х автоматически принимает значение, равное очередному элементу массива nums. Сначала ее значение равно 1, на втором шаге цикла итерации оно становится равным 2 и т.д. В данном случае не только упрощается синтаксис, но и исключается ошибка, связанная с превышением границ массива.
Ниже приведен весь исходный код программы, демонстрирующей решение описанной выше задачи с помощью разновидности for-each цикла for.
Результат выполнения данной программы выглядит следующим образом:
Нетрудно заметить, что в данной разновидности for-each цикла for элементы массива автоматически извлекаются один за другим в порядке возрастания индекса.
Несмотря на то что в разновидности for-each цикла for обрабатываются все элементы массива, этот цикл можно завершить преждевременно, используя оператор break. Так, в цикле, используемом в следующем примере, вычисляется сумма только пяти элементов массива nums:
Следует, однако, иметь в виду одну важную особенность разновидности for-each цикла for. Итерационная переменная в этом цикле обеспечивает только чтение элементов массива, но ее нельзя использовать для записи значения в какой-либо элемент массива. Иными словами, изменить содержимое массива, присвоив итерационной переменной новое значение, не удастся. Рассмотрим в качестве примера следующую программу:
В первом цикле for значение итерационной переменной увеличивается на 10, но это не оказывает никакого влияния на содержимое массива nums, что и демонстрирует второй цикл for. Это же подтверждает и результат выполнения программы.
Циклическое обращение к многомерным массивам
Расширенный цикл for можно применять и при обращении к многомерным массивам. Как вам должно быть уже известно, в Java многомерный массив представляет собой массив массивов. (Например, двумерный массив — это массив, элементами которого являются одномерные массивы.) Эту особенность важно помнить, организуя циклическое обращение к многомерным массивам, поскольку на каждом шаге цикла извлекается очередной массив, а не отдельный элемент. Более того, итерационная переменная в расширенном цикле for должна иметь тип, совместимый с типом извлекаемого массива. Так, при обращении к двумерному массиву итерационная переменная должна представлять собой ссылку на одномерный массив. При использовании разновидности for-each цикла for для обработки TV-мерного массива извлекаемый объект представляет собой (Л/»—1)-мерный массив. Для того чтобы сказанное стало более понятным, рассмотрим приведенный ниже пример программы, где для извлечения элементов двумерного массива используются вложенные циклы for. Обратите внимание на то, каким образом объявляется переменная х.
Выполнение этой программы дает следующий результат:
Обратите особое внимание на следующую строку кода:
Не упустите из виду и то, как объявляется переменная х. Она представляет собой ссылку на одномерный целочисленный массив. Это очень важно, поскольку на каждом шаге цикла for из двумерного массива nums извлекается очередной массив, начиная с nums [0]. А во внутреннем цикле for перебираются элементы полученного массива и отображаются их значения.
Применение расширенного цикла for
Разновидность for-each цикла for обеспечивает лишь последовательный перебор элементов от начала до конца массива, поэтому может создаться впечатление, будто такой цикл имеет ограниченное применение. Но это совсем не так. Данный механизм циклического обращения применяется в самых разных алгоритмах. Один из самых характерных тому примеров — организация поиска. В приведенном ниже примере программы расширенный цикл for используется для поиска значения в неотсортированном массиве. Выполнение цикла прерывается, если искомый элемент найден.
В данном случае применение расширенного цикла for вполне оправданно, поскольку найти значение в неотсортированном массиве можно лишь, перебрав все его элементы. (Если бы содержимое массива было предварительно отсортировано, то лучше было бы применить более эффективный алгоритм поиска, например поиск методом дихотомии. В этом случае пришлось бы использовать другой массив.) Расширенным циклом for удобно также пользоваться для расчета среднего значения, нахождения минимального и максимального элементов множества, выявления дублирующихся значений и т.д.
Теперь, когда разновидность for-each цикла for представлена в достаточной степени, она будет еще не раз использоваться там, где это уместно, в примерах программ, представленных в остальной части книги.
В повседневной работе каждый программист обязательно встречается с объектами типа String. Объект типа String определяет символьную строку и поддерживает операции над ней. Во многих языках программирования символьная строка — это лишь массив символов, но в Java это совсем не так, где символьная строка, по существу, является объектом.
Возможно, вы и не заметили, но класс String фактически уже использовался в примерах программ, начиная с главы 1. При создании строкового литерала на самом деле строился объект типа String. Рассмотрим приведенный ниже оператор.
Наличие в нем символьной строки » In Java, strings are objects. » (B Java строки являются объектами) автоматически приводит к созданию объекта типа String. Таким образом, класс String незримо присутствовал в предыдущих примерах программ. В последующих разделах будет показано, как этим классом пользоваться явным образом. Однако в классе String предусмотрен обширный ряд методов, поэтому здесь будут рассмотрены лишь некоторые из них. Большую часть функциональных возможностей класса String вам предстоит изучить самостоятельно.
Объекты типа String создаются таким же образом, как и объекты других типов. Для этой цели используется конструктор, как показано в следующем примере:
В данном примере создается объект str типа String, содержащий символьную строку «Hello» (Привет). Объект типа String можно создать и на основе другого объекта такого же типа. Например:
После выполнения этих строк кода объект str2 будет также содержать символьную строку «Hello».
Ниже представлен еще один способ создания объекта типа String.
В данном случае объект str инициализируется последовательностью символов » Java strings are powerful. » (Строки в Java эффективны).
Создав объект типа String, можете использовать его везде, где допускается строковый литерал (последовательность символов, заключенная в кавычки). Например, объект типа String можно передать в качестве параметра методу println() при его вызове, как показано в приведенном ниже примере программы.
Выполнение этой программы дает следующий результат:
Операции над символьными строками
Класс String содержит ряд методов, предназначенных для выполнения действий над символьными строками. Ниже описаны некоторые из них.
| boolean equals (str) | Возвращает логическое значение true, если текущая строкасодержит ту же последовательность символов, что и параметр str |
| int length() | Возвращает длину символьной строки |
| char charAt (index) | Возвращает символ, находящийся в строке на позиции, указываемой параметром index |
| int compareTo (String str) | Возвращает отрицательное значение, если текущая строкаменьше строки str, нуль, если эти строки равны, и положительное значение, если текущая строка больше строки str |
| int indexOf (String str) | Производит в текущей строке поиск подстроки, определяемой параметром str. Возвращает индекс первого вхождения подстроки str или -1, если поиск завершается неудачно |
| int lastlndexOf (String str) | Производит в текущей строке поиск подстроки, определяемойпараметром str. Возвращает индекс последнего вхожденияподстроки str или -1, если поиск завершается неудачно |
В приведенном ниже примере программы демонстрируется применение перечисленных выше методов, оперирующих символьными строками.
Выполнение этой программы дает следующий результат:
Сцепление (или объединение) двух символьных строк обеспечивает оператор +. Например, в приведенной ниже последовательности операторов присваивания переменная str4 инициализируется символьной строкой «OneTwoThree».
Массивы символьных строк
Подобно другим типам данных, символьные строки можно объединять в массивы.
Ниже приведен характерный тому пример.
Выполнение этого фрагмента кода дает следующий результат:
Как ни странно, содержимое объекта типа string не подлежит изменению. Это означает, что однажды созданную последовательность символов изменить нельзя. Но данное ограничение способствует более эффективной реализации символьных строк. Поэтому этот, на первый взгляд, очевидный недостаток на самом деле превращается в преимущество. Так, если требуется строка в качестве разновидности уже имеющейся строки, для этой цели следует создать новую строку, содержащую все необходимые изменения. А поскольку неиспользуемые строковые объекты автоматически собираются в “мусор”, то о дальнейшей судьбе ненужных строк можно даже не беспокоиться. Следует, однако, иметь в виду, что переменные ссылки на строки (т.е. объекты типа String) подлежат изменению, а следовательно, могут ссылаться на другой объект. Но содержимое самого объекта типа String не меняется после его создания.
Для того чтобы стало понятнее, почему постоянство строк не является помехой, воспользуемся еще одним методом обращения со строками из класса String. Это метод substring(), возвращающий новую строку, содержащую часть вызывающей строки. В итоге создается новый строковый объект, содержащий выбранную подстроку, тогда как исходная строка не меняется, а следовательно, соблюдается принцип постоянства строк. Ниже приведена рассматриваемая здесь общая форма объявления метода substring().
где начальный_индекс обозначает начало извлекаемой подстроки, а конечный_индекс — ее окончание. Ниже приведен пример программы, демонстрирующий применение метода substringO и принцип постоянства строк.
Результат выполнения данной программы выглядит следующим образом:
Как видите, исходная строка orgstr остается без изменения, а новая строка substr содержит сформированную подстроку.
Применение строк для управления оператором switch
Как пояснялось в главе 3, до появления версии JDK 7 для управления оператором switch приходилось пользоваться константами типа int или char. Это препятствовало применению оператора switch в тех случаях, когда одно из выполняемых действий выбирается из содержимого символьной строки. В качестве выхода из этого положения зачастую приходилось обращаться к многоступенчатой конструкции if-else-if. И хотя эта конструкция семантически правильна, для организации подобного выбора более естественным было бы применение оператора switch. К счастью, этот недостаток был исправлен. После выпуска комплекта JDK 7 появилась возможность пользоваться объектами типа String для управления оператором switch. И во многих случаях это способствует написанию более удобочитаемого и рационально организованного кода.
Ниже приведен краткий пример программы, демонстрирующий управление оператором switch с помощью объектов типа String.
Как и следовало ожидать, выполнение этой программы приводит к следующему результату:
Символьная строка, содержащаяся в переменной command, а в данном примере это строка «cancel» (отмена), проверяется на совпадение с символьными константами в ветвях case оператора switch. Если совпадение обнаружено, как это имеет место во второй ветви case, выполняется кодовая последовательность, связанная с данной последовательностью действий.
Использование символьных строк в операторе switch может оказаться очень удобным и позволяет сделать код более удобочитаемым. В частности, применение оператора switch, управляемого строками, является более совершенным решением по сравнению с равнозначной последовательностью операторов if/else. Но переход по символьным строкам обходится дороже с точки зрения потребляемых вычислительных ресурсов, чем переход по целочисленным значениям. Поэтому организовывать переход по символьным строкам рекомендуется лишь в тех случаях, когда управление данными уже происходит в строковой форме. Иными словами, пользоваться символьными строками в операторе switch без особой надобности не следует.
Употребление аргументов командной строки
А теперь, когда представлен класс String, можно пояснить назначение параметра args метода main() в исходном коде большинства всех рассмотренных ранее примеров программ. Многие программы получают параметры, задаваемые в командной строке. Это так называемы аргументы командной строки. Они представляют собой данные, указываемые непосредственно после имени запускаемой на выполнение программы. Для того чтобы получить доступ к аргументам командной строки из программы на Java, достаточно обратиться к массиву объектов типа String, который передается методу main(). Рассмотрим в качестве примера программу, отображающую параметры командной строки. Ее исходный код приведен ниже.
Допустим, программа CLDemo была запущена на выполнение из командной строки следующим образом:
Тогда ее выполнение приведет к следующему результату:
Обратите внимание на то, что первый аргумент содержится в строке, представляющей собой элемент массива с индексом 0. Для доступа ко второму аргументу следует воспользоваться индексом 1 и т.д.
Для того чтобы стало понятнее, как пользоваться аргументами командной строки, рассмотрим приведенный ниже пример программы. Эта программа принимает из командной строки один аргумент, определяющий имя абонента, а затем производит поиск имени в двумерном массиве символьных строк. Если имя найдено, программа отображает телефонный номер обнаруженного абонента.
Выполнение этой программы может дать, например, следующий результат:
В главе 2 были рассмотрены арифметические и логические операторы, а также операторы отношения. Эти три вида операторов используются чаще всего, но в Java предоставляются также поразрядные операторы, которые позволяют расширить границы применения данного языка программирования. Поразрядные операторы можно применять к значениям типа long, int, short, char и byte. А над типами boolean, float, double или типами классов поразрядные операции выполнять нельзя. Эти операторы называются поразрядными потому, что они используются в основном для проверки, установки и сдвига отдельных разрядов числа. Поразрядные операции чрезвычайно важны для решения задач системного программирования, в которых требуется анализировать данные, получаемые из устройства, или формировать значения, передаваемые на устройство. Доступные в Java поразрядные операторы перечислены к табл. 5.1.
Таблица 5.1. Поразрядные операторы
Поразрядные операторы И, ИЛИ, исключающее ИЛИ и НЕ
Поразрядные операторы И, ИЛИ, исключающее ИЛИ и НЕ обозначаются следующим образом: &, |, А и Они выполняют те же функции, что и их логические аналоги, рассмотренные в главе 2. Но в отличие от логических операторов поразрядные операторы действуют на уровне отдельных двоичных разрядов. Ниже приведены результаты поразрядных операций с двоичными единицами и нулями.
С точки зрения наиболее распространенного применения поразрядную операцию И можно рассматривать как способ подавления отдельных двоичных разрядов. Это означает, что если какой-нибудь бит в любом из операндов равен 0, то соответствующий бит результата будет сброшен в 0. Например:
Ниже приведен пример программы, демонстрирующий применение оператора 6. В этой программе строчные буквы английского алфавита преобразуются в прописные путем сброса шестого бита в коде символа. Коды ASCII и уникода (Unicode) строчных букв английского алфавита отличаются от аналогичных кодов прописных букв на вели¬ чину 32. Поэтому для преобразования строчных букв в прописные достаточно сбросить в нуль шестой бит в кодах их символов.
Результат выполнения данной программы выглядит следующим образом:
Значение 65503, используемое в операции поразрядного И, является десятичным представлением двоичного числа 1111111111011111. Таким образом, при выполнении данной операции все биты кода символа в переменой ch, за исключением шестого, остаются без изменения, а шестой бит сбрасывается в нуль.
Операция поразрядного И оказывается удобной и в том случае, если требуется выяснить, установлен или сброшен отдельный бит числа. Например, в приведенной ниже строке кода проверяется, установлен ли четвертый бит значения переменной status,
В данном примере число 8 использует потому, что в его двоичном представлении установлен только четвертый бит. Таким образом, в условном операторе if логическое значение true будет получено только в том случае, если четвертый бит значения переменной status также установлен. Подобный подход можно применить и для преобразования значения типа byte в двоичный формат, как показано ниже.
Выполнение этой программы дает следующий результат:
В цикле for последовательно проверяется каждый бит значения переменной val. Для того чтобы выяснить, установлен ли бит, выполняется операция поразрядного И. Если бит установлен, отображается цифра 1, иначе — 0. В примере для опробования 5.3 будет показано, как расширить этот элементарный принцип для создания класса, в котором будут отображаться биты двоичного представления целого числа любого типа.
Операция поразрядного ИЛИ выполняет действия, противоположные операции поразрядного И, и служит для установки отдельных битов. Любой бит, значение которого равно единице хотя бы в одном из двух операндов, будет равен единице и в результирующем значении. Например:
Операцию поразрядного ИЛИ можно использовать для преобразования прописных букв английского алфавита в строчные. Ниже приведен пример программы, решающей эту задачу.
Выполнение этой программы дает следующий результат:
В приведенном выше примере программы операция поразрядного ИЛИ выполняется над кодом символа и значением 32, имеющим двоичное представление 0000000000100000. Как видите, в двоичном представлении значения 32 установлен только шестой бит. Используя это значение в качестве одного операнда в операции поразрядного ИЛИ с любым другим значением в качестве другого операнда, получим результат, в котором устанавливается шестой бит, а состояние всех остальных битов остается без изменения. Таким образом, любая прописная буква будет преобразована в строчную.
Операция поразрядного исключающего ИЛИ дает результат, в котором отдельный бит устанавливается в том и только в том случае, если соответствующие биты в двух операндах имеют разные значения. Ниже приведен пример выполнения операции поразрядного исключающего ИЛИ.
Операция поразрядного исключающего ИЛИ имеет одну интересную особенность, которая позволяет очень просто кодировать сообщения. Если выполнить данную oneрацию сначала над некоторыми значениями X и Y, а затем над ее результатом и значением Y, то снова получится значение X. Например, при выполнении приведенной ниже последовательности операторов переменная R2 получит то же значение, что и X. Таким образом, в результате выполнения подряд двух операций поразрядного исключающего ИЛИ восстанавливается исходное значение.
Эту особенность операции поразрядного исключающего ИЛИ можно использовать для создания простейшей шифрующей программы, в которой некоторое целое число будет выполнять роль ключа, применяемого как при шифровании, так и дешифровании сообщений. Над всеми символами сообщения и данным числом будет выполняться операция поразрядного исключающего ИЛИ. В первый раз данная операция будет выполняться при шифровании, формируя кодированный текст, а второй раз — при дешифровании, в результате чего восстанавливается исходный текст сообщения. Ниже приведен пример простой программы, выполняющей шифрование и дешифрование коротких сообщений.
Выполнение этой программы дает следующий результат:
Как видите, в результате двух операций поразрядного исключающего ИЛИ с одним и тем же ключом получается дешифрованное сообщение, совпадающее с исходным.
Унарная операция поразрядного НЕ (или дополнения до 1) изменяет на обратное состояние всех битов операнда. Так, если некоторая целочисленная переменная А содержит значение с двоичным представлением 10010110, то в результате поразрядной операции
А получится двоичная комбинация 01101001.
Ниже приведен пример программы, демонстрирующий применение операции поразрядного НЕ. Эта программа отображает число и его дополнение в двоичном представлении.
Выполнение этой программы дает следующий результат:
В Java предусмотрена возможность сдвига битов, составляющих числовое значение, влево или вправо на заданное количество позиций. Для этой цели в Java предоставляются три перечисленных ниже оператора сдвига.
| << | Сдвиг влево |
| >> | Сдвиг вправо |
| >>> | Сдвиг влево без знака |
Ниже приведена общая форма для этих операторов.
где число_битов — это число позиций двоичных разрядов, на которое сдвигается указанное значение.
При сдвиге влево освободившиеся младшие разряды заполняются нулями. А при сдвиге вправо дело обстоит немного сложнее. Как известно, признаком отрицательного целого числа является единица в старшем разряде, поэтому при сдвиге вправо старший (знаковый) разряд сохраняется. Если число положительное, то в него записывается нуль, а если отрицательное — единица.
Помимо сохранения знакового разряда, необходимо помнить еще об одной особенности сдвига вправо. Отрицательные числа в Java (как, впрочем, и в других языках программирования) представлены в виде дополнения до двух. Для того чтобы преобразовать положительное число в отрицательное, нужно изменить на обратное состояние всех битов его двоичного представления, а к полученному результату прибавить единицу. Так, значение -1 имеет байтовое представление 11111111. Сдвинув это значение вправо на любое число позиций, мы снова получим -1!
Если при сдвиге вправо не требуется сохранять знаковый разряд, то можно воспользоваться сдвигом вправо без знака (оператором »>). В этом случае освободившиеся старшие разряды всегда будут заполняться нулями. Именно поэтому такая операция называется еще сдвигом с заполнением нулями. Сдвигом вправо без знака удобно пользоваться для обработки нечисловых значений, в том числе кодов состояния.
При любом сдвиге теряются те биты, которые сдвигаются. Циклический сдвиг в Java не поддерживается, и поэтому нет возможности восстановить потерянные разряды.
Ниже приведен пример программы, демонстрирующий эффект от применения операторов сдвига влево и вправо. В двоичном представлении исходного целочисленного значения 1 установлен лишь младший разряд. К этому значению восемь раз применяется операция сдвига влево. После каждого сдвига на экран выводится восемь младших разрядов числа. Затем единица устанавливается в восьмом двоичном разряде числа и производятся его сдвиги вправо.
Результат выполнения данной программы выглядит следующим образом:
Выполняя сдвиг значений типа byte и short, необходимо соблюдать осторожность, поскольку исполняющая система Java автоматически преобразует их в тип int и лишь затем вычисляет выражение с оператором сдвига. Так, если сдвинуть вправо значение типа byte, оно будет сначала продвинуто к типу int, а результат сдвига будет также отнесен к типу int. Обычно такое преобразование не влечет за собой никаких последствий. Но если попытаться сдвинуть отрицательное значение типа byte или short, то при продвижении к типу int оно будет дополнено знаком, а следовательно, старшие его разряды будут заполнены единицами. Это вполне оправдано при обычном сдвиге вправо. Но при выполнении сдвига с заполнением нулями в байтовом представлении числа неожиданно появятся 24 единицы, которые придется дополнительно сдвинуть, прежде чем в нем появятся нули.
Поразрядные составные операторы присваивания
составные операторы присваивания Все двоичные поразрядные операторы имеют укороченную форму и могут быть использованы в составных операциях присваивания. Например, в двух приведенных ниже операторах переменной х присваивается результат выполнения операции исключающее ИЛИ над первоначальным значением переменной х и числовым значением 127.
Пример для опробования 5.3. Создание класса ShowBits
В данном проекте предстоит создать класс ShowBits, который позволит отображать любое целочисленное значение в двоичном виде. Этот класс может оказаться очень полезным при разработке некоторых программ. Так, если требуется отладить код драйвера устройства, возможность контролировать поток данных в двоичном виде окажется весьма кстати.
- Создайте новый файл ShowBits Demo. j ava.
- Создайте класс ShowBits, начав его со следующего кода:
Разница между одномерным (1D) и двумерным (2D) массивом
Массив — это набор переменных, которые имеют сходные типы данных и имеют общее имя. Доступ к конкретному элементу в массиве осуществляется с помощью определенного индекса этого массива. Массивы в Java работают иначе, чем в C ++. Основной темой нашего обсуждения является различие между одномерным и двумерным массивом. Одномерный массив — это список переменных с одним и тем же типом данных, тогда как двумерный массив — это «массив массивов», имеющий схожие типы данных. В C ++ нет проверки границ для массивов, тогда как в Java есть строгая проверка границ для массивов.
Итак, давайте начнем с различий между одномерным и двухмерным массивом вместе со сравнительной таблицей.
Сравнительная таблица:
| Основа для сравнения | Одномерный | Двумерный |
|---|---|---|
| основной | Хранить единый список элементов схожего типа данных. | Хранить «список списков» или «массив массивов» или «массив одномерных массивов». |
| декларация | / * объявление в C ++ тип имя_переменной [размер]; * / / * объявление в Java тип имя_переменной []; имя_переменной = новый тип [размер]; * / |
/ * объявление в C ++ тип имя_переменной [размер1] [размер2]; * / / * объявление в Java тип переменная_имя = новый int [размер1] [размер2]; * / |
| Альтернативная декларация | / * В Java int [] a = new int [10]; * / |
/ * В Java int [] [] a = new int [10] [20]; * / |
| Общий размер в байтах | Всего байт = sizeof (тип данных переменной массива) * размер массива. | Всего байт = sizeof (тип данных переменной массива) * размер первого индекса * размер второго индекса. |
| Параметр получения | Он может быть получен в виде указателя, массива размера или массива без размера. | Получающий его параметр должен определять самый правый размер массива. |
| Размеры | Одномерный | Двумерный. |
Определение одномерного массива (одномерный массив)
Одномерный или одномерный массив рассматривается как «список переменных схожих типов данных», и к каждой переменной можно получить отдельный доступ, указав ее индекс в квадратных скобках, перед которым следует имя этого массива.
В C ++ объявления переменной массива с размером достаточно, чтобы выделить для них место в памяти. В Java это достигается в два этапа. Во-первых, вы должны объявить переменную нужного типа. Во-вторых, вы должны выделить память для хранения массива, используя 'new', и назначить ее объявленной переменной массива. Следовательно, массивы динамически размещаются в Java.
Давайте обсудим в контексте C ++
Здесь тип объявляет тип данных переменной массива, а размер определяет количество элементов, которые будет содержать массив.
Например, если мы хотим объявить массив, который будет содержать баланс каждого месяца года.
Month _balance — это переменная массива, которая будет содержать 12 целых чисел, которые будут представлять баланс каждого месяца. Теперь, если мы хотим получить доступ к балансу месяца «апрель», мы просто должны упомянуть имя переменной, за которым следует квадратная скобка, содержащая значение индекса для месяца апреля, то есть «month_balance [3]». Но поскольку «апрель» является четвертым месяцем года, но мы упомянули «[3]», потому что все массивы имеют 0 в качестве индекса их первого элемента.
В Java это можно сделать как
Здесь изначально мы объявили переменную массива с ее типом, а затем мы выделили ей память, используя 'new' и присвоив 'new' объявленной переменной массива. Давайте рассмотрим приведенный выше пример, если мы хотим объявить массив, который будет содержать баланс в каждом месяце года.
Здесь «new» выделяет память для переменной массива «month_balance», так что теперь mont_balance теперь будет хранить память для 12 целочисленных значений.
Массивы могут быть инициализированы, когда они объявлены. Инициализатор массива — это список значений, разделенных запятыми, заключенных в фигурные скобки.
//пример
Определение двумерного массива (двумерный массив)
И C ++, и Java поддерживают многомерный массив. Одной из самых простых форм многомерного массива является двумерный массив или двумерный массив. Двумерный массив можно рассматривать как «массив массивов» или «массив одномерных массивов». Чтобы объявить переменную двумерного массива, мы должны указать имя массива, за которым следуют две квадратные скобки, где второй индекс — это второй набор квадратных скобок.
Двумерный массив хранится в форме матрицы строки-столбца, где первый индекс указывает строку, а второй индекс указывает столбец. Второй или самый правый индекс массива изменяется очень быстро по сравнению с первым или самым левым индексом при доступе к элементам массива.
В C ++ двумерный массив объявлен как;
Например, мы хотим хранить остаток каждые 30 дней в каждом месяце года в двумерном массиве.
В Java двумерный массив получается
Поскольку мы не можем передать весь массив в качестве параметра функции, передается указатель на первый элемент массива. Аргумент, получающий двумерный массив, должен определять его самое правое измерение. Крайнее правое измерение требуется, потому что оно требуется компилятору, чтобы подтвердить длину каждой строки, если он хочет правильно проиндексировать массив. Если самый правый индекс не упомянут, компилятор не может определить, где начинается следующая строка.
Когда память динамически выделяется для двумерного массива в Java, указывается крайний левый индекс, а остальные измерения могут выделяться отдельно, т.е. все строки массива могут не иметь одинаковый размер.
Но в этом нет никакого преимущества.
Ключевые различия между одномерным и двумерным массивом
- Одномерный массив — это список, элементы которого имеют схожий тип данных. С другой стороны, двумерный массив представляет собой список, элементами которого являются массивы аналогичного типа данных.
- В C ++, когда одномерный массив получен параметром принимающей функции, нет необходимости упоминать размер массива, поскольку компилятор понимает, что массив типа (упомянутый тип данных вместе с параметром) имеет некоторую длину должен быть получен. В двумерном массиве указывается второй или самый правый индекс, так как компилятору необходимо знать, где заканчивается конец одной строки и начинается новая строка.
- В C ++ одномерный массив хранится в смежной области памяти в индексированном порядке, тогда как двумерный массив также хранится в смежной области памяти, но, поскольку в двумерном массиве есть несколько строк, хранение за первым рядом следует второй, третий и т. д.
Замечания:
Передача как одномерного массива, так и двумерного массива в функцию аналогична, т.е. оба передаются только по имени массива
Заключение:
Как в одномерном, так и в двумерном массиве индекс играет очень важную роль, потому что это единственное, что конкретно идентифицирует элемент в массиве. Как одномерный, так и двумерный массив могут быть инициализированы во время их объявления.
Разница между одномерным (1D) и двумерным (2D) массивом
An массив представляет собой набор переменных с похожими типами данных, названных общим именем. Основная тема нашего обсуждения — разница между одномерным и двумерным массивами. Одномерный массив — это список переменных с одним и тем же типом данных, тогда как двумерный массив — это «массив массивов» с похожими типами данных.
Доступ к определенному элементу в массиве осуществляется по определенному индексу этого массива. Массивы в Java работают иначе, чем в C ++. C ++ не имеет проверки привязки для массивов, тогда как Java имеет строгую проверку привязки для массивов.
Есть несколько факторов, в соответствии с которыми можно различать одномерные и двумерные массивы, например, способ их инициализации, доступа, реализации, вставки, удаления, обхода. Итак, давайте начнем с различий между одномерным и двумерным массивами, а также сравнительную таблицу.
Сравнительная таблица
Определение одномерного массива (одномерного массива)
Одномерный или Одномерный массив рассматривается как «список переменных схожих типов данных», и к каждой переменной можно получить отдельный доступ, указав ее индекс в квадратных скобках, которому предшествует имя этого массива. В C ++ объявления переменной массива с размером достаточно, чтобы выделить для них место в памяти. В Java это достигается в два этапа. Во-первых, вы должны объявить переменную желаемого типа. Во-вторых, вы должны выделить память для хранения массива, используя «новый», и назначить ее объявленной переменной массива. Следовательно, в Java массивы выделяются динамически.
Объявление одномерного массива в C ++
Давайте обсудим в контексте C ++
// объявление в C ++ типа имя_переменной [размер];
Здесь type объявляет тип данных переменной массива, а size определяет количество элементов, которые будет содержать массив. Например, если мы хотим объявить массив, который будет содержать баланс каждого месяца в году.
// пример int month_balance [12];
Месяц _balance — это переменная массива, которая будет содержать 12 целых чисел, которые будут представлять баланс каждого месяца.
Объявление массивов в C ++ также может быть выполнено следующим образом:
Доступ к элементам одномерного массива
Теперь, если мы хотим получить доступ к балансу месяца «апрель», нам просто нужно было упомянуть имя переменной, за которой следует квадратная скобка, содержащая значение индекса для апреля месяца.
Но поскольку «апрель» — это четвертый месяц в году, мы упомянули «[3]» (3 в квадратных скобках), потому что все массивы имеют 0 в качестве индекса своего первого элемента.
Объявление одномерного массива в Java
В Java это можно сделать как
// объявление в Java типа имя_переменной []; имя_переменной = новый тип [размер];
Здесь изначально мы объявили переменную массива с ее типом, а затем мы выделили для нее память с помощью «new» и назначили «new» объявленной переменной массива. Давайте возьмем приведенный выше пример, если мы хотим объявить массив, который будет содержать баланс за каждый месяц года.
// пример int month_balance []; month_balance = новый int [12];
Здесь «new» выделяет память переменной массива month_balance, так что теперь mont_balance будет удерживать память для 12 целочисленных значений.
Массивы могут быть инициализированы при их объявлении. Инициализатор массива — это список значений, разделенных запятыми и заключенных в фигурные скобки.
Определение двумерного массива (2-мерный массив)
И C ++, и Java поддерживают многомерный массив. Одна из простейших форм многомерного массива — это двумерный массив или 2-D массив. Двумерный массив может быть выражен как «массив массивов» или «массив одномерных массивов».
Чтобы объявить двумерную переменную массива, мы должны указать имя массива, за которым следует две квадратные скобки, где второй индекс — это второй набор квадратных скобок.
Двумерный массив хранится в виде матрицы строка-столбец, где первый индекс обозначает строку, а второй индекс показывает столбец. Второй или крайний правый индекс массива изменяется очень быстро по сравнению с первым или крайним левым индексом при доступе к элементам массива.
Объявление и инициализация 2D-массива в C ++
В C ++ двумерный массив объявлен как;
// объявление в C ++ типа имя_переменной [size1] [size2];
Например, мы хотим сохранить баланс каждые 30 дней каждого месяца года в двумерном массиве.
// пример int month_balance [12] [30];
Инициализация 2D-массива очень похожа на 1D-массив. В приведенном ниже примере показана матрица 5 × 2 двумерного массива.
Доступ к элементам 2D-массива
Чтобы получить доступ ко всему 2D-массиву в C ++, мы должны выполнить цикл по строкам и столбцам, как показано ниже, а затем использовать «name_of_the_array [rows] [coloumn]» для печати элементов массива.
Объявление 2D-массива в Java
В Java двумерный массив получается с помощью
// объявление в Java типа имя_переменной = new int [size1] [size2]; // пример int month_balance = new int [12] [30];
Поскольку мы не можем передать весь массив в качестве параметра функции, передается указатель на первый элемент массива. Аргумент, получающий двумерный массив, должен определять его крайнее правое измерение. Крайнее правое измерение требуется, потому что оно необходимо компилятору, чтобы подтвердить длину каждой строки, если он хочет правильно проиндексировать массив. Если крайний правый индекс не указан, компилятор не может определить, где начинается следующая строка.
// пример в Java void receiveing_funct (int a [] [10])
Когда память динамически выделяется для двумерного массива в Java, указывается крайний левый индекс, а остальные измерения могут быть выделены отдельно, т.е. все строки массива могут быть разных размеров.
// пример в Java int month_balance = new int [12] []; month_balance [0] = новый int [31]; month_balance [1] = новый int [28]; month_balance [2] = новый int [31]; month_balance [3] = новый int [30]; month_balance [4] = новый int [31]; month_balance [5] = новый int [30]; month_balance [6] = новый int [31]; month_balance [7] = новый int [30]; month_balance [8] = новый int [31]; month_balance [9] = новый int [30]; month_balance [10] = новый int [31]; month_balance [11] = новый int [30]; month_balance [12] = новый int [31];
Но в этом нет никакого преимущества.
Заметка
Передача как одномерного массива, так и двумерного массива в функцию аналогична, то есть оба передаются только по имени массива.
// пример прохождения_funt (name_of_array);
Расчет адреса
Реализация одномерного массива
Адрес любого конкретного элемента в 1D-массиве можно вычислить по следующему уравнению:
Адрес элемента a [k] = B + W * k
Здесь B — это базовый адрес массива, W — размер каждого элемента массива, а количество элементов, необходимых в массиве, равно k (то есть индекс элемента).
пример
Например, мы хотим найти адрес 6-го элемента одномерного массива «a [10]», базовый адрес которого равен 1000.Размер каждого элемента в этом примере составляет 4 байта. Итак, расчет на основе этого можно произвести следующим образом.
Адрес элемента a [6] = 1000 + 4 * 6
= 1000+24
= 1024
Реализация двумерного массива
Вычисление адреса в 2D-массиве отличается от 1D-массива из-за возникновения концепции строк и столбцов. Есть два типа реализации:
- Строка-мажор — В строке-мажоре элементы читаются построчно.
- Столбец-главный — В-главном столбце проводится столбец за столбцом.
Строка-мажорная реализация
Как мы знаем, в этой реализации строки хранятся одна за другой от первой до последней. Формула, используемая для вычисления адреса элементов в 2D-массиве с использованием мажорной строки:
Адрес элемента a [i] [j] = B + W (n (i-L1) + (j-L2))
Где B обозначает базовый адрес, а W обозначает размер каждого элемента массива, а n — количество столбцов. L1 определяет нижнюю границу строки, а L2 обозначает нижнюю границу столбца.
пример
Предположим, нам нужно найти адрес двумерного массива, расположенного в местоположении a [6,2], имеющего базовый адрес 100 и определенного как [4… 8, -2… 3], в котором хранится 2 байта для каждого элемента.
Во-первых, нам нужно найти количество столбцов n, для которых верхняя граница определенного массива вычитается из нижней границы, т.е. 3 — (- 2), и к результату добавляется единица (так как индексирование начинается с 0) , что дает 6.
Адрес [6] [2] = 100 + 2 (6 (6-4) + (2 — (- 2)))
= 100+2(6×2+4)
= 100+32 = 132
Реализация главного столбца
Реализация с основным столбцом в основном отличается от реализации с основным столбцом в том смысле, что оно хранит столбец за столбцом. Его формула для вычисления адреса элемента аналогична основной строке, за исключением того, что спецификации столбца изменились с учетом спецификаций строки.
Адрес элемента a [i] [j] = B + W (m (j-L2) + (i-L1))
Здесь «m» показывает количество строк.
Вывод
Как в одномерном, так и в двумерном массиве индекс играет очень важную роль, потому что это единственное, что конкретно определяет элемент в массиве. Как одномерный, так и двухмерный массив можно инициализировать во время их объявления.