Одномерные массивы

Лабораторная работа №9.

Массивы в C #

Массивом называется упорядоченная совокупность элементов одного и того же типа, объединенных одним именем. Каждому элементу массива соответствует свой номер (индекс), задающий порядок расположения элементов в массиве. Следует отметить, что в C # нумерация элементов начинается с нуля.

Язык программирования C # предоставляет возможность работать с одномерными, многомерными (прямоугольными) и ступенчатыми массивами.

Одномерные массивы

Синтаксис описания одномерного массива в общем виде:

<ТипЭлементов>[] <ИмяМассива> {<Инициализация>};

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

В языке C # массивы относятся к ссылочным типам данных, поэтому создание массива как объекта представляет собой двухступенчатый процесс: сначала объявляется ссылочная переменная, а затем выделяется память под требуемое количество элементов базового типа, и ссылочной переменной присваивается адрес нулевого элемента массива.

Объявление переменной для массива и выделение необходимого объема памяти может быть разделено; кроме того, на этапе объявления массива можно произвести его инициализацию. Рассмотрим более подробно конкретные способы описания и инициализации одномерного массива (рис. 9.1).

Рис. 9.1. Способы описания одномерного массива

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

<ТипЭлементов>[] <ИмяМассива>;

Пример:

int[] MyArray;

Здесь описан одномерный массив MyArray, предназначенный для хранения целых чисел. При таком способе описания сам массив не формируется, поэтому прежде чем работать с таким массивом, его нужно будет проинициализировать.

В связи с этим иногда бывает гораздо удобнее использовать способ описания массива с инициализацией. При этом возможны два варианта инициализации массива.

Первый вариант – это явная инициализация с указанием конкретных значений элементов. В этом случае, значения элементов перечисляются через запятую и заключаются в фигурные скобки:

<ТипЭлементов>[] <ИмяМассива> = {<ЗначенияЭлементов>};

Пример:

int[] MyArray = {1, 2, 3};

Здесь формируется одномерный массив целых чисел из трех элементов с конкретными значениями, формируется ссылка на массив. В дальнейшем с таким массивом уже можно работать без использования конструктора.

Второй вариант инициализации предполагает использование конструктора:

<ТипЭлементов>[] <ИмяМассива> = new <ТипЭлементов> [<Размерность>];

Пример:

int[] MyArray = new int [10];

Здесь формируется целочисленный массив из десяти элементов, которым присваиваются начальные значения (нули), и формируется ссылка на массив. Подчеркнем, что при подобной инициализации массива его элементам присваиваются значения по умолчанию, т. е. например нули для арифметических типов, null для ссылочных типов.

Следует отметить, что второй способ инициализации массива не исключает возможность задания конкретных значений элементов, однако в этом случае необходимо исключить ошибку несоответствия размерности массива, определяемой в конструкторе, и количества элементов массива, заданных явно. Например:

int[] MyArray = new int [4] {1, 8, 5, 2};

Здесь формируется целочисленный массив из четырех элементов с конкретными значениями, и устанавливается ссылка на массив. Чтобы исключить ошибку, возможен способ описания массива без указания в конструкторе его размерности. Например:

int[] MyArray = new int [] {9, 7, 1, 2, 6};

В этом случае размерность массива определяется автоматически.

Рассмотрим основные методы работы с одномерными массивами.

Прежде чем работать с одномерным массивом, его необходимо описать, а далее, определить значения его элементов. Это можно сделать явно при описании массива (см. выше). Однако этот способ не всегда удобен, например, в случае, когда размерность массива достаточно велика. Тогда можно использовать, например, один из следующих способов: заполнение массива по некоторой формуле, заполнение целочисленного массива случайными числами и считывание элементов массива с клавиатуры либо из файла.

Проиллюстрируем способы заполнения одномерного массива на конкретных примерах.

В качестве первого примера сформируем одномерный массив и заполним его 20 первыми членами последовательности Фибоначчи. Напомним, что в последовательности Фибоначчи первые два элемента равны единице, а каждый последующий равен сумме двух предыдущих: f (0) = f (1) = 1, f (n) = f (n – 1) + f (n – 2) для n = 2, 3,…, т. е. это бесконечная последовательность вида 1, 1, 2, 3, 5, 8, 13, 21 и т. д.

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

const byte ArraySize=20; //размерность массива

