Содержание
Задача: даны два массива 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#, интерполяции строк. Лабораторная работа представлена в двух вариантах — подробном и улучшенном варианте, где сортировка массива происходит в том порядке, в котором её задает пользователь.