Вы находитесь на странице: 1из 48

Перечисления и массивы

1
Перечислимый тип данных
 Перечисление — отдельный тип-значение, содержащий
совокупность именованных констант.
 Пример:
 

enum Color : long Базовый класс - System.Enum.


{ Перечисление может иметь
Red, модификатор (new, public, protected,
Green, internal, private). Он имеет такое же
Blue
значение, как и при объявлении классов.
}
 Каждый элемент перечисления имеет связанное с ним
константное значение, тип которого определяется базовым
типом перечисления.
 Базовые типы: byte, sbyte, short, ushort, int, uint, long и
ulong. По умолчанию – int.

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

enum Button {Start, Stop, Play, Next, Prev }; // неявно


enum Color
{ Red, // 0 неявно
Green = 10, // 10 явно
Blue // 11 неявно
}
enum Nums { two = 2, three, ten = 10, eleven, fifty = ten + 40 };
 Несколько элементов перечисления могут иметь одно и то же
значение.
 Элементы одного перечисления не могут иметь одинаковые
имена.
3
Действия с элементами перечислений
 арифметические операции (+, –, ++, – –)
 логические поразрядные операции (^, &, |, ~)
 сравнение с помощью операций отношения (<, <=, >, >=, ==, !=)
 получение размера в байтах (sizeof)
 вывод на консоль

enum Menu { Read, Write, Edit, Quit };


Menu m, n;

m = Menu.Read; n = m; n++;
if (n > m ) Console.WriteLine(n);

Каждое перечисление определяет отдельный тип; для


преобразования между перечислением и целым типом или между
двумя перечислениями требуется явное приведение типа.

