Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Язык C#. Краткое описание и введение в технологии программирования

.pdf
Скачиваний:
244
Добавлен:
11.03.2016
Размер:
3.16 Mб
Скачать

{

static void Main()

{

int[] m1=new int[4], m2 = new int[] {2,4,6,8}, m3 = {1,3,5,7 };

for (short j = 0; j < 4;) m1[j] = ++j; int сумма = 0 ;

for (short i = 0 ; i <= 3; i++) сумма += m1[i] + m2[i] + m3[i];

Console.WriteLine("{0:d}", сумма);

}

}

Оператор объявления массива в общем случае может состоять из трёх частей. Но уже и первая часть, например int[] m1, представляет собой завершённый оператор. Его исполнение транслятором сводится к созданию ссылки с именем m1. Ссылка – это объект осо-

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

Для инициализации ссылки (задание значения) в языке С# используется оператор new. Его действие сводится к запросу у испол-

няющей системы необходимого фрагмента области динамической памяти. В общем случае область динамической памяти состоит из двух разделов: стека и кучи (heap). Место, где физически будет вы-

делена память, определяется категорией объекта: ссылочные объекты размещаются в области heap, а значащие – в стеке.

Инициализирующий блок может содержать константы, или константные выражения. Если размер массива определён в операции new, то количество инициализаторов должно точно соответствовать

количеству элементов массива. При отсутствии инициализирующего блока элементы массива получают значения по умолчанию (для числовых массивов это – нуль). Оператор new возвращает адрес выде-

ленной области, и затем этим адресом инициализируется ссылка. Аргументами оператора new являются тип и количество элементов, ко-

торые необходимо разместить в динамической памяти. В языке С# нет необходимости заботиться об удалении объектов из динамической области после завершения их обработки. Освобождением памя-

60

ти занимается специальная программа Garbage Collector (сборщик мусора).

Как следует из примера (на с. 60), при наличии блока инициализаторов в операторе объявления массива может быть опущено как количество элементов в операции new (массив m2), так и сама эта опе-

рация (массив m3). Типы констант в блоке инициализации либо

должны соответствовать типу элементов массива, либо должны быть неявно приводимыми к этому типу (расширяющее неявное преобразование).

Переменная сумма является сумматором. Чаще всего сумматор

инициализируется нулем.

Рис. 16 демонстрирует схему размещения массивов.

Стек

m1 адрес

m2 адрес

m3 адрес

Динамическая область (heap)

0

 

1

 

2

 

 

 

3

 

 

 

 

 

 

 

 

 

 

индексы

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0

 

0

 

0

 

 

 

0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0

 

1

 

2

 

 

3

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2

4

6

8

0

1

2

3

1

3

5

7

Рис. 16. Схема размещения массивов

Оператор цикла foreach

Оператор foreach (для каждого) (рис. 17) предназначен для

работы с объектами, состоящими из некоторого набора элементов (их ещё называют коллекциями). Он также может быть использован для массивов. Синтаксис оператора foreach:

foreach ( Элемент in ИмяМассива ) оператор ;

Тип элемента должен совпадать с типом массива. Предыдущий пример (см. с. 60) с использованием оператора foreach выглядит несколько проще. Нужно помнить, что foreach может быть ис-

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

using System; class Массивы2

61

{

static void Main()

{

int[] m1 = new int[4], m2 = new int[] {2,4,6,8}, m3 = {1,3,5,7};

for (short j = 0; j < 4; ) m1[j] = ++j; int сумма = 0 ;

foreach (int j in m1) сумма += j; foreach (int j in m2) сумма += j; foreach (int j in m3) сумма += j;

Console.WriteLine("{0:d}", сумма);

}

}

для j из массива m1

сумма <- сумма +1

Рис. 17. Блок-схема цикла foreach

Базовые приёмы работы с одномерными массивами

Инициализация массивов датчиком случайных чисел

На практике (к примеру, на этапе отладки какого-либо алгоритма) зачастую бывает необходимо наполнить массив произвольными числовыми значениями. Для этого существует специальный класс Random (пространство имён System) генератора псевдослучайных

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

Наиболее часто используемые методы класса Random:

int Next() – возвращает очередное псевдослучайное целое число в диапазоне от 0 до 0x7FFFFFFF;