int[] F = new int [ArraySize]; //описание массива c инициализацией

Так как массив представляет собой набор элементов, объединенных общим именем, то обработка массива чаще всего выполняется в цикле. Заполнение массива будет выполняться следующим образом (напомним, что обращение к элементу массива осуществляется по имени массива с указанием в квадратных скобках номера элемента):

F[0] = 1;

F[1] = 1;

for (int i = 2; i < ArraySize; i++)

F[i] = F[i - 1] + F[i - 2];

Отметим, что при необходимости изменить размерность массива, достаточно просто изменить значение константы ArraySize.

Далее сформируем одномерный массив из 20 элементов типа byte и заполним его случайными числами.

Само описание и инициализация массива выполняются так:

const byte ArraySize=20; //размерность массива

//описание массива с указанием размерности (выделяем память)

byte [] MyArray = new byte [ArraySize];

В языке C # для генерации случайных чисел предусмотрен специальный класс Random. Для того чтобы воспользоваться методами этого класса, необходимо создать экземпляр класса с помощью конструктора.

Конструктор по умолчанию (без параметров) позволяет генерировать неповторяющееся при каждом запуске случайное число или последовательность чисел. Второй способ реализации конструктора требует указания целого числа в качестве параметра и позволяет генерировать случайное число или последовательность чисел, повторяющуюся при условии задания одного и того же значения параметра.

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

Таблица 9.1

Некоторые методы класса Random

Метод Способ вызова Описание
Next () Next () Возвращает положительное целое число из всего диапазона int
Next (int maxValue) Возвращает положительное целое число из диапазона [0, maxValue - 1]
Next (int minValue, int maxValue) Возвращает положительное целое число из диапазона [ minValue, maxValue ]
NextDouble () NextDouble () Возвращает вещественное число из диапазона [0,1)
NextBytes () NextBytes (byte [] buffer) Позволяет генерировать последовательность случайных чисел из всего диапазона byte, которую записывает в одномерный массив buffer

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

1-й способ:

Random Rand = new Random(); //создаем экземпляр класса Random

//заполняем массив случайными числами

for (int i = 0; i < ArraySize; i++)

MyArray[i] = Rand.Next();

2-й способ:

Random Rand = new Random(); //создаем экземпляр класса Random

//заполняем массив случайными числами

Rand.NextBytes(MyArray);

Следует отметить, что в случае, когда необходимо заполнить массив случайными числами из некоторого определенного диапазона, второй из рассмотренных выше способов не подойдет.

Теперь заполним одномерный массив целых чисел с клавиатуры. Напомним, что считывание строки с клавиатуры осуществляется с помощью оператора Console. ReadLine (), который возвращает введенную пользователем строку. Отсюда самый простой способ заполнить одномерный массив с клавиатуры – поэлементно с использованием операции преобразования строки в число. При этом необходимо обработать исключительную ситуацию в случае невозможности подобного преобразования.

byte ArraySize; //размерность массива

try

{ //размерность массива определяется пользователем

Console.WriteLine("Введите размерность массива");

ArraySize = byte.Parse(Console.ReadLine());

//описание массива с выделением памяти

int[] MyArray = new int[ArraySize];

//заполнение массива c клавиатуры

Console.WriteLine("Введите элементы массива");

for (int i = 0; i < ArraySize; i++)

MyArray[i] = int.Parse(Console.ReadLine());

}

catch

{

Console.WriteLine("Ошибка ввода");

}

Считывание элементов массива с клавиатуры можно организовать и по-другому. Для этого воспользуемся возможностями языка C # и преобразуем строку, считанную с клавиатуры и представляющую собой последовательность целых чисел, разделенных пробелом, сразу в одномерный массив.

int ArraySize;

try

{

Console.WriteLine("Введите размерность массива");

ArraySize = byte.Parse (Console.ReadLine());

int[] MyArray = new int[ArraySize];

Console.WriteLine("Введите элементы массива");

for (int i = 0; i < ArraySize; i++)

{

Console.Write("MyArray[{0}]=", i);

MyArray[i] = int.Parse(Console.ReadLine());

}

}

catch (FormatException e)

{

Console.WriteLine(e);

}

Здесь пользователь вводит размерность массива, а затем и сами элементы.

