Использование массивов в качестве параметров

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

Пример 5.3. Максимальный элемент массива а размера 6 поменять местами с максимальным элементом массива b размера 8. Оформить метод для поиска максимального элемента одномерного массива. Результатом метода являются значение и индекс максимального элемента^

using System;

class Program

{

static void maxx(int[] x,

ref int xmax, ref int imax)

{

xmax = x[0];

imax = 0;

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

{

if (x[i] >= xmax)

{

xmax = x[i];

imax = i;

}

}

}

static void Main()

{

int[] a = new int[]{ 1, 7, 3, 5, 6, 2 };

int[] b = new int[]{ 4, 2, 1, 8, 9, 3, 5, 6 };

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

{

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

}

Console.WriteLine();

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

{

Console.Write("{0:d} ", b[i]);

}

Console.WriteLine();

Console.WriteLine();

int amax = 0, bmax = 0, iamax = 0, ibmax = 0;

maxx(a, ref amax, ref iamax);

maxx(b, ref bmax, ref ibmax);

a[iamax] = bmax; b[ibmax] = amax;

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

{

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

}

Console.WriteLine();

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

{

Console.Write("{0:d} ", b[i]);

}

Console.WriteLine();

}

}

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

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

Пример 5.4. Просуммировать элементы строки матрицы d размера n × m (программа реализована для n = 3, m = 4), содержащей максимальный элемент матрицы. Поиск максимального элемента матрицы осуществлять в методе.

Исходный массив d представим в виде одномерной последовательности с нумерацией индексов от 0 до n × m – 1 (в данном примере n=3, m=4, n*m–1 = 11). Возвращаемым значением метода является номер строки (нумерация с 0), содержащей максимальный элемент матрицы. После нахождения максимального элемента матрицы необходимо просуммировать следующие подряд m элементов, начиная с первого элемента в строке (это элемент с номером ns × m, где ns – номер строки, содержащей максимальный элемент матрицы, строки нумеруются от 0 до n – 1, m – количество элементов в строке).

Результатом работы метода является одно значение – номер строки, содержащей максимальный элемент матрицы. Возможны два варианта организации метода: получить результат как возвращаемое методом значение (вариант 1) или использовать для этого параметр метода (вариант 2). Далее приводятся оба варианта кода. В методе находится индекс максимального элемента в одномерной последовательности imax. Номер строки, содержащей этот элемент, определяется делением этого значения индекса на количество элементов в строке. Вспомним, что при делении двух целых чисел дробная часть отбрасывается.

Вариант 1. Метод возвращает значение:

using System;

class Program

{

const int m = 4;

static int maxx(int[] x)

{

int xmax = x[0];

int imax = 0;

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

{

if (x[i] > xmax)

{

xmax = x[i];

imax = i;

}

}

return imax / m;

}

static void Main()

{

int[] d = new int[] { 1, 7, 3, 5, 6, 2, 9, 3,

8, 3, 6, 1 };

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

{

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

}

Console.WriteLine();

int s = 0;

int ns = maxx(d) * m;

for (int k = ns; k <= ns + m - 1; k++)

s = s + d[k];

Console.WriteLine(s);

Console.ReadKey();

}

}

Вариант 2. Для получения результата используется параметр метода:

using System;

class Program

{

const int m = 4;

static void maxx(int[] x, ref int di)

{

int xmax = x[0];

int imax = 0;

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

{

if (x[i] > xmax)

{

xmax = x[i];

imax = i;

}

}

di = imax / m;

}

static void Main()

{

int[] d = new int[] { 1, 7, 3, 5, 6,

2, 9, 3, 8, 35, 6, 1 };

int di = 0;

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

{

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

}

Console.WriteLine();

int s = 0;

maxx(d, ref di);

int ns = di * m;

for (int k = ns; k <= ns + m - 1; k++)

s = s + d[k];

Console.WriteLine(s);

Console.ReadKey();

}

}

5.3. Использование делегата для передачи метода в качестве параметра в другой метод

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

s1 =

s2 =

Вычисление суммы в методе оформим в общем виде, не конкретизируя зависимость члена суммы от его номера, т.е. оформим функцию для вычисления суммы

S = .

Функция f должна быть включена в список формальных параметров как переменная типа делегат, которая при каждом обращении должна быть заменена фактическим параметром, т.е. именем метода, описывающего вычисление конкретного члена суммы.

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

Ключевое слово delegate используется для объявления ссылочного типа. Делегат это тип, который определяет подпись метода и который можно связать с любым методом с совместимой подписью.

Пример 5.5. В качестве примера приводится программа для решения рассмотренной выше задачи вычисления двух сумм:

using System;

class Program

{

delegate int fi(int i);

static int f1(int i)

{

return i * i;

}

static int f2(int i)

{

return i * i * i;

}

static int si(fi f, int n)

{

int s = 0;

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

{

s = s + f(i);

}

return s;

}

static void Main()

{

int s1 = si(f1,12);

int s2 = si(f2,7);

Console.WriteLine("{0} {1}", s1, s2);

}

}

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

Пример 5.6. Оформить функцию для вычисления . Используя эту функцию, вычислить и . Для вычисления определенного интеграла использовать метод трапеций. Разделим отрезок [a, b] на n отрезков длиной h = (b a)/n. Формула трапеций для вычисления интеграла в этом случае имеет вид

где x1 = a + h; x2 = a + 2h, ....

Выберем n = 20 для вычисления s1 и n = 30 для вычисления s2:

using System;

class Program

{

delegate double fx(double i);

static double f1(double x)

{

return Math.Sin(x)*Math.Sin(x);

}

static double f2(double x)

{

return 1/Math.Sqrt(9 + x * x);

}

static double sw(fx f, double a, double b, int n)

{

double c = 0, x = a, h = (b - a)/n;

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

{

x += h; c += f(x);

}

return (2 * c + f(a) + f(b)) * h / 2;

}

static void Main()

{

double s1 = sw(f1, 0.0, Math.PI/2, 20);

double s2 = sw(f2, 0.0, 2.0, 30);

Console.WriteLine("{0:f4} {1:f4}", s1, s2);

}

}

Пример 5.7. Оформить функцию для вычисления . Используя эту функцию, вычислить и Для вычисления определенного интеграла использовать метод трапеций и метод Симпсона. Для выбора метода использовать перечисление (см. п. 1.6).

Разделим отрезок [a, b] на n отрезков (для метода Симпсона n должно быть четным) длиной h = (b a)/n. Формула трапеций для вычисления интеграла приведена выше.

Формула Симпсона имеет вид

где ci = (–1)i+1 вычисляется как c = –c.

Выберем n =20 для вычисления s1 и n =30 для вычисления s2:

using System;

class Program

{

//объявление перечисления

enum Method { method1, method2 };

delegate double fx(double i);

static double f1(double x)

{

return Math.Sin(x) * Math.Sin(x);

}

static double f2(double x)

{

return 1 / Math.Sqrt(9 + x * x);

}

static double sw(fx f, double a, double b, int n,

Method met)

{

double s = f(a) + f(b), x = a, h = (b - a) / n;

if (met == Method.method1)

{

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

{

x += h; s += 2 * f(x);

}

s = s * h / 2;

}

if (met == Method.method2)

{

double c = 1.0;

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

{

x += h; s += (3 + c) * f(x); c = -c;

}

s = s * h / 3;

}

return s;

}

static void Main()

{

double s1 = sw(f1, 0.0, Math.PI / 2, 20,

Method.method1);

double s11 = sw(f1, 0.0, Math.PI / 2, 20,

Method.method2);

double s2 = sw(f2, 0.0, 2.0, 30,

Method.method1);

double s22 = sw(f2, 0.0, 2.0, 30,

Method.method2);

Console.WriteLine(

"{0:f4} {1:f4} {2:f4} {3:f4}",

s1, s11, s2, s22);

Console.ReadKey();

}

}