4
enum Color Пример 1
{ Red, Yellow, Green }
class Test
{ static void Main()
{ Color color = Color.Red; // или Color color = 0;
… // изменение color
switch (color)
{
case Color.Red:
Console.WriteLine("Стойте"); break;
case Color.Green:
Console.WriteLine("Идите"); break;
case Color.Yellow:
Console.WriteLine("Ждите"); break;
default:
Console.WriteLine("Светофор сломан");break;
} }
5
enum Color Пример 2
{ Red = 0x000000FF, Green = 0x0000FF00, Blue = 0x00FF0000 }
class Test
{ static void Main()
{ Console.WriteLine(StringFromColor(Color.Green)); }

static string StringFromColor(Color c)


{ switch (c)
{ case Color.Red:
return String.Format("Red = {0:X}", (int)c);
case Color.Green:
return String.Format("Green = {0:X}", (int)c);
case Color.Blue:
return String.Format("Blue = {0:X}", (int)c);
default:
return "Invalid color";
} } }
6
Базовый класс - System.Enum
enum Color { Red, Yellow, Green }
class Test
{ static void Main()
{ Color color = 0;
string[] names = Enum.GetNames(typeof(Color));
foreach (string name in names)
Console.WriteLine(name);
int[] values = (int[])Enum.GetValues(typeof(Color));
foreach (int value in values)
Console.WriteLine(value);
if (Enum.IsDefined(typeof(Color), "Blue"))
Console.WriteLine("Есть такой цвет!");
else Console.WriteLine("Нет такого цвета!");
int x = (int) Enum.Parse(typeof(Color), "Green");
int x = (int) Color.Green;
Console.WriteLine(x);
7
Массивы
 Массив — ограниченная совокупность однотипных
величин
Элементы массива имеют одно и то же имя, а
различаются по порядковому номеру (индексу)
 Виды массивов в C#:
 одномерные
 многомерные (например, двумерные, или прямоугольные)
 массивы массивов (др. термины: невыровненные,
ступенчатые).

8
Создание массива
 Массив относится к ссылочным типам данных, поэтому
создание массива начинается с выделения памяти под его
элементы.
 Элементами массива могут быть величины как значимых, так
и ссылочных типов (в том числе массивы), например:
int[] w = new int[10]; // массив из 10 целых чисел
string[] z = new string[100]; // массив из 100 строк
Monster [] s = new Monster[5]; // массив из 5 монстров
double[,] t = new double[2, 10]; // прямоуг. массив 2х10
int[,,,] m = new int[2,2,2,2]; // 4-xмерный массив
int[][][] a = new int[2][][]; … // массив массивов массивов

 Массив значимых типов хранит значения, массив ссылочных


типов — ссылки на элементы.
 Всем элементам при создании массива присваиваются
значения по умолчанию: нули для значимых типов и null для
ссылочных.
9
Размещение массивов в памяти
Пять простых переменных (в стеке):
a b c d e

Массив из пяти элементов значимого типа (в хипе):


a[0] a[1] a[2] a[3] a[4]

Массив из пяти элементов ссылочного типа (в хипе):


a[0] a[1] a[2] a[3] a[4]

Значение Значение Значение

Значение Значение
10
Размерность массива
 Количество элементов в массиве (размерность)
задается при выделении памяти и не может
быть изменена впоследствии. Она может
задаваться выражением:
short n = ...;
string[] z = new string[2*n + 1];
 Размерность не является частью типа массива.
 Элементы массива нумеруются с нуля.

Для обращения к элементу массива после имени


массива указывается номер элемента в
квадратных скобках, например:
w[4] z[i]

11
Действия с массивами
 С элементом массива можно делать все, что допустимо для
переменных того же типа.
 При работе с массивом автоматически выполняется контроль
выхода за его границы: если значение индекса выходит за
границы массива, генерируется исключение
IndexOutOfRangeException.
 Массивы одного типа можно присваивать друг другу. При этом
происходит присваивание ссылок, а не элементов:
int[] c = new int[10];
int[] b = c; Хип (дин. область)
Значение Значение
// b и c указывают на
// один и тот же массив

Стек
Значение Значение Ссылка Ссылка Ссылка

а b c
x y

Тип-значение Ссылочный тип 12


Одномерные массивы
 Варианты описания массива:
тип[] имя;
тип[] имя = new тип [ размерность ];
тип[] имя = { список_инициализаторов };
тип[] имя = new тип [] { список_инициализаторов };
тип[] имя = new тип [ размерность ]
{ список_инициализаторов };
 Примеры описаний (один пример на каждый вариант
описания, соответственно):
int[] a; // память под элементы не выделена
int[] b = new int[4]; // элементы равны 0
int[] c = { 61, 2, 5, -9 }; // new
подразумевается
int[] d = new int[] { 61, 2, 5, -9 }; // размерность вычисляется
int[] e = new int[4] { 61, 2, 5, -9 }; // избыточное описание

13
Пример

Для массива, состоящего из 6


целочисленных элементов,
программа определяет:
 сумму и количество отрицательных
элементов;
 максимальный элемент.

14
Программа (не лучший способ)
const int n = 6;
int[] a = new int[n] { 3, 12, 5, -9, 8, -4 };
Console.WriteLine( "Исходный массив:" );
for ( int i = 0; i < n; ++i ) Console.Write( "\t" + a[i] );
Console.WriteLine();

long sum_otr = 0; // cумма отрицательных элементов


int num_otr = 0; // количество отрицательных элементов
for ( int i = 0; i < n; ++i )
if ( a[i] < 0 ) {
sum_otr += a[i]; ++num_otr;
}
Console.WriteLine( "Сумма отрицательных = " + sum_otr );
Console.WriteLine( "Кол-во отрицательных = " + num_otr );

int max = a[0]; // максимальный элемент


for ( int i = 0; i < n; ++i )
if ( a[i] > max ) max = a[i];
Console.WriteLine( "Максимальный элемент = " + max );

15
Оператор foreach (упрощенно)
 Применяется для перебора элементов массива.
Синтаксис:
foreach ( тип имя in имя_массива ) тело_цикла;
 имя задает локальную по отношению к циклу
переменную, которая будет по очереди принимать
все значения из массива, например:

int[] massiv = { 24, 50, 18, 3, 16, -7, 9, -1 };


foreach ( int x in massiv ) Console.WriteLine( x );

16
Программа с использованием foreach
int[] a = { 3, 12, 5, -9, 8, -4 };
Console.WriteLine( "Исходный массив:" );
- cумма и количество
foreach ( int elem in a )
отрицательных элементов;
Console.Write( "\t" + elem );
- максимальный элемент.
Console.WriteLine();

long sum_otr = 0; // cумма отрицательных элементов


int num_otr = 0; // количество отрицательных элементов
foreach ( int elem in a )
if ( elem < 0 ) { for ( int i = 0; i < n; ++i )
sum_otr += elem; ++num_otr; if ( a[i] < 0 ) {
sum_otr += a[i]; ++num_otr;
}
}
Console.WriteLine( "sum = " + sum_otr );
Console.WriteLine( "num = " + num_otr );

int max = a[0]; // максимальный элемент


foreach ( int elem in a )
if ( elem > max ) max = elem;
Console.WriteLine( "max = " + max );

17
class Mas_1 // класс для работы с 1-мерным
массивом
{
int[] a = { 3, 12, 5, -9, 8, -4 };

public void PrintMas() // вывод


массива
{ Console.Write("Массив: ");
foreach (int elem in a) Console.Write(" " + elem);
Console.WriteLine();
}

public long SumOtr() // cумма отрицательных


элементов
{
long sum_otr = 0;
foreach (int elem in a)
if (elem < 0) sum_otr += elem;
return sum_otr; }
18
public int NumOtr() // кол-во отрицательных
элементов
{
int num_otr = 0;
foreach (int elem in a)
if (elem < 0) ++num_otr;
return num_otr;
}

public int MaxElem() // максимальный элемент


{
int max = a[0];
foreach (int elem in a) if (elem > max) max = elem;
return max;
}
}

19
class Program
{ static void Main(string[] args)
{
Mas_1 mas = new Mas_1();
mas.PrintMas();

long sum_otr = mas.SumOtr();


if (sum_otr != 0) Console.WriteLine("Сумма отриц. = " + sum_otr);
else Console.WriteLine("Отриц-х эл-тов нет");

int num_otr = mas.NumOtr();


if (num_otr != 0) Console.WriteLine("Кол-во отриц. = " + num_otr);
else Console.WriteLine("Отриц-х эл-тов нет");

Console.WriteLine("Макс. элемент = " + mas.MaxElem());


}
}

20
Пример анализа задания
Найти среднее арифметическое элементов,
расположенных между минимумом и максимумом
 Варианты результата:
 выводится среднее арифметическое
 выводится сообщение «таких элементов нет» (мин. и
макс. рядом или все элементы массива одинаковы)
 Вопрос: если макс. или мин. эл-тов несколько?
 Варианты тестовых данных:
 минимум левее максимума
 наоборот
 рядом
 более одного мин/макс
 все элементы массива равны
 все элементы отрицательные
21
Еще один пример анализа задания
Найти сумму элементов, расположенных между
первым и последним элементами, равными нулю
 Варианты результата:
 выводится сумма
 выводится сообщение «таких элементов нет» (нулевые
эл-ты рядом или их меньше двух)
 Варианты тестовых данных:
 два эл-та, равных нулю, не рядом
 два эл-та, равных нулю, рядом
 один эл-т, равный нулю
 ни одного
 более двух
 …

22
Сортировка выбором

1-й 2-й 3-й 4-й


просмотр: просмотр: просмотр: просмотр:
i=1 20 9 9 9

j=2..5 27 i=2 27 10 10

nmin 9 j=3..5 20 i=3 20 17

17 17 j=4..5 17 i=4 20
nmin

10 nmin 10 27 j=5 27

23
Алгоритм сортировки
 Найти, где расположен минимальный элемент массива
 Поменять его местами с 1-м элементом. Первый элемент
теперь на нужном месте.
Повторить (n-1) раз (i := 1 to n-1):
 Среди элементов, начиная со 2-го, найти, где расположен
 Среди элементов, начиная с i-го, найти, где расположен
минимальный элемент массива
минимальный элемент массива
 Поменять его местами со 2-м элементом. Второй элемент
 Поменять его местами с i-м элементом. i-й элемент теперь на
теперь на нужном месте.
нужном месте.
 Среди элементов, начиная с 3-го, найти, где расположен
минимальный элемент массива
 Поменять его местами с 3-м элементом. Третий элемент
теперь на нужном месте.
 ...
 Среди элементов, начиная с предпоследнего (n-1), найти,
где расположен минимальный элемент массива
 Поменять его местами с (n-1)-м элементом.

24
Обмен значений двух переменных

3
5 5
3

25
Базовый класс Array

Все массивы в C# имеют общий базовый класс


Array, определенный в пространстве имен System.
Некоторые элементы класса Array:
 Length (Свойство) - Количество элементов
массива (по всем размерностям)
 BinarySearch (Статический метод) - Двоичный
поиск в отсортированном массиве
 IndexOf – (Статический метод) - Поиск первого
вхождения элемента в одномерный массив
 Sort (Статический метод) - Упорядочивание
элементов одномерного массива
 Reverse (Статический метод) –
«переворачивание» массива
26
Использование методов класса Array
static void Main()
{
int[] a = { 24, 50, 18, 3, 16, -7, 9, -1 };
PrintArray( "Исходный массив:", a );
Console.WriteLine( Array.IndexOf( a, 18 ) );
Array.Sort(a); // Array.Sort(a, 1, 5);
PrintArray( "Упорядоченный массив:", a );
Console.WriteLine( Array.BinarySearch( a, 18) );
Array.Reverse(a); // Array.Reverse(a, 2, 4);
}
public static void PrintArray( string header, int[] a ) {
Console.WriteLine( header );
for ( int i = 0; i < a.Length; ++i )
Console.Write( "\t" + a[i] );
Console.WriteLine();
}

27
Что вы должны уметь найти в массиве:
 минимум/максимум [по модулю]
 номер минимума/максимума [по модулю]
 номер первого/второго/последнего
положительного/отрицательного/нулевого эл-та
 сумма/произведение/количество/сред. арифм-е
положительных/отрицательных/нулевых эл-тов

 упорядочить массив НЕ методом пузырька.

 анализировать все возможные варианты


расположения исходных данных

28
Прямоугольные массивы
 Прямоугольный массив имеет более одного измерения. Чаще
всего в программах используются двумерные массивы. Варианты
описания двумерного массива:
тип[,] имя;
тип[,] имя = new тип [ разм_1, разм_2 ];
тип[,] имя = { список_инициализаторов };
тип[,] имя = new тип [,] { список_инициализаторов };
тип[,] имя = new тип [ разм_1, разм_2 ]
{ список_инициализаторов };
 Примеры описаний (один пример на каждый вариант описания):
int[,] a; // элементов нет
int[,] b = new int[2, 3]; // элементы равны 0
int[,] c = {{1, 2, 3},
{4, 5, 6}}; // new подразумевается
int[,] c = new int[,] {{1, 2, 3}, {4, 5, 6}}; // разм-сть вычисляется
int[,] d = new int[2,3] {{1, 2, 3}, {4, 5, 6}}; // избыточное описание
29
 К элементу двумерного массива обращаются,
указывая номера строки и столбца, на пересечении
которых он расположен:

a[1, 4] b[i, j] b[j, i]

 Компилятор воспринимает как номер строки


первый индекс, как бы он ни был обозначен в
программе.

30
Начало

Пример
Ввод массива

sred = 0
Программа определяет:
 среднее i = 1, m
арифметическое всех
n_pos_el = 0
элементов;
 количество j = 1, n
положительных
sred = sred + aij
элементов в каждой да
строке inc(n_pos_el)
aij > 0

для целочисленной
матрицы размером Вывод n_pos_el
3 х 4

sred = sred / m / n

Вывод sred

Конец 31
0 ... n-1

0
a00 a01 a02 a03

...
const int m = 3, n = 4; a10 a11 a12 a13
m
int[,] a = new int[m, n] { m-1
{ 2,-2, 8, 9 }, a20 a21 a22 a23

{-4,-5, 6,-2 },
{ 7, 0, 1, 1 }
};
n
Console.WriteLine( "Исходный массив:" );
for ( int i = 0; i < m; ++i )
{ for ( int j = 0; j < n; ++j )
Console.Write( "\t" + a[i, j] );
Console.WriteLine();
}

32
int nPosEl;
for ( int i = 0; i < m; ++i ) - среднее арифметическое
{ всех элементов;
nPosEl = 0; - количество положительных
элементов в каждой строке
for ( int j = 0; j < n; ++j )
if ( a[i, j] > 0 ) ++nPosEl;
Console.WriteLine( "В строке {0} {1} положит-х эл-в",
i, nPosEl);
}

double sum = 0;
foreach ( int x in a ) sum += x; // все элементы массива!
Console.WriteLine( "Среднее арифметическое всех элементов: "
+ sum / m / n );

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

34
Описание ступенчатого массива
тип[][] имя;

Под каждый из массивов, составляющих ступенчатый массив,


память требуется выделять явным образом:

int[][] a = new int[3][]; // память под ссылки на 3 строки


a[0] = new int[5]; // память под 0-ю строку (5 эл-в)
a[1] = new int[3]; // память под 1-ю строку (3 эл-та)
a[2] = new int[4]; // память под 2-ю строку (4 эл-та)

Или:
int[][] a = { new int[5], new int[3], new int[4] };

Обращение к элементу ступенчатого массива:


a[1][2] a[i][j] a[j][i]

35
Пример
int[][] a = new int[3][];
a[0] = new int [5] { 24, 50, 18, 3, 16 };
a[1] = new int [3] { 7, 9, -1 };
a[2] = new int [4] { 6, 15, 3, 1 };
Console.WriteLine( "Исходный массив:" );
for ( int (i int
foreach = 0;[] imas1
< a.Length;
in a ) ++i )
{{
for ( int j=0;
foreach ( int jx <
ina[i].Length;
mas1 ) ++j)
Console.Write("\t"
Console.Write( "\t"++xa[i][j]
); );
Console.WriteLine();
Console.WriteLine();
}}
// поиск числа 18 в нулевой строке:
Console.WriteLine( Array.IndexOf( a[0], 18 ) );

36
Эффективность работы с двумерными массивами

30

25

20

Время 15 прямоугольные
ступенчатые

10

создание обработка

37
Передача массивов как параметров метода
class Program { - сумма всех элементов;
static void Main(string[] args) - номера строк,
{ const int n = 3, m = 4; содержащих нули
double[,] a = new double[n, m] {{2,3,4,7}, {4,3,2,0}, {2,0,1,8}};
Console.WriteLine("Сумма элементов: " + Sum(a));
bool[] nums = RowsWithNulls(a, n, m);
Console.Write("Номера строк, содержащих нули: ");
for (int i = 0; i < n; ++i)
if (nums[i]) Console.Write(" " + i);
}
static double Sum(double[,] x)
static bool[] RowsWithNulls(double[,] x, n,m)
{{ bool[]
doublenums
sum == 0;
new bool[n];
foreach
for( int i (double
= 0; i <elem in x) sum += elem;
n; ++i)
for(sum;
return int j = 0; j < m; ++j)
} if(Math.Abs(x[i,j]) < 1e-9) nums[i] = true;
return nums;
}
}
38
13

Случайные числа

 Для генерации случайных чисел в программах,


написанных на C#, предназначен класс Random
Random rand = new Random();
Сначала создаем объект типа Random, потом
вызываем его метод Next, и получаем случайное число

int a;
a = rand.Next(100);
Создаем переменную а и помещаем в нее
случайное число из интервала от 0 до 99
14

Случайные числа
int a;
a = rand.Next(10, 51);
Создаем переменную а и помещаем
в нее случайное число из интервала
от 10 до 50

double a;
a= Convert.ToDouble(rand.Next(10001))/100;
Создаем переменную а и помещаем в нее
случайное дробное число из интервала от
1 до 100 с точностью до сотых
23
Задача. Заполнить массив из n чисел случайными
числами из интервала от -10 до 10, и вывести его на
экран
Random rand = new Random();
double [] a = new double [100];
Console.Write("Введи n= ");
int n = Convert.ToInt32(Console.ReadLine());
for (int i = 0; i < n; i++)
{
a[i]=rand.Next(-10,11);
Console.Write(a[i]+"; ");
}
24
Задача. Найти среднее арифметическое
положительных элементов массива

double s = 0;
double k = 0;
for (int i = 0; i < a.Length; i++)
{
if (a[i] > 0) {
s+ = a[i]; k++;
};
}
Console.WriteLine("Сумма положительных " + s);
Console.WriteLine("Количество положительных "+k);
double sr = s / k;
Console.WriteLine("Ср.арифм. положительных "+sr);
25

Выравнивание с помощью пробелов


Для выравнивания числа по правому краю используется запятая
перед двоеточием. То есть, ставится запятая, а следом идет число,
которое указывает, сколько пробелов должно быть. Пример:
"0,10:0.0".
Для выравнивания по левому краю, шаблон будет таким же, за
исключением того, что число пробелов должно быть указано со
знаком минуса.
P.S. Этот способ можно использовать только с помощью
метода String.Format

String.Format("{0,10:0.0}", 123.4567); // " 123.5"


String.Format("{0,-10:0.0}", 123.4567); // "123.5 "
String.Format("{0,10:0.0}", -123.4567); // " -123.5"
String.Format("{0,-10:0.0}", -123.4567); // "-123.5 "
26

Цифры перед точкой


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

String.Format("{0:00.0}", 123.4567); // "123.5"


String.Format("{0:00.0}", 23.4567); // "23.5"
String.Format("{0:00.0}", 3.4567); // "03.5"
String.Format("{0:00.0}", -3.4567); // "-03.5"
27

Цифры после точки


В этом примере демонстрируется перевод вещественного
числа в строку с фиксированным числом десятичных
знаков. Например, для двух знаков используется
шаблон "0.00". Если вещественное число содержит менее
десятичных знаков, то оставшиеся позиции
справа заполняются нулями, если же число знаков
больше — производится округление.

String.Format("{0:0.00}", 123.4567); // "123.46"


String.Format("{0:0.00}", 123.4); // "123.40"
String.Format("{0:0.00}", 123.0); // "123.00"
28

Задача. Заполнить массив N x N случайными


числами [-10; 10], и вывести его на экран.
Random rand = new Random();
int [,] a = new int[100,100];
Console.Write("Введи n= ");
int n = Convert.ToInt32(Console.ReadLine());

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


{
for (int j = 0; j < n; j++)
{
a[i, j] = rand.Next(-10, 10);
Console.Write("{0,5:0}",a[i, j]);
}
Console.WriteLine();
}
29

Console.Write("{0,5:0}",a[i, j]);

Целые числа

«Ровная»
таблица

Console.Write("{0,5:0.0}",a[i, j]);

Дробные
числа

5 позиций для
числа
30

Массив констант (изменять нельзя)


Две константы целого типа

const int m = 3, n = 3;
int[,] a = new int[m, n]
{
{ 1, 1, 1 },
{ 2, 2, 2 },
{ 3, 3, 3 }
};
Значения
массива

Оценить