int Next(int Max) – то же в диапазоне от 0 до max;

62

int Next(int Min, int Max) – в диапазоне от min до max;

double NextDouble() – возвращает очередное псевдослучайное вещественное число в диапазоне от 0,0 до 1,0.

Пример:

using System; class Массивы3

{

static void Main()

{

Random Gen = new Random(); int[] m1 = new int[10];

for (int i = 0; i < 10; i++) m1[i] = Gen.Next(100); int Cчётчик = 0 ;

foreach (int j in m1)

if (j % 2 == 0) Cчётчик++; Console.WriteLine("Массив случайных значений"); for (int i = 0; i < 10; i++ ) Console.WriteLine("m1[{0}] = {1:d}", i, m1[i]);

Console.WriteLine("Количество четных = {0}", Cчётчик);

}

}

В данном примере в первый раз продемонстрирован вызов нестатического метода. Методом называется функция, являющаяся элементом класса. Функция WriteLine является статическим мето-

дом класса Console, и её вызов технологически проще: необходимо

через соединитель-точку указать имя класса и имя метода. Нестатические методы класса могут быть вызваны только в привязке к экземпляру (объекту) класса. Для этого приходится объявлять объект Gen

и выделять ему память (экземпляры класса, как и массивы, являются ссылочными объектами).

63

Листинг предыдущего примера умышленно выполнен без структурирования. В качестве самостоятельного упражнения нарисуйте блок-схему к этому примеру.

Экстремальныезначенияистатистическиехарактеристики элементов массива

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

using System; class Массивы4

{

static void Main()

{

string s; Console.WriteLine

("Задайте количество элементов массива"); s = Console.ReadLine();

int i = Convert.ToInt32(s); int[] mas = new int[i];

Random Gen = new Random();

for (int k = 0; k < mas.Length; k++) mas[k] = Gen.Next(1,10); Console.WriteLine("Элементы массива\n");

foreach (int j in mas) Console.Write("{0,8}", j); int max = mas[0], min = mas [0];

foreach (int j in mas)

{

if (max < j) max = j; if (min > j) min = j;

}

Console.WriteLine("\n Максимум= {0}, Минимум ={1}", max, min);

float среднее=0, дисперсия=0; foreach (int j in mas) среднее+=j; среднее/=mas.Length; Console.WriteLine

64

("\nСреднее арифметическое= {0:f5}", среднее); foreach (int j in mas)

дисперсия+= (j-среднее)*(j-среднее);

дисперсия/=mas.Length; Console.WriteLine("Дисперсия = {0:f5}",дисперсия); Console.WriteLine

("Среднеквадратичное отклонение= {0:f5}",Math.Sqrt(дисперсия));

}

}

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

любого массива есть элементы указанного класса. Здесь используется свойство Length. Пока достаточно сказать, что это – элемент объекта,

с помощью которого можно получить размерность (количество элементов) данного массива. Иным способом может быть использование значение переменной i, ранее введённой с клавиатуры, но использо-

вание свойства Length является универсальным решением.

В этом же примере используется статический метод класса Math c именем Sqrt, который возвращает квадратный корень аргу-

мента.

Методы сортировки одномерных массивов

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

65

Среди наиболее востребованных методов сортировки можно выделить:

метод отбора (еще известен как метод минимакса) (см. рис. 18);

перестановки (или пузырьковой сортировки) (рис. 19);

вставки (рис. 20);

Шелла (рис. 21);

компаранда (рис. 22).

 

0

 

1

 

2

 

 

 

 

 

 

 

 

N–1

Массив

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Первый проход

 

 

 

 

 

 

 

 

 

Поиск максимального

 

 

 

 

 

 

 

 

max1

 

 

 

 

 

 

 

 

 

 

Второй проход

элемента

 

 

 

 

 

 

 

 

 

 

 

 

 

 

max2

 

 

 

 

 

 

 

 

 

 

 

 

 

 

maxN

 

 

 

 

 

 

 

Последний проход

Рис. 18. Сортировка массива по убыванию методом минимакса

Массив

Сравнение соседних элементов: если их отношение не соответствует «направлению» сортировки, они меняются местами

Массив

Важно!

Если на очередном проходе выясняется, что не было произведено ни одной перестановки, значит, массив уже отсортирован!