Часто в программах более удобным способом заполнения массива является считывание элементов массива из файла. Этот способ будет рассмотрен в теме “ Основы работы с файлами в C # ”.

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

for (int i = 0; i < ArraySize; i++)

Console.Write("{0} ", MyArray[i]);

Однако в языке C # предусмотрен специальный оператор – цикл перебора foreach, позволяющий просматривать последовательно все элементы массива по порядку, не указывая количество элементов. Его синтаксис:

foreach (<ТипЭлементовМассива> <ПараметрЦикла> in <ИмяМассива>)

<Оператор>;

Оператор цикла foreach может использоваться для просмотра элементов одномерного, многомерного массивов, а также любой коллекции.

Подчеркнем, что в теле цикла управляющая переменная цикла будет принимать значение очередного элемента массива только в определенном порядке: от первого элемента к последнему. Преимущество использования этого оператора состоит в том, что он исключает возможность возникновения ошибки выхода за пределы массива. Однако следует помнить, что в цикле foreach не разрешено изменять значения элементов массива, можно их лишь перебирать, просматривать.

Вывод массива на экран с использованием оператора foreach можно записать следующим образом:

foreach (int element in MyArray)

Console.Write(element + " ");

Используя цикл foreach, невозможно выйти за границы массива, что в C # расценивается как ошибка, из-за которой генерируется исключение IndexOutOfRangeException.

Продемонстрируем рассмотренные выше методы работы с одномерными массивами на примере решения следующей задачи: сформировать одномерный массив из 10 элементов и заполнить его случайными числами из диапазона [–20, 20], найти максимальный элемент массива.

static void Main(string[] args)

{

const int ArraySize = 10;

int[] MyArray = new int[ArraySize];

int MaxElement = int.MinValue;

Random Rand = new Random();

for (int i = 0; i < ArraySize; i++)

MyArray[i] = Rand.Next(-20, 20);

foreach (int element in MyArray)

{

if (element > MaxElement) MaxElement = element;

Console.Write("{0} ", element);

}

Console.WriteLine();

Console.WriteLine("Максимальный элемент массива = {0}",

MaxElement);

Console.ReadKey();

}

Здесь мы вводим вспомогательную переменную MaxElement и изначально заносим в нее минимальное допустимое значение типа int. Далее заполняем массив случайными числами из заданного диапазона и в цикле foreach осуществляем поиск максимального элемента и одновременно вывод массива на экран.

При решении более сложных задач, включающих в себя такие операции как сортировка массива, поиск заданного элемента в массиве и др., удобно воспользоваться встроенными методами, которые предоставляет класс Array. Отметим, что класс Array является базовым классом для любого массива в C # и содержит большой набор свойств и методов. Некоторые из них приведены в таблице 7.2.

Таблица 9.2

Некоторые свойства и методы класса Array

Элемент Вид Описание
Length свойство Количество элементов массива (по всем размерностям)
BinarySearch () статический метод Двоичный поиск в отсортированном массиве
Clear () статический метод Присваивание элементам массива значений по умолчанию (0 для арифметического, false для логического, null для ссылочного типа)
Copy () статический метод Копирование заданного диапазона элементов одного массива в другой
CopyTo () экземплярный метод Копирование всех элементов текущего одномерного массива в другой массив
Find () статический метод Поиск первого элемента, удовлетворяющего заданному условию
FindAll () статический метод Возвращает одномерный массив элементов, удовлетворяющих заданному условию
FindIndex () статический метод Возвращает индекс первого вхождения элемента, удовлетворяющего заданному условию
FindLast () статический метод Возвращает последнее вхождение элемента, удовлетворяющего заданному условию
FindLastIndex () статический метод Возвращает индекс последнего вхождения элемента, удовлетворяющего заданному условию
GetLength () экземплярный метод Количество элементов в заданном измерении массива
GetValue () экземплярный метод Получение значения элемента массива
IndexOf () статический метод Поиск первого вхождения элемента в одномерный массив
LastIndexOf () статический метод Поиск последнего вхождения элемента в одномерный массив
Rank свойство Количество измерений массива
Reverse () статический метод Изменение порядка следования элементов на обратный
SetValue () экземплярный метод Установка значения элемента массива
Sort () статический метод Сортировка элементов массива

Отметим, что вызов статических методов выполняется через обращение к имени класса, а массив передается методу в качестве параметра. Например:

Array.Sort(MyArray);

