Содержание
Задача: даны два массива a
и b
размерностью n
и m
соответственно, сформировать массив c
таким образом, что первая часть — отсортированный по возрастанию массив а
, а вторая часть — отсортированный по убыванию массив b
.
Визуализация задачи
Прежде, чем приступим к написанию кода, представим, что должна будет выполнять наша программа. Итак, в задаче определено, что даны два одномерных массива, с некоторой размерностью, например, два массива целых чисел размерностью 5 и 3, соответственно:
int[] a = new int[5] { 2, 4, 5, 1, 4 }; int[] b = new int[3] { 9, 1, 4 };
далее, необходимо отсортировать первый массив по возрастанию, то есть получить вот такой массив a
:
1, 2, 4, 4, 5
второй массив необходимо отсортировать по убыванию (от большего к меньшему), то есть, получить следующий массив:
9, 4, 1
и, на третьем шаге, мы должны объединить два массива в один, то есть получить вот такой массив чисел в качестве ответа:
1, 2, 4, 4, 5, 9, 4, 1
Разобравшись с тем, как должна работать наша программа, перейдем к следующему шагу — выявлению неопределенностей (неточностей) в формулировке самой задачи.
Неопределенности задачи
Первое: какой тип данных у массивов?
Теоретически, отсортировать в порядке возрастания и убывания можно всё, что угодно. Учитывая, что лабораторная работа выполняется, в основном, неподготовленными или слабо подготовленными людьми, примем, что массивы у нас будут содержать числа и, при этом, числа целые, то есть тип данных у нас будет int
. Те, кто захочет реализовать решение задачи с другими типами данных, например, с double
— без проблем откорректирую исходный код программы.
Второе: какой метод сортировки массива использовать?
Существует множество методов сортировки массивов: выбором, пузырьковая, гномья, вставками, перемешиванием и т.д. Учитывая, что конкретный метод сортировки не указан, будем реализовывать нашу задачу, используя один из самых простых методов сортировки — сортировку выбором.
Третье: как задаются массивы a
и b
?
Массив может быть задан пользователем с клавиатуры, а может быть жестко прописан в коде программы. Для упрощения, будем задавать массивы в коде программы.
Определившись с типами данных, способом получения данных и методом сортировки, приступим к выполнению лабораторной работы №1.
Решение лабораторной работы
Для того, чтобы в дальнейшем мы могли достаточно легко модифицировать наш код под другие вводные, напишем три отдельных метода, каждый из которых будет выполнять свою часть работы:
- Метод сортировки массива по возрастанию
- Метод сортировки массива по убыванию
- Метод объединения двух массивов в один
Технически, можно обойтись и двумя методами — вместо двух методов сортировки написать один, который будет сортировать массив в любом заданном пользователе порядке, но для наглядности пока оставим два метода, а, в дальнейшем проведем улучшение нашего кода.
Метод сортировки массива по возрастанию
В качестве параметра, метод должен получать массив целочисленных значений и сортировать его:
static void SortAscending(int[] intArray) { int indx; //переменная для хранения индекса минимального элемента массива for (int i = 0; i < intArray.Length; i++) //проходим по массиву с начала и до конца { indx = i; //считаем, что минимальный элемент имеет текущий индекс for (int j = i; j < intArray.Length; j++) //ищем минимальный элемент в неотсортированной части { if (intArray[j] < intArray[indx]) { indx = j; //нашли в массиве число меньше, чем intArray[indx] - запоминаем его индекс в массиве } } if (intArray[indx] == intArray[i]) //если минимальный элемент равен текущему значению - ничего не меняем continue; //меняем местами минимальный элемент и первый в неотсортированной части int temp = intArray[i]; //временная переменная, чтобы не потерять значение intArray[i] intArray[i] = intArray[indx]; intArray[indx] = temp; } }
Метод реализует сортировку массива выбором.
Метод сортировки массива по убыванию
Нетрудно догадаться, как должен выглядеть метод для сортировки по убыванию, если внимательно прочитать комментарии к коду, представленному выше:
static void SortDescending(int[] intArray) { int indx; for (int i = 0; i < intArray.Length; i++) { indx = i; for (int j = i; j < intArray.Length; j++) { if (intArray[j] > intArray[indx]) //заменяем знак сравнения на противоположный { indx = j; } } if (intArray[indx] == intArray[i]) continue; int temp = intArray[i]; intArray[i] = intArray[indx]; intArray[indx] = temp; } }
Метод объединения двух массивов в один
Здесь стоит помнить, что массив в C# остается неизменным в течение всего его времени жизни после создания. Следовательно, метод объединения массива должен принимать в качестве параметров два массива, а в качестве результата — возвращать объединенный массив. Сделать это можно следующим образом:
static int[] ConcatArrays(int[] a, int[] b) { int[] c = new int[a.Length + b.Length]; //длина нового массива равна сумме длин исходных массивов for (int i = 0; i < a.Length; i++) //переносим числа из массива A в массив C c[i] = a[i]; for (int i = a.Length; i < a.Length+b.Length; i++) //переносим числа из массива B в массив C, начиная с индекса a.Length c[i] = b[i- a.Length]; //не забываем, что у массива B индекс очередного элемента на a.Length меньше, чем у C! return c; }
Код основной программы
Теперь у нас всё готово для того, чтобы составить основной код программы. Он будет очень коротким и простым:
static void Main(string[] args) { int[] a = new int[5] { 2, 4, 5, 1, 4 }; int[] b = new int[5] { 9, 1, 4, -1, 2 }; SortAscending(a); //отсортировли первый массив по возрастанию SortDescending(b); //отсортировали второй массив по убыванию int[] c = ConcatArrays(a, b); //объединили массивы /*Выводим итоговый массив в консоль*/ foreach (int i in c) Console.Write($"{i} "); }
Результаты работы программы представлены ниже:
Весь исходный код программы
Весь исходный код программы для лабораторной работы №1 представлен ниже:
using System; namespace LabRab_1 { class Program { static void SortAscending(int[] intArray) { int indx; //переменная для хранения индекса минимального элемента массива for (int i = 0; i < intArray.Length; i++) //проходим по массиву с начала и до конца { indx = i; //считаем, что минимальный элемент имеет текущий индекс for (int j = i; j < intArray.Length; j++) //ищем минимальный элемент в неотсортированной части { if (intArray[j] < intArray[indx]) { indx = j; //нашли в массиве число меньше, чем intArray[indx] - запоминаем его индекс в массиве } } if (intArray[indx] == intArray[i]) //если минимальный элемент равен текущему значению - ничего не меняем continue; //меняем местами минимальный элемент и первый в неотсортированной части int temp = intArray[i]; //временная переменная, чтобы не потерять значение intArray[i] intArray[i] = intArray[indx]; intArray[indx] = temp; } } static void SortDescending(int[] intArray) { int indx; for (int i = 0; i < intArray.Length; i++) { indx = i; for (int j = i; j < intArray.Length; j++) { if (intArray[j] > intArray[indx]) //заменяем знак сравнения на противоположный { indx = j; } } if (intArray[indx] == intArray[i]) continue; int temp = intArray[i]; intArray[i] = intArray[indx]; intArray[indx] = temp; } } static int[] ConcatArrays(int[] a, int[] b) { int[] c = new int[a.Length + b.Length]; //длина навого массива равна сумме длин исходных массивов for (int i = 0; i < a.Length; i++) //переносим числа из массива A в масси C c[i] = a[i]; for (int i = a.Length; i < a.Length+b.Length; i++) //переносим числа из массива B в масси C, начиная с индекса a.Length c[i] = b[i- a.Length]; //не забываем, что у массива B индекс очередного элемента на a.Length меньше, чем у C! return c; } static void Main(string[] args) { int[] a = new int[5] { 2, 4, 5, 1, 4 }; int[] b = new int[5] { 9, 1, 4, -1, 2 }; SortAscending(a); //отсортировли первый массив по возрастанию SortDescending(b); //отсортировали второй массив по убыванию int[] c = ConcatArrays(a, b); //объединили массивы /*Выводим итоговый массив в консоль*/ foreach (int i in c) Console.Write($"{i} "); } } }
Улучшения
Обратите внимание на два метода сортировки массивов — SortAscending
и SortDescending
. Эти методы отличаются друг от друга ровно одним символом! Конечно же, это совсем не рационально и не правильно, как минимум по двум причинам:
- Если потребуется изменить метод сортировки массива — придется проводить двойную работу и вносить изменения в оба метода;
- «Портянки» дублирующего кода — признак плохого кода.
Намного лучше, если сортировкой массива будет заниматься один метод, который на входе будет получать не только массив для сортировки, но и какой-либо параметр, указывающий на то, в каком порядке массив сортировать — для этих целей как нельзя лучше нам подойдут перечисления. Перепишем метод сортировки массива следующим образом:
enum SortParam {ASC, DESC}; static void SortArray(int[] intArray, SortParam sortParam) { int indx; for (int i = 0; i < intArray.Length; i++) { indx = i; for (int j = i; j < intArray.Length; j++) { //ASC = по возврастанию (intArray[j] < intArray[indx]) //DESC = по убыванию (intArray[j] > intArray[indx]) if (((intArray[j] < intArray[indx]) && (sortParam == SortParam.ASC)) || ((intArray[j] > intArray[indx]) && (sortParam == SortParam.DESC))) { indx = j; } } if (intArray[indx] == intArray[i]) continue; int temp = intArray[i]; intArray[i] = intArray[indx]; intArray[indx] = temp; } }
Здесь метод принимает в качестве параметров массив и порядок сортировки: ASC
— по возрастанию, DESC
— по убыванию. Также немного изменился внутренний цикл for — условие сравнение двух элементов теперь происходит в зависимости от того, в каком порядке сортируется массив. Для составления условия при котором очередной индекс элемента будет запоминаться мы использовали условные логические операторы.
Теперь методы SortAscending
и SortDescending
можно убрать из программы, а основной код программы переписать вот так:
static void Main(string[] args) { int[] a = new int[5] { 2, 4, 5, 1, 4 }; int[] b = new int[5] { 9, 1, 4, -1, 2 }; SortArray(a, SortParam.ASC); //отсортировали первый массив по возрастанию SortArray(b, SortParam.DESC);//отсортировали второй массив по убыванию int[] c = ConcatArrays(a, b); //объединили массивы /*Выводим итоговый массив в консоль*/ foreach (int i in c) Console.Write($"{i} "); }
Теперь, когда у нас основная логика программы улучшена, можно приступить к улучшению программы с точки зрения пользователя. Удобнее было бы выводить пользователю программы не только итог работы программы, но и исходные данные, а чтобы, опять же не дублировать код вывода массива в консоль — выделим этот код в отдельный метод:
static string ArrayToString(int[] array) { string s = string.Empty; foreach (int i in array) s += $"{i} "; return s; }
Здесь метод возвращает в качестве результата строку, содержащую элементы массива, разделенные пробелом. Для работы со строками мы применили интерполяцию.
Полный исходный код улучшенной программы представлен ниже:
using System; namespace LabRab_1 { class Program { enum SortParam {ASC, DESC}; static void SortArray(int[] intArray, SortParam sortParam) { int indx; for (int i = 0; i < intArray.Length; i++) { indx = i; for (int j = i; j < intArray.Length; j++) { //ASC = по возврастанию (intArray[j] < intArray[indx]) //DESC = по убыванию (intArray[j] > intArray[indx]) if (((intArray[j] < intArray[indx]) && (sortParam == SortParam.ASC)) || ((intArray[j] > intArray[indx]) && (sortParam == SortParam.DESC))) { indx = j; } } if (intArray[indx] == intArray[i]) continue; int temp = intArray[i]; intArray[i] = intArray[indx]; intArray[indx] = temp; } } static int[] ConcatArrays(int[] a, int[] b) { int[] c = new int[a.Length + b.Length]; //длина навого массива равна сумме длин исходных массивов for (int i = 0; i < a.Length; i++) //переносим числа из массива A в масси C c[i] = a[i]; for (int i = a.Length; i < a.Length+b.Length; i++) //переносим числа из массива B в масси C, начиная с индекса a.Length c[i] = b[i- a.Length]; //не забываем, что у массива B индекс очередного элемента на a.Length меньше, чем у C! return c; } static string ArrayToString(int[] array) { string s = string.Empty; foreach (int i in array) s += $"{i} "; return s; } static void Main(string[] args) { int[] a = new int[5] { 2, 4, 5, 1, 4 }; int[] b = new int[5] { 9, 1, 4, -1, 2 }; Console.WriteLine($"Исходный массив A: {ArrayToString(a)}"); SortArray(a, SortParam.ASC); //отсортировли первый массив по возрастанию Console.WriteLine($"Отсортированный массив A: {ArrayToString(a)}"); Console.WriteLine($"Исходный массив B: {ArrayToString(b)}"); SortArray(b, SortParam.DESC);//отсортировали второй массив по убыванию Console.WriteLine($"Отсортированный B: {ArrayToString(b)}"); int[] c = ConcatArrays(a, b); //объединили массивы Console.WriteLine($"Итоговый массив С: {ArrayToString(c)}"); } } }
Результат работы программы:
Отсортированный массив A: 1 2 4 4 5
Исходный массив B: 9 1 4 -1 2
Отсортированный B: 9 4 2 1 -1
Итоговый массив С: 1 2 4 4 5 9 4 2 1 -1
Итого
Сегодня мы выполнили лабораторную работу в C# по сортировке и объединению массивов. Для выполнения работы нам потребовались знания о массивах, методах их сортировки, знание логических операторов в C#, интерполяции строк. Лабораторная работа представлена в двух вариантах — подробном и улучшенном варианте, где сортировка массива происходит в том порядке, в котором её задает пользователь.