Замечание.Среди параметров метода sw для вычисления интеграла имеется параметр met типа Method. При вызове метода в качестве аргумента указывается конкретный элемент списка перечисления, объявленного в начале кода, в соответствии с чем и выбирается способ вычисления интеграла в методе sw.

Вопросы для самопроверки

1. Что такое метод? Разновидности методов: метод, возвращающий значение и метод, не возвращающий значения. Особенности их оформления.

2. Что такое подпись метода?

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

4. Различные возможности взаимного расположения вызываемого и вызывающего методов: в одном классе, в разных классах.

5. Особенности вызова нестатического метода из статического метода.

6. Использование массивов в качестве параметров.

7. Методы как параметры: использование делегата для передачи метода как параметра другого метода.

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

1. Определить, сколькими способами можно отобрать команду в составе пяти человек из восьми кандидатов; из 10 кандидатов; из 11 кандидатов. Использовать метод для подсчета количества способов отбора по формуле

.

2. Два треугольника заданы длинами своих сторон a, b и с. Определить треугольник с большей площадью, вычисляя площади треугольников по формуле Герона

,

где p = (a + b + c)/2.

3. Два велосипедиста одновременно начинают движение из одной точки. Первый начинает движение со скоростью 10 км/ч и равномерно увеличивает скорость на 1 км/ч. Второй начинает движение со скоростью 9 км/ч и равномерно увеличивает скорость на 1,6 км/ч. Определить:

а) какой спортсмен преодолеет большее расстояние через 1 ч,
через 4 ч;

б) когда второй спортсмен догонит первого.

Использовать метод для вычисление пути в зависимости от времени по формуле

S = vt + at2/2,

где v – начальная скорость;
а – ускорение.

4. Поменять местами максимальные элементы матриц А размера 5 × 6 и В размера 3 × 5. Поиск максимального элемента матрицы осуществить в методе.

5. В массивах А размера 9 и В размера 7 заменить максимальные элементы на среднее арифметическое значение элементов, расположенных после максимального, в том массиве, для которого максимальный элемент расположен дальше от конца массива. Поиск максимального элемента осуществить в методе.

6. В матрицах В размера 5 × 5 и С размера 6 × 6 удалить строку, содержащую максимальный элемент на диагонали. Поиск максимального элемента диагонали осуществить в методе.

7. Поменять местами строку матрицы А размера 5 × 5 и столбец матрицы В размера 5 × 5, содержащие максимальные элементы на диагоналях. Поиск максимального элемента на диагонали осуществить в методе.

8. Поменять местами строки матриц А размера 4 × 6 и В размера
6 × 6, содержащие максимальные элементы в 1-м столбце. Поиск максимального элемента в заданном столбце матрицы осуществить в методе.

9. Объединить массивы А размера 7 и В размера 8, предварительно удалив максимальные элементы этих массивов. Результат получить в массиве А. Удаление элемента массива с заданным индексом осуществить в методе.

10. В массив В размера 4 × 5 вставить после строки, содержащей максимальное количество положительных элементов, столбец массива С размера 5 × 6, содержащий максимальное количество положительных элементов. Определение количества положительных элементов в заданной строке (или столбце) матрицы осуществить в методе.

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

12. Даны матрицы А размера 6 × 5 и С размера 7 × 4. Объединить массивы, сформированные из сумм положительных элементов столбцов матриц А и С. Суммирование положительных элементов столбцов с получением результата в виде массива осуществить в методе.

13. Вычислить суммы

Вычисление суммы осуществлять в методе. Для вычисления члена суммы использовать делегата.

14. Японская радиокомпания провела опрос 250 радиослушателей по вопросам:

а) какое животное вы связываете с Японией и японцами?

б) какая черта характера присуща японцам больше всего?

в) какай неодушевленный предмет или понятие вы связываете с Японией?

Большинство опрошенных прислали ответы на все или часть вопросов. Составить программу получения первых пяти наиболее часто встречающихся ответов по каждому вопросу и доли (в %) каждого такого ответа. Предусмотреть необходимость сжатия столбца ответов в случае отсутствия ответов на некоторые вопросы. Обработку информации по каждому вопросу осуществлять в методе.

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

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