Обращение к свойству или вызов экземплярного метода выполняется через обращение к экземпляру класса. Например:

int k = MyArray.Length;

Рассмотрим некоторые свойства и методы подробнее. Первый пример:

int[] A = new[] { 1, 2, 3, 4, 5 };

int[] B = A;

B[2] = 55;

Console.Write(A[2]);

Поскольку массив является ссылочным объектом, то присваивая одному массиву другой, мы присваиваем ссылку на массив, т. е. в нашем примере после операции присваивания A и B указывают на одну и ту же область памяти, и при изменении значения элемента массива B одновременно меняется и соответствующий элемент массива A. Таким образом, на экран выводится число 55. Чтобы A и B стали разными массивами, значения элементов которых совпадают, необходимо воспользоваться методом Copy () или CopyTo (). Например:

int[] A = new[] { 1, 2, 3, 4, 5 };

int[] B = new int[5];

Array.Copy(A, B, 5); // или A.CopyTo(B, 0);

B[2] = 55;

Console.Write(A[2]);

Здесь массив B получается путем копирования массива A и изменение элементов B не влияет на элементы A. В методе Copy () в качестве параметров передаются массив-источник (который копируется), массив-приемник (в который копируется) и количество элементов. Метод CopyTo () в качестве параметров получает массив-приемник и индекс, с которого в него будет произведено копирование. При любом из этих вариантов на экран выводится число 3.

Рассмотрим на примере использование статического метода Find (). Метод Find () возвращает первое вхождение элемента, удовлетворяющего заданному условию, а если такого элемента в массиве нет, то возвращает значение по умолчанию. Его синтаксис:

Find(<ИмяМассива>, <Предикат>)

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

static void Main()

{

//инициализация массива

int[] MyArray = new int[] { 1, -4, 6, 6, -45, 90, 12, 4, 0 };

//вывод массива на экран

foreach (int element in MyArray)

Console.Write(element + " ");

Console.WriteLine();

//поиск первого отрицательного элемента массива

int N = Array.Find(MyArray, Negative);

Console.WriteLine("Первый отрицательный элемент = {0}", N);

Console.ReadKey();

}

//предикат

static bool Negative(int element)

{

if (element < 0) return true; else return false;

}

Здесь метод Find () осуществляет поиск первого вхождения отрицательного элемента массива.

Статический метод FindAll () возвращает одномерный массив элементов, удовлетворяющих заданному условию. Его синтаксис аналогичен синтаксису метода Find ():

FindAll(<ИмяМассива>, <Предикат>)

Рассмотрим пример использования:

static void Main()

{

//инициализация исходного массива

int[] MyArray = new int[] { 1, 415, 65, 6, 45, 90, 1, 4, 509 };

Console.Write("Исходный массив: ");

PrintArray(MyArray); //вывод исходного массива на экран

// формирование нового массива

// из всех элементов исходного массива,

// являющихся двузначными числами

int[] Rez = Array.FindAll(MyArray, TwoDigit);

//вывод результирующего массива на экран

Console.Write("Двузначные элементы массива: ");

PrintArray(Rez); //вывод результирующего массива на экран

Console.ReadLine();

}

static void PrintArray(int[] array) //метод распечатки массива

{

foreach (int element in array) Console.Write(element + " ");

Console.WriteLine();

}

static bool TwoDigit(int element) //предикат

{

if (element > 9 && element < 100) return true;

else return false;

}

Здесь метод FindAll () осуществляет поиск всех элементов исходного массива MyArray, являющихся двузначными числами, и формирует результирующий одномерный массив Rez.

Укажем еще один вид параметров, которые можно передавать в методы – это массив параметров, для которого указывается ключевое слово params. Он позволяет передавать в метод переменное число параметров. В списке параметров не может быть больше одного такого параметра, причем он всегда стоит последним. params задает массив произвольного типа, при вызове метода этому формальному параметру соответствует произвольное число фактических параметров (последнему формальному параметру, если он объявлен с ключевым словом params, ставятся в соответствие все оставшиеся фактические аргументы).

Рассмотрим пример.

class Program

{

static int sum(params int[] a)

{

int s = 0;

for (int i = 0; i < a.Length; i++)

s += a[i];

return s;

}

static void Main()

{

Console.WriteLine(sum(1, 2, 3));

Console.WriteLine(sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));

Console.ReadKey();

}

}