0 1 2 3

 

 

 

 

 

N–1

 

 

 

 

 

 

 

 

 

 

max1

Первый проход сравнения соседей: максимальный «всплывает» и занимает место последнего элемента

max2

Второй проход сравнения соседей: максимальный «всплывает» и занимает

место предпоследнего элемента

0 1

Последний (N–1)-й проход:

Массив

 

 

сравнение нулевого и первого

 

 

 

 

элемента – массив окончательно

 

 

 

 

 

 

отсортирован

Рис. 19. Сортировка массива по возрастанию методом пузырька

66

Исходный массив

 

 

 

 

Начало: нулевой элемент переписывается

 

 

в итоговый массив

Итоговый массив

 

Первый шаг: первый элемент переписывается в итоговый

 

?

массив на место, соответствующее направлению сорти-

 

ровки – либо до, либо после нулевого элемента

Итоговый массив

 

 

?

 

 

 

 

Второй шаг: второй элемент переписывается в итого-

Итоговый массив

 

вый массив на место, соответствующее направлению

 

сортировки

 

 

Рис. 20. Сортировка массива методом вставки

Массив

Сравнение элементов: если их отношение не соответствует «направлению» сортировки, они меняются местами

Массив

Массив

Первый проход: сравнение элементов, отстоящих друг от друга на три позиции

Второй проход: сравнение элементов, отстоящих друг от друга на две позиции

Последний проход: сравнение соседних элементов

Рис. 21. Сортировка массива методом Шелла

0 1 2 N–1

Исходный массив

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Шаг 1: определяются компаранд: элемент,

 

 

 

компаранд

 

 

 

элементы, значения которых

расположенный в середине (или почти

 

 

 

 

 

 

больше компаранда

в середине) массива

 

 

 

 

 

 

 

 

 

 

 

Элементы, значения которых меньше компаранда

Шаг 2: из исходного массива формируются два раздела: в первый переписываются элементы,

значение которых меньше компаранда, во второй – больше Для каждого из полученных разделов выполняется шаг 1 и шаг 2, пока количество элемен-

тов в получаемых разделах не станет равным единице

Рис. 22. Сортировка массива по возрастанию методом компаранда

67

Пример реализации сортировки методом минимакса:

using System; class Сортировка1

{

static void Main()

{

string s; Console.WriteLine

("Задайте количество элементов массива"); s = Console.ReadLine();

int k = Convert.ToInt32(s); int[] mas = new int[k]; Random Gen = new Random();

for (int i=0; i<mas.Length; i++)mas[i]=Gen.Next(1,100); Console.WriteLine("Элементы массива");

foreach (int j in mas) Console.Write("{0,8}", j); int max , imax;

for (int i = 0; i < mas.Length - 1; i++)

{

max = mas[imax = i];

for ( int j = i + 1 ; j < mas.Length; j++) if (max < mas[j]) max = mas[imax = j];

mas[imax] = mas[i]; mas[i] = max;

}

Console.WriteLine

("\nЭлементы массива после сортировки по убыванию"); foreach (int j in mas) Console.Write("{0,8}", j);

}

}

Пример реализации пузырьковой сортировки:

using System; class Сортировка2

{

static void Main()

68

{

string s;

Console.WriteLine("Задайте количество элементов массива"); s = Console.ReadLine();

int k = Convert.ToInt32(s); int[] mas = new int[k]; Random Gen = new Random();

for (int i=0; i<mas.Length; i++)mas[i]=Gen.Next(1,100); Console.WriteLine("Элементы массива");

foreach (int j in mas) Console.Write("{0,8}", j); int r ;

bool flag = false;

for (int i = 0; i < mas.Length - 1; i++)

{

flag = false;

for ( int j = 0 ; j < mas.Length-i-1 ; j++) if (mas[j] < mas[j + 1]) continue; else

{

r = mas[j];

mas[j] = mas[j + 1]; mas[j+1] = r;

flag = true;

}

if (flag == false) break;

}

Console.WriteLine

("\nМассив после сортировки по возрастанию"); foreach (int j in mas) Console.Write("{0,8}", j);

}

}

Результат аналогичен результату выполнения примера со с. 69.

Двумерные массивы

Объявление двумерных массивов

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

69