Практические Мацука. Основы программирования на. Net и Java
Скачать 131.13 Kb.
|
МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ ДОНЕЦКОЙ НАРОДНОЙ РЕСПУБЛИКИ МАРИУПОЛЬСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ Факультет экономики, управления и права Кафедра системного анализа и информационных технологий Практические работы по дисциплине: «Основы программирования на .NET и Java» Выполнил: студент 1 курса, группы ИСТ Информационные системы и технологии Мацука В. А Проверил: Ассистент Шестова О.Ю. Мариуполь 2022 Практическое задание 1.0. Тема: максимальное, минимальное и среднее значение. Цель: научиться находить максимальное, минимальное и среднее значение. Задача: Заполните массив случайным числами и выведите максимальное, минимальное и среднее значение. Для генерации случайного числа используйте метод Math.random(), который возвращает значение в промежутке [0, 1]. Постановка задачи(пример) Предположим, что был проведен социологический опрос на какую-либо актуальную тему нашей жизни. Обычно одним из вопросов респонденту является вопрос о его возрасте. При публикации результатов опроса обычно приводятся справочной такие данные, как число опрошенных, средний, минимальный и максимальный возраст участников опроса. Рассмотрим только эту задачу, не касаясь самих результатов опроса. Далее мы построим алгоритм решения этой простой задачи методами структурного программирования, предложим его реализацию на языке C#, зададим пару вопросов, касающихся смысла задачи, на которые вы постарайтесь ответить. Решение Используя принципы структурного программирования выделим в методе static void Main(string[] args) блоки: Ввод данных, Средний возраст, Минимальный и максимальный возраст, Итоги (вывод результатов). 1) При вводе данных сначала задается число участников n и создается массив a (Age — возраст) из n элементов целого типа: int[] a = new int[n]; Затем поочередно вводим с подсказкой возраст каждого человека. 2) Средний возраст находим, предварительно обнулив сумматор m, путем суммирования (в цикле for{ } ) возрастов участников и делением полученной суммы на их число. 3) В другом цикле находим одновременно минимальный и максимальный элементы: до цикла предполагаем, что минимальный и максимальный возраст у первого участника (элемент a[0]), затем в цикле от 1 до (n-1) проверяем условия и изменяем их при необходимости. 4) Вывод результатов — последовательность операторов Console.WriteLine(); Примечание: Отметим, что мы используем всего только три основные конструкции: последовательность, цикл, условие. Циклы вложены в последовательность, условные операторы вложены в цикл. Блоки разделены строками комментариев. Программная реализация: // Средний, минимальный и максимальный возраст в группе using System; namespace среднее_значение_минимальный_и_максимальный_элементы { class Program { static void Main(string[] args) { // Ввод данных int n; Console.Write("Численность группы = "); n = Convert.ToInt32(Console.ReadLine()); int[] a = new int[n]; for (int i = 0; i < n; i++) { Console.Write("Возраст {0}-го человека: ", i+1); a[i] = Convert.ToInt32(Console.ReadLine()); } // Средний возраст double m = 0; for (int i = 0; i < n; i++) m = m + a[i]; m = m / n; // Минимальный и максимальный возраст int min, max; min = a[0]; max = a[0]; for (int i = 1; i < n; i++) { if (a[i] < min) min = a[i]; if (a[i] > max) max = a[i]; } // Итоги Console.Write("ИТОГИ:\nВсего опрошено {0}\n", n); Console.WriteLine("средний возраст = {0}", m); Console.WriteLine("Минимальный возраст = {0}", min); Console.WriteLine("Максимальный возраст = {0}", max); Console.ReadKey(); } } } Практическая 1.2. Цель: поиск простых чисел Тема: поиск простых чисел Задача: Напишите программу, которая выводит на консоль простые числа в промежутке от [2, 100]. Используйте для решения этой задачи оператор "%" (остаток от деления) и циклы. Алгоритм определения простого числа Для того, чтобы проверить является ли число N простым необходимо: Задаем значение N Задаем цикл for от 2 до N-1 (счётчик цикла обозначим, например, как i) Если остаток от деления N на i равен нулю, то число не является простым — выходим из цикла Если остаток от деления N на i не равен нулю, то переходим к следующей итерации цикла Если цикл полностью пройден, то число является простым. Метод определения простого числа в C#, реализующий представленный выше алгоритм может быть представлен следующим образом: public bool IsPrime(int number) { for (int i = 2; i < number; i++) { if (number % i == 0) return false; } return true; } Если по условиям задачи конечное значение диапазона задается в виде числа N, то здесь удобно использовать цикл for или while. Пример программы с использованием цикла for представлен ниже: using System; namespace Prime { class Program { public static bool IsPrime(int number) { for (int i = 2; i < number; i++) { if (number % i == 0) return false; } return true; } static void Main(string[] args) { Console.WriteLine("Введите конечное значение диапазона 1...N и нажмите Enter"); Console.WriteLine("N = "); if ((!int.TryParse(Console.ReadLine(), out int result))||(result<0)) Console.WriteLine("Число должно быть положительным и целым"); Console.WriteLine($"Простые числа из диапазона от 1 до {result}"); int count = 0; for (int i = 1; i <= result; i++) { if (IsPrime(i)) { Console.Write($"{i} "); count++; } } Console.WriteLine(""); Console.WriteLine($"Найдено {count} простых чисел из диапазона от 1 до {result}"); } } } Строго говоря, число 1 не является ни простым не составным, поэтому его можно было бы исключить из цикла, что мы и сделаем в следующем примере. Пример определения заданного количества простых чисел Задача поиска простых чисел может быть сформулирована и по другому, например, так: найти первые N простых чисел. В этом случае нам будет выгодно использовать цикл while: using System; namespace Prime { class Program { public static bool IsPrime(int number) { for (int i = 2; i < number; i++) { if (number % i == 0) return false; } return true; } static void Main(string[] args) { Console.WriteLine("Введите количество простых чисел которые необходимо найти"); Console.WriteLine("N = "); if ((!int.TryParse(Console.ReadLine(), out int result))||(result<=0)) Console.WriteLine("Число должно быть положительным и целым"); Console.WriteLine($"Первые {result} простых чисел"); int count = 0; //количество найденных простых чисел int number = 1; //очередное число, проверку которого необходимо найти int total = 0; //общее количество проверенных чисел while (count { total++; number++; if (IsPrime(number)) { Console.Write($"{number} "); count++; } } Console.WriteLine(""); Console.WriteLine($"Найдено {count} простых чисел. Проверено {total} чисел"); } } } Результатом работы программы будет вывод в консоль первых N простых чисел. В зависимости от условий задачи, мы использовали различные виды циклов для поиска набора простых чисел. Практическая 1.3. Тема: удаление из массива Цель: удаление из массива Задача: Дан массив целых чисел и ещё одно целое число. Удалите все вхождения этого числа из массива (пропусков быть не должно). public static void main(String[] args) { int test_array[] = {0,1,2,2,3,0,4,2}; /* Arrays.toString: см. https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html */ System.out.println(Arrays.toString(removeElement(test_array, 3))); } public static int[] removeElement(int[] nums, int val) { int offset = 0; for(int i = 0; i< nums.length; i++){ if(nums[i] == val){ offset++; } else{ nums[i - offset] = nums[i]; } } // с длинной nums.length - offset return Arrays.copyOf(nums, nums.length - offset); } Можно написать метод для «отрезания хвоста» массива и самостоятельно, но стоит отметить, что стандартный метод будет работать быстрее: public static int[] removeElement(int[] nums, int val) { int offset = 0; for(int i = 0; i< nums.length; i++){ if(nums[i] == val){ offset++; } else{ nums[i - offset] = nums[i]; } } int[] newArray = new int[nums.length - offset]; for(int i = 0; i < newArray.length; i++){ newArray[i] = nums[i]; } return newArray; } Впрочем, если идти таким путём, то можно сначала создать массив нужной длины, а потом уже заполнить его: public static int[] removeElement(int[] nums, int val) { int count = 0; // Сначала вычислим длину нового массива for (int i = 0; i < nums.length; i++) { if (nums[i] != val) { count++; } } int[] newArray = new int[count]; int offset = 0; // Далее всё как в прошлых решениях, // только запись идёт в новый массив for(int i = 0; i< nums.length; i++){ if(nums[i] == val){ offset++; } else{ newArray[i - offset] = nums[i]; } } return newArray; } Практическая 2.0. Тема: проектирование и создание класса, описывающего вектор Цель: проектирование и создание класса, описывающего вектор Задача: Создайте класс, который описывает вектор (в трёхмерном пространстве). У него должны быть: • конструктор с параметрами в виде списка координат x, y, z • метод, вычисляющий длину вектора. Корень можно посчитать с помощью Math.sqrt(): • метод, вычисляющий скалярное произведение: • метод, вычисляющий векторное произведение с другим вектором: • метод, вычисляющий угол между векторами (или косинус угла): косинус угла между векторами равен скалярному произведению векторов, деленному на произведение модулей (длин) векторов: • методы для суммы и разности: • статический метод, который принимает целое число N, и возвращает массив случайных векторов размером N. Если метод возвращает вектор, то он должен возвращать новый объект, а не менять базовый. То есть, нужно реализовать шаблон "Неизменяемый объект" Решение: public class Vector { // Три приватных поля private double x; private double y; private double z; // С тремя параметрами public Vector(double x, double y, double z) { this.x = x; this.y = y; this.z = z; } // Длина вектора. Корень из суммы квадратов public double length() { return Math.sqrt(x * x + y * y + z * z); } // метод, вычисляющий скалярное произведение public double scalarProduct(Vector vector) { return x * vector.x + y * vector.y + z * vector.z; } // метод, вычисляющий векторное произведение public Vector crossProduct(Vector vector) { return new Vector( y * vector.z - z * vector.y, z * vector.x - x * vector.z, x * vector.y - y * vector.x); } // Косинус между двумя векторами public double cos(Vector vector) { // Для вычисления длины и произведения используются //методы multiply и length return scalarProduct(vector) / (length() * vector.length()); } public Vector add(Vector vector) { return new Vector( x + vector.x, y + vector.y, z + vector.z ); } public Vector subtract(Vector vector) { return new Vector( x - vector.x, y - vector.y, z - vector.z ); } public static Vector[] generate(int n){ Vector[] vectors = new Vector[n]; for(int i =0; i < n; i++){ vectors[i] = new Vector(Math.random(), Math.random(), Math.random()); } return vectors; } @Override public String toString() { return "Vector{" + "x=" + x + ", y=" + y + ", z=" + z + '}'; } } Использовать этот класс можно так: public static void main(String[] args) { Vector[] vectors = Vector.generate(10); System.out.println(vectors[0]); System.out.println(vectors[1]); System.out.println(vectors[0].length()); System.out.println(vectors[0].scalarProduct(vectors[1])); System.out.println(vectors[0].crossProduct(vectors[1])); System.out.println(vectors[0].cos(vectors[1])); System.out.println(vectors[0].add(vectors[1])); System.out.println(vectors[0].subtract(vectors[1])); } Это решение можно обобщить и написать класс Vector для произвольной размерности: public class Vector { // теперь не три координаты, а массив координат private double values[]; public Vector(double[] values) { this.values = values; } // Длина вектора. Корень из суммы квадратов public double length() { double sum = 0; for (int i = 0; i < values.length; i++) { sum += values[i] * values[i]; } return Math.sqrt(sum); } // метод, вычисляющий скалярное произведение public double scalarProduct(Vector vector) { double res = 0; for (int i = 0; i < values.length; i++) { res += values[i] * vector.values[i]; } return res; } // для многомерных не определено // public double crossProduct(Vector vector) { // // } // Косинус между двумя векторами public double cos(Vector vector) { return scalarProduct(vector) / (length() * vector.length()); } public Vector add(Vector vector) { double[] another = new double[values.length]; for (int i = 0; i < values.length; i++) { another[i] = values[i] + vector.values[i]; } return new Vector(another); } public Vector subtract(Vector vector) { double[] another = new double[values.length]; for (int i = 0; i < values.length; i++) { another[i] = values[i] - vector.values[i]; } return new Vector(another); } // Вспомогательный метод private static double[] generateRandomArray(int length) { double[] array = new double[length]; for (int i = 0; i < array.length; i++) { array[i] = Math.random(); } return array; } public static Vector[] generate(int n, int dimension) { Vector[] vectors = new Vector[n]; for (int i = 0; i < n; i++) { vectors[i] = new Vector(generateRandomArray(dimension)); } return vectors; } } Практическая 2.1. Тема: генерация случайного элемента с весом Цель: генерация случайного элемента с весом Задача: Напишите класс, конструктор которого принимает два массива: массив значений и массив весов значений. Класс должен содержать метод, который будет возвращать элемент из первого массива случайным образом, с учётом его веса. Пример: Дан массив [1, 2, 3], и массив весов [1, 2, 10]. В среднем, значение «1» должно возвращаться в 2 раза реже, чем значение «2» и в десять раз реже, чем значение «3». Решение: /* Решение основывается на геометрической идее: Будем считать, что веса — это длины некоторых отрезков. Тогда надо "уложить" все отрезки в один общий, генерировать случайное значение из этого общего отрезка, определять в какой из наших отрезков попало значение: |-|--|----------| 0-1--3----------13 ^ */ class RandomFromArray { private int[] values; // значения private int[] weights; // веса private int[] ranges; // левые границы отрезков private int sum; // общая длина всех отрезков public RandomFromArray(int[] values, int[] weights) { this.values = values; this.weights = weights; ranges = new int[values.length]; // Сумма длин всех отрезков sum = 0; for (int weight : weights) { sum += weight; } // Заполняем ranges, левыми границами int lastSum = 0; for (int i = 0; i < ranges.length; i++) { ranges[i] = lastSum; lastSum += weights[i]; } } /* Массив ranges уже заполнен, так что остаётся сгенерировать значение в промежутке [0;sum], и найти отрезок, содержащий это значение: */ public int getRandom() { int random = (int) (Math.random() * (sum - 1)); int ourRangeIndex = 0; for (int i = 0; i < ranges.length; i++) { if (ranges[i] > random) { break; } ourRangeIndex = i; } return values[ourRangeIndex]; } } Но, так как массив ranges отсортирован, то можно (и нужно) использовать бинарный поиск: public int getRandom() { int random = (int) (Math.random() * (sum - 1)); int index = Arrays.binarySearch(ranges, random); return values[index >= 0 ? index : -index - 2]; } Есть ещё один вариант решения этой задачи. Можно создать массив, размер которого равен сумме всех весов. Тогда выбор случайного элемента сводится к генерации случайного индекса. То есть, если дан массив значений [1, 2, 3], и массив весов [1, 2, 10], то можно сразу создать массив [1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] и извлекать из него случайный элемент: class RandomFromArray { private int[] extended_values; // значения public RandomFromArray(int[] values, int[] weights) { // Сумма длин всех отрезков int sum = 0; for (int weight : weights) { sum += weight; } extended_values = new int[sum]; int cursor = 0; for(int i = 0; i < weights.length; i++){ for(int j = 0; j < weights[i]; j++){ extended_values[cursor++] = values[i]; } } } /* Массив extended_values уже заполнен, так что остаётся сгенерировать значение в промежутке [0; extended_values.length) */ public int getRandom() { int random = (int) (Math.random() * ( extended_values.length - 1)); return extended_values[random]; } } У этого решения есть преимущество — время извлечения случайного элемента O(1), в отличии от log(n) в предыдущем решении. Однако требует много памяти: O (Ʃn) Практическая 3.0. |