Использование перегрузки методов, а также массивов параметров позволяет гибко работать с методами в зависимости от параметров.

Задания для самостоятельного выполнения:

1. Подсчитать среднее арифметическое всех положительных элементов массива.

2. Подсчитать количество четных элементов массива, стоящих на нечетных позициях.

3. Вывести на экран номера всех элементов, попадающих в диапазон [ A.. B ] (целые числа A и B вводятся с клавиатуры).

4. Вывести на экран значение максимального элемента и их количество.

5. Заменить все минимальные элементы нулями.

6. Поменять порядок элементов массива, расположенных между первым максимальным и последним минимальным элементами, на обратный.

7. Отсортировать элементы массива, расположенные между первым положительным и последним отрицательным элементами массива.

8. Найти количество пар соседних элементов, сумма которых равна заданному числу.

9. В исходном массиве из n элементов встречаются по одному разу все целые числа от 0 до n, кроме одного. Найти пропущенное число.

10. Дан неубывающий массив (в котором каждый следующий элемент не больше последующего). Найти количество различных чисел среди элементов массива.

11. Даны два возрастающих массива. Найти количество совпадающих элементов в этих массивах.

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

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

14. Удалить первый отрицательный элемент, если такой элемент имеется.

15. Удалить все повторяющиеся элементы, оставив только их первые вхождения, то есть получить массив различных элементов.

16. Вставить элемент, равный нулю, перед всеми элементами, кратными заданному числу A.

17. Вставить элемент, равный минимальному элементу всего массива, перед всеми элементами, равными максимальному элементу.

18. Найти сумму положительных элементов массива.

19. Изменить знак у максимального по модулю элемента массива.

20. Поменять местами максимальный и минимальный элементы всего массива.

21. Определить, есть ли в массиве элемент, равный заданному числу. Если есть, то вывести номер одного из таких элементов.

22. Заполнить массив следующим образом:

             
             
             
             
             
             
             

23. Заполнить массив следующим образом:

             
             
             
             

24. Заполнить массив следующим образом:

           
           
           
           
           
           

25. Заполнить массив следующим образом:

           
           
           
           
           
           

26. Заполнить массив размера 6×6 случайным образом неповторяющимися числами от 0 до 35.

27. Определить, является ли массив симметричным относительно главной диагонали.

28. Определить, является ли массив логическим квадратом (суммы по всем горизонталям, вертикалям и двум диагоналям равны).

29. Заменить все отрицательные элементы на сумму их соседей (соседними являются элементы, расположенные на одну строку выше или ниже в том же столбце или на один столбец левее или правее в той же строке; в зависимости от положения элемента количество его соседей может быть два, три или четыре).

30. Найти количество элементов в каждой строке массива, больших среднего арифметического элементов данной строки.

31. Определить, есть ли в данном массиве строка, состоящая только из положительных элементов. Если есть, то поменять ее местами со средней строкой (при нечетном количестве строк).

32. Определить, есть ли в данном массиве столбец, содержащий ровно два отрицательных элемента. Если есть, то переставить этот столбец после последнего столбца (количество столбцов остается неизменным).

33. Сформировать одномерный массив, каждый элемент которого равен номеру первого отрицательного элемента соответствующего столбца исходного массива.

34. Отсортировать столбцы массива по неубыванию минимальных элементов в них (можно сформировать промежуточный одномерный массив минимумов).

35. Определить, есть ли в массиве строка, в которой имеется ровно два максимальных элемента всего массива. Если есть, то поменять местами средние столбцы (столбцов должно быть четное количество) друг с другом.

36. Вставить строку из нулей перед каждой строкой исходного массива, в которой имеются повторяющиеся элементы.

37. Удалить строку и столбец, на пересечении которых находится минимальный элемент массива.

38. Удалить столбцы, в которых все элементы положительные.

39. Удалить первую строку, в которой равное количество положительных и отрицательных элементов.

40. Разработайте программу, запрашивающую координаты коня и определяющую поля, находящиеся под боем. Конь изображается буквой ‘H’, поля под боем – красными точками.

41. Разработайте программу заполнения и вывода на форму арифметического квадрата размером 10×10 (в нем первый столбец и первая строка заполнены 1, а каждый из остальных элементов равен сумме своих соседей сверху и слева).


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: