Программирование на С#
Конструкции языка и типы данных, среда разработки Visual Studio. Программы линейного алгоритма. Создание объектов в программном коде. Построения графиков с помощью элемента управления Сhart. Работа со строками, массивами и методами, обработка изображений.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | учебное пособие |
Язык | русский |
Дата добавления | 26.09.2021 |
Размер файла | 2,3 M |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
private void Form1_Paint(object sender,
PaintEventArgs e)
{
Graphics g = e.Graphics;
g.Clear(Color.White);
for (int i = 0; i < 50; i++)
g.DrawLine(new Pen(Brushes.Black, 2),
10, 4 * i + 20, 200, 4 * i + 20);
}
Здесь мы вызываем метод DrawLine в цикле, рисуя 50 горизонтальных линий (рис. 10.2).
Рис. 10.2. Пример использования DrawLine
Вызвав один раз метод DrawLines, можно нарисовать сразу несколько прямых линий, соединенных между собой. Иными словами, метод DrawLines позволяет соединить между собой несколько точек. Координаты этих точек по горизонтальной и вертикальной оси передаются методу через массив класса Point или PointF:
public void DrawLines(Pen, Point[]);
public void DrawLines(Pen, PointF[];
Для демонстрации возможностей метода DrawLines создайте приложение. Код будет выглядеть следующим образом:
Point[] points = new Point[50];
Pen pen = new Pen(Color.Black, 2);
private void Form1_Paint(object sender,
PaintEventArgs e)
{
Graphics g = e.Graphics;
g.DrawLines(pen, points);
}
private void Form1_Load(object sender, EventArgs e)
{
for (int i = 0; i < 20; i++)
{
int xPos;
if (i % 2 == 0)
{
xPos = 10;
}
else
{
xPos = 400;
}
points[i] = new Point(xPos, 10 * i);
}
}
Результат работы программы приведен на рис. 10.3.
Рис. 10.3. Пример использования массива точек
Для прорисовки прямоугольников можно использовать метод DrawRectangle:
DrawRectangle(Pen, int, int, int, int);
В качестве первого параметра передается перо класса Pen. Остальные параметры задают расположение и размеры прямоугольника.
Для прорисовки многоугольников можно использовать следующий метод:
DrawPolygon(Pen, Point[]);
Метод DrawEllipse рисует эллипс, вписанный в прямоугольную область, расположение и размеры которой передаются ему в качестве параметров. При помощи метода DrawArc программа может нарисовать сегмент эллипса. Сегмент задается при помощи координат прямоугольной области, в которую вписан эллипс, а также двух углов, отсчитываемых в направлении против часовой стрелки. Первый угол Angle1 задает расположение одного конца сегмента, а второй Angle2 - расположение другого конца сегмента (рис. 10.4).
Рис. 10.4. Углы и прямоугольник, задающие сегмент эллипса
В классе Graphics определен ряд методов, предназначенных для рисования закрашенных фигур. Имена некоторых из этих методов, имеющих префикс Fill*:
FillRectangle (рисование закрашенного прямоугольника), FillRectangles (рисование множества закрашенных многоугольников), FillPolygon (рисование закрашенного многоугольника), FillEllipse (рисование закрашенного эллипса) FillPie (рисование закрашенного сегмента эллипса) FillClosedCurve (рисование закрашенного сплайна) FillRegion (рисование закрашенной области типа Region).
Есть два отличия методов с префиксом Fill* от одноименных методов с префиксом Draw*. Прежде всего, методы с префиксом Fill* рисуют закрашенные фигуры, а методы с префиксом Draw* - не закрашенные. Кроме этого, в качестве первого параметра методам с префиксом Fill* передается не перо класса Pen, а кисть класса SolidBrush. Ниже приведем пример выводящий закрашенный прямоугольник:
SolidBrush B = new SolidBrush(Color.DeepPink);
g.FillRectangle(B, 0, 0, 100, 100);
10.4 Индивидуальное задание
Изучите с помощью справки MSDN методы и свойства классов Graphics, Color, Pen и SolidBrush. Создайте собственное приложение выводящий на форму рисунок, состоящий из различных объектов (линий, многоугольников, эллипсов, прямоугольников и пр.), не закрашенных и закрашенных полностью. Используйте разные цвета и стили линий (сплошные, штриховые, штрих-пунктирные).
Лабораторная работа №11. Анимация
Цель лабораторной работы: изучить возможности Visual Studio по создание простейшей анимации. Написать и отладить программу, выводящую на экран анимационное изображение.
11.1 Работа с таймером
Класс для работы с таймером Timer формирует в приложении повторяющиеся события. События повторяются с периодичностью, указанной в миллисекундах в свойстве Interval. Установка свойства Enabled в значение true запускает таймер. Каждый тик таймера порождает событие Tick, обработчик которого обычно и создают в приложении. В этом обработчике могут изменяться какие-либо величины, и вызываться принудительная перерисовка окна. Для создания анимации весь код, рисующий что-либо на форме, должен находиться в обработчике события Paint.
11.2 Создание анимации
Для создания простой анимации достаточно использовать таймер, при тике которого будут изменяться параметры изображения (например, координаты концов отрезка) и вызываться обработчик события Paint для рисования по новым параметрам. При таком подходе не надо заботиться об удалении старого изображения, ведь оно создается в окне заново.
В качестве примера рассмотрим код анимации секундной стрелки часов:
// Глобальные переменные
private int x1, y1, x2, y2, r;
private double a;
private Pen pen = new Pen(Color.DarkRed, 2);
// Перерисовка формы
private void Form1_Paint(object sender,
PaintEventArgs e)
{
Graphics g = e.Graphics;
// Рисуем секундную стрелку
g.DrawLine(pen, x1, y1, x2, y2);
}
// Действия при загрузке формы
private void Form1_Load(object sender, EventArgs e)
{
r = 150; // Радиус стрелки
a = 0; // Угол поворота стрелки
// Определяем центр формы - начало стрелки
x1 = ClientSize.Width / 2;
y1 = ClientSize.Height / 2;
// Конец стрелки
x2 = x1 + (int)(r * Math.Cos(a));
y2 = y1 - (int)(r * Math.Sin(a));
}
// Действия при очередном «тике» таймера
private void timer1_Tick(object sender, EventArgs e)
{
a -= 0.1; // Уменьшаем угол на 0,1 радиану
// Новые координаты конца стрелки
x2 = x1 + (int)(r * Math.Cos(a));
y2 = y1 - (int)(r * Math.Sin(a));
// Принудительный вызов события Paint
Invalidate();
}
11.3 Движение по траектории
Движение по траектории реализуется аналогично выше рассмотренному примеру. Для реализации движения по прямой нужно увеличивать переменные, являющиеся узловыми точками, на определённые константы: в приведённом выше примере это переменные x2 и y2. Для задания более сложной траектории можно использовать различные параметрические кривые.
В случае движения на плоскости обычно изменению подвергается один параметр. Рассмотрим пример реализации движения окружности по декартову листу. Декартов лист - это плоская кривая третьего порядка, удовлетворяющая уравнению в прямоугольной системе x3+y3=3·a·x·y. Параметр 3·a определяется как диагональ квадрата, сторона которого равна наибольшей хорде петли.
Рис. 11.1. Декартов лист
При переходе к параметрическому виду получаем:
,
где t=tg ц.
Программная реализация выглядит следующим образом:
private int x1, y1, x2, y2;
private double a, t, fi;
private Pen pen = new Pen(Color.DarkRed, 2);
private void Form1_Load(object sender, EventArgs e)
{
x1 = ClientSize.Width / 2;
y1 = ClientSize.Height / 2;
a = 150;
fi = -0.5;
t = Math.Tan(fi);
x2 = x1 + (int)((3 * a * t) / (1 + t * t * t));
y2 = y1 - (int)((3 * a * t * t) / (1 + t * t * t));
}
private void Form1_Paint(object sender,
PaintEventArgs e)
{
Graphics g = e.Graphics;
g.DrawEllipse(pen, x2, y2, 20, 20);
}
private void timer1_Tick(object sender, EventArgs e)
{
fi += 0.01;
t = Math.Tan(fi);
x2 = x1 + (int)((3 * a * t) / (1 + t * t * t));
y2 = y1 - (int)((3 * a * t * t) / (1 + t * t * t));
Invalidate();
}
Описание ряда интересных кривых для создания траектории движения можно найти в Википедии в статье Циклоидальная кривая.
11.3 Индивидуальное задание
Создайте программу, показывающую пульсирующее сердце.
Создайте приложение, отображающее вращающийся винт самолета.
Разработайте программу анимации двигающегося человечка.
Создайте программу, показывающую движение окружности по синусоиде.
Создайте приложение, отображающее движение окружности по спирали.
Разработайте программу анимации падения снежинки.
Создайте программу, показывающую скачущий мячик.
Создайте приложение, отображающее движение окружности вдоль границы окна. Учтите возможность изменения размеров окна.
Разработайте программу анимации летающего бумеранга.
Создайте программу, показывающую падение нескольких звезд одновременно.
Создайте приложение, отображающее хаотичное движение звезды в окне.
Разработайте программу анимации взлета ракеты. Старт осуществляется по нажатию специальной «красной» кнопки.
Создайте программу, показывающую движение окружности вдоль многоугольника. Число вершин вводится пользователем до анимации.
Создайте приложение, отображающее броуновское движение молекулы в окне.
Разработайте программу анимации движения планет в Солнечной системе.
Создайте программу, показывающую движение квадратика по траектории, состоящей из 100 точек, и хранящихся в специальном массиве.
Создайте приложение, имитирующие механические часы.
Разработайте программу анимации падения несколько листков с дерева. Движение не должно быть линейным.
Создайте программу, показывающую движение окружности по спирали с плавно изменяющейся скоростью.
Создайте приложение, отображающее движение автомобиля с вращающимися колесами.
Лабораторная работа №12. Обработка изображений
Цель лабораторной работы: изучить возможности Visual Studio по открытию и сохранению файлов. Написать и отладить программу для обработки изображений.
12.1 Отображение графических файлов
Обычно для отображения точечных рисунков, рисунков из метафайлов, значков, рисунков из файлов в формате BMP, JPEG, GIF или PNG используется объект PictureBox, т.е. элемент управления PictureBox действует как контейнер для картинок. Можно выбрать изображение для вывода, присвоив значение свойству Image. Свойство Image может быть установлено в окне свойств или в коде программы, указывая на рисунок, который следует отображать.
Элемент управления PictureBox содержит и другие полезные свойства, в том числе свойство AutoSize, определяющее, будет ли изображение растянуто в элементе PictureBox, и SizeMode, которое может использоваться для растягивания, центрирования или увеличения изображения в элементе управления PictureBox.
Перед добавлением рисунка к элементу управления PictureBox в проект обычно добавляется файл рисунка в качестве ресурса В приложениях Visual C# часто содержатся данные, не являющиеся исходным кодом. Такие данные называются ресурсами проекта и могут включать двоичные данные, текстовые файлы, аудио- и видеофайлы, таблицы строк, значки, изображения, XML-файлы или любой другой тип данных, необходимых для приложения. Данные ресурсов проекта хранятся в формате XML в файле с расширением RESX (имя по умолчанию - Resources.resx), который можно открыть в Обозревателе решений.. После добавления ресурса к проекту можно повторно использовать его. Например, может потребоваться отображение одного и того же изображения в нескольких местах.
Необходимо отметить, что поле Image само является классом для работы с изображениями, у которого есть свои методы. Например, метод FromFile используется для загрузки изображения из файла. Кроме класса Image существует класс Bitmap, который расширяет возможности класса Image за счет дополнительных методов для загрузки, сохранения и использования растровых изображений. Так метод Save класса Bitmap позволяет сохранять изображения в разных форматах, а методы GetPixel и SetPixel позволяют получить доступ к отдельным пикселям рисунка.
12.2 Элементы управления OpenFileDialog и SaveFileDialog
Элемент управления OpenFileDialog является стандартным диалоговым окном. Он аналогичен диалоговому окну «Открыть файл» операционной системы Windows. Элемент управления OpenFileDialog позволяет пользователям просматривать папки личного компьютера или любого компьютера в сети, а также выбирать файлы, которые требуется открыть.
Для вызова диалогового окна для выбора файла можно использовать метод ShowDialog() который возвращает значение DialogResult.OK при корректном выборе. Диалоговое окно возвращает путь и имя файла, который был выбран пользователем в специальном свойстве FileName.
12.3 Простой графический редактор
Создайте приложение, реализующее простой графический редактор. Функциями этого редактора должны быть: открытие рисунка, рисование поверх него простой кистью, сохранение рисунка в другой файл. Для этого создайте форму и разместите на ней элементы управления Button и PictureBox (рис 12.1).
В этом случае не понадобится из панели элементов размещать на форме элементы диалоговых окон OpenFileDialog и SaveFileDialog. Эти элементы будут порождены динамически в ходе выполнения программы с помощью конструктора. Например, так:
Рис. 12.1. Форма для графического редактора
OpenFileDialog dialog = new OpenFileDialog();
Далее они будут вызываться с помощью метода ShowDialog().
Для кнопок «Открыть» и «Сохранить» создайте свои обработчики события. Также создайте обработчик события Load для формы. Для элемента управления pictureBox1 создайте обработчики события MouseDown, MouseMove. Код приложения будет выглядеть следующим образом:
// Глобальные переменные
private Point PreviousPoint, point;
private Bitmap bmp;
private Pen blackPen;
private Graphics g;
// Действия при загрузке формы
private void Form1_Load(object sender, EventArgs e)
{
// Подготавливаем перо для рисования
blackPen = new Pen(Color.Black, 4);
}
// Действия при нажатии кнопки загрузки изображения
private void button1_Click(object sender, EventArgs e)
{
// Описываем объект класса OpenFileDialog
OpenFileDialog dialog = new OpenFileDialog();
// Задаем расширения файлов
dialog.Filter = "Image files (*.BMP, *.JPG, " +
*.GIF, *.PNG)|*.bmp;*.jpg;*.gif;*.png";
// Вызываем диалог и проверяем выбран ли файл
if (dialog.ShowDialog() == DialogResult.OK)
{
// Загружаем изображение из выбранного файла
Image image = Image.FromFile(dialog.FileName);
int width = image.Width;
int height = image.Height;
pictureBox1.Width = width;
pictureBox1.Height = height;
// Создаем и загружаем изображение в формате bmp
bmp = new Bitmap(image, width, height);
// Записываем изображение в pictureBox1
pictureBox1.Image = bmp;
// Подготавливаем объект Graphics для рисования
g = Graphics.FromImage(pictureBox1.Image);
}
}
// Действия при нажатии мышки в pictureBox1
private void pictureBox1_MouseDown(object sender,
MouseEventArgs e)
{
// Записываем в предыдущую точку текущие координаты
PreviousPoint.X = e.X;
PreviousPoint.Y = e.Y;
}
// Действия при перемещении мышки
private void pictureBox1_MouseMove(object sender,
MouseEventArgs e)
{
// Проверяем нажата ли левая кнопка мыши
if (e.Button == MouseButtons.Left)
{
// Запоминаем текущее положение курсора мыши
point.X = e.X;
point.Y = e.Y;
// Соеденяем линией предыдущую точку с текущей
g.DrawLine(blackPen, PreviousPoint, point);
// Текущее положение курсора - в PreviousPoint
PreviousPoint.X = point.X;
PreviousPoint.Y = point.Y;
// Принудительно вызываем перерисовку
pictureBox1.Invalidate();
}
}
// Действия при нажатии кнопки сохранения файла
private void button2_Click(object sender, EventArgs e)
{
// Описываем и порождаем объект savedialog
SaveFileDialog savedialog = new SaveFileDialog();
// Задаем свойства для savedialog
savedialog.Title = "Сохранить картинку как ...";
savedialog.OverwritePrompt = true;
savedialog.CheckPathExists = true;
savedialog.Filter =
"Bitmap File(*.bmp)|*.bmp|" +
"GIF File(*.gif)|*.gif|" +
"JPEG File(*.jpg)|*.jpg|" +
"PNG File(*.png)|*.png";
// Показываем диалог и проверяем задано ли имя файла
if (savedialog.ShowDialog() == DialogResult.OK)
{
string fileName = savedialog.FileName;
// Убираем из имени расширение файла
string strFilExtn = fileName.Remove(0,
fileName.Length - 3);
// Сохраняем файл в нужном формате
switch (strFilExtn)
{
case "bmp":
bmp.Save(fileName,
System.Drawing.Imaging.ImageFormat.Bmp);
break;
case "jpg":
bmp.Save(fileName,
System.Drawing.Imaging.ImageFormat.Jpeg);
break;
case "gif":
bmp.Save(fileName,
System.Drawing.Imaging.ImageFormat.Gif);
break;
case "tif":
bmp.Save(fileName,
System.Drawing.Imaging.ImageFormat.Tiff);
break;
case "png":
bmp.Save(fileName,
System.Drawing.Imaging.ImageFormat.Png);
break;
default:
break;
}
}
}
Далее добавим в проект кнопку для перевода изображения в градации серого цвета:
// Действия при нажатии кнопки перевода в градации серого
private void button3_Click(object sender, EventArgs e)
{
// Циклы для перебора всех пикселей на изображении
for (int i = 0; i < bmp.Width; i++)
for (int j = 0; j < bmp.Height; j++)
{
// Извлекаем в R значение красного цвета
int R = bmp.GetPixel(i, j).R;
// Извлекаем в G значение зеленого цвета
int G = bmp.GetPixel(i, j).G;
// Извлекаем в B значение синего цвета
int B = bmp.GetPixel(i, j).B;
// Высчитываем среднее арифметическое
int Gray = (R = G + B) / 3;
// Переводим число в значение цвета.
// 255 - показывает степень прозрачности.
// Остальные значения одинаковы
Color p = Color.FromArgb(255, Gray, Gray,
Gray);
// Записываем цвет в текущую точку
bmp.SetPixel(i, j, p);
}
// Вызываем функцию перерисовки окна
Refresh();
}
Данный код демонстрирует возможность обращения к отдельным пикселям. Цвет каждого пикселя хранится в модели RGB и состоит из трех составляющих: красного, зеленого и синего цвета, называемых каналами. Значение каждого канала может варьироваться в диапазоне от 0 до 255.
12.4 Индивидуальное задание
Добавьте в приведенный графический редактор свои функции в соответствии с вариантом.
1) Расширьте приложение путем добавления возможности выбора пользователем цвета и величины кисти.
2) Разработайте функцию, добавляющую на изображение 1000 точек с координатами заданными случайным образом. Цвет, также, задается случайным образом.
3) Создайте функцию, переводящую изображение в черно-белый формат. Пороговое значение задавать с помощью элемента управления TrackBar.
4) Разработайте функцию, оставляющую на изображении только один из каналов (R, G, B). Канал выбирается пользователем.
5) Создайте функцию, выводящую на изображение окружность. Центр окружности совпадает с центром изображения. Все точки вне окружности переводятся в градации серого цвета. Все точки внутри окружности остаются неизменными. Радиус окружности задается пользователем.
6) Создайте функцию, выводящую на изображение треугольник. Для всех точек вне треугольника оставьте только канал B. Все точки внутри треугольника переводятся в градации серого цвета.
7) Создайте функцию, выводящую на изображение ромб. Все точки вне ромба переводятся в градации серого цвета. Для всех точек внутри ромба оставьте только канал G.
8) Разработайте функцию, которая каждую четную строку изображения переводит в градации серого цвета.
9) Разработайте функцию, которая переводит каждый нечетный столбец пикселей (вертикальные линии) в градации серого цвета.
10) Создайте функцию, разбивающую изображение на четыре равные части. В каждой оставьте значение только одного канала R, G и B, а в четвертой выведите градации серого цвета.
11) Разработайте функцию, заменяющую все точки синего цвета на точки красного цвета.
12) Создайте функцию, инвертирующую изображение в градациях серого цвета в негатив.
13) Создайте функцию, изменяющую яркость изображения. Путем прибавления или уменьшения заданной пользователем величины к каждому каналу.
14) Создайте функцию, переводящую изображение в черно-белый формат в соответствии с пороговым значением, которое ввел пользователь. Для анализа используйте только один из каналов (R, G, B).
15) Разработайте функцию для создания эффекта мозаики. При этом изображения разбивается на прямоугольные фрагменты, в каждом из которых выбирается цвет средней точки и этим же цветом закрашивается весь фрагмент.
16) Разработайте функцию, разбивающую изображение на фрагменты, в каждом из которых остается только один из каналов (R, G, B).
Лабораторная работа №13. Методы
Цель лабораторной работы: научиться работать с методами, написать программу с использованием методов.
13.1 Общие понятия
Метод - это элемент класса, который содержит программный код. Метод имеет следующую структуру:
[атрибуты] [спецификторы] тип имя ([параметры])
{
Тело метода;
}
Атрибуты - это особые указания компилятору на свойства метода. Атрибуты используются редко.
Спецификаторы - это ключевые слова, предназначенные для разных целей, например:
· определяющие доступность метода для других классов:
· private - метод будет доступен только внутри этого класса
· protected - метод будет доступен также дочерним классам
· public - метод будет доступен любому другому классу, который может получить доступ к данному классу
· указывающие доступность метода без создания класса
· задающие тип
Тип определяет результат, который возвращает метод: это может быть любой тип, доступный в C#, а также ключевое слово void, если результат не требуется.
Имя метода - это идентификатор, который будет использоваться для вызова метода. К идентификатору применяются те же требования, что и к именам переменных: он может состоять из букв, цифр и знака подчёркивания, но не может начинаться с цифры.
Параметры - это список переменных, которые можно передавать в метод при вызове. Каждый параметр состоит из типа и названия переменной. Параметры разделяются запятой.
Тело метода - это обычный программный код, за исключением того, что он не может содержать определения других методов, классов, пространств имён и т. д. Если метод должен возвращать какой-то результат, то обязательно в конце должно присутствовать ключевое слово return с возвращаемым значением. Если возвращение результатов не нужно, то использование ключевого слова return не обязательно, хотя и допускается.
Пример метода, вычисляющего выражение:
public double Calc(double a, double b, double c)
{
if (a > b)
return Math.Sin(a) * Math.Cos(b);
else
{
double k = Math.Tan(a * b);
return k * Math.Exp(c / k);
}
}
13.2 Перегрузка методов
Язык C# позволяет создавать несколько методов с одинаковыми именами, но разными параметрами. Компилятор автоматически подберёт наиболее подходящий метод при построении программы. Например, можно написать два отдельных метода возведения числа в степень: для целых чисел будет применяться один алгоритм, а для вещественных - другой:
/// <summary>
/// Вычисление X в степени Y для целых чисел
/// </summary>
private int Pow(int X, int Y)
{
int b = 1;
while (Y != 0)
if (Y % 2 == 0)
{
Y /= 2;
X *= X;
}
else
{
Y--;
b *= X;
}
return b;
}
/// <summary>
/// Вычисление X в степени Y для вещественных чисел
/// </summary>
private double Pow(double X, double Y)
{
if (X != 0)
return Math.Exp(Y * Math.Log(Math.Abs(X)));
else if (Y == 0)
return 1;
else
return 0;
}
Вызывается такой код одинаково, разница лишь в параметрах - в первом случае компилятор вызовет метод Pow с целочисленными параметрами, а во втором - с вещественными:
Pow(3, 17);
Pow(3.0, 17.0);
13.3 Параметры по умолчанию
Язык C# начиная с версии 4.0 (Visual Studio 2010) позволяет задавать некоторым параметрам значения по умолчанию - так, чтобы при вызове метода можно было опускать часть параметров. Для этого при реализации метода нужным параметрам следует присвоить значение прямо в списке параметров:
private void GetData(int Number, int Optional = 5)
{
MessageBox.Show("Number: {0}", Number);
MessageBox.Show("Optional: {0}", Optional);
}
В этом случае вызывать метод можно следующим образом:
GetData(10, 20);
GetData(10);
В первом случае параметр Optional будет равен 20, так как он явно задан, а во втором будет равен 5, т.к. явно он не задан и компилятор берёт значение по умолчанию.
Параметры по умолчанию можно ставить только в правой части списка параметров, например, такая сигнатура метода компилятором принята не будет:
private void GetData(int Optional = 5, int Number)
13.4 Передача параметров по значению и по ссылке
Когда параметры передаются в метод обычным образом (без дополнительных ключевых слов ref и out), любые изменения параметров внутри метода не влияют на его значение в основной программе. Предположим, у нас есть следующий метод:
private void Calc(int Number)
{
Number = 10;
}
Видно, что внутри метода происходит изменение переменной Number, которая была передана как параметр. Попробуем вызвать метод:
int n = 1;
Calc(n);
MessageBox.Show(n.ToString());
На экране появится число 1, то есть, не смотря на изменение переменной в методе Calc, значение переменной в главной программе не изменилось. Это связано с тем, что при вызове метода создаётся копия переданной переменной, именно её изменяет метод. При завершении метода значение копий теряется. Такой способ передачи параметра называется передачей по значению.
Чтобы метод мог изменять переданную ему переменную, её следует передавать с ключевым словом ref - оно должно быть как в сигнатуре метода, так и при вызове:
private void Calc(ref int Number)
{
Number = 10;
}
int n = 1;
Calc(ref n);
MessageBox.Show(n.ToString());
В этом случае на экране появится число 10: изменение значения в методе сказалось и на главной программе. Такая передача метода называется передачей по ссылке, т.е. передаётся уже не копия, а ссылка на реальную переменную в памяти.
Если метод использует переменные по ссылке только для возврата значений и не имеет значения что в них было изначально, то можно не инициализировать такие переменные, а передавать их с ключевым словом out. Компилятор понимает, что начальное значение переменной не важно и не ругается на отсутствие инициализации:
private void Calc(out int Number)
{
Number = 10;
}
int n; // Ничего не присваиваем!
Calc(out n);
13.5 Индивидуальное задание
· Написать метод min(x, y), находящий минимальное значение из двух чисел. С его помощью найти минимальное значение из четырёх чисел a, b, c, d.
· Написать метод max(x, y), находящий максимальное значение из двух чисел. С его помощью найти максимальное значение из четырёх чисел a, b, c, d.
· Написать метод, вычисляющий значение n/xn. С его помощью вычислить выражение:
· Написать метод, вычисляющий значение n/xn. С его помощью вычислить выражение:
· Написать метод, вычисляющий значение xn/(n+x). С его помощью вычислить выражение:
· Написать метод, вычисляющий значение sin(x) + cos(2 * x). С его помощью определить в какой из точек a, b или с значение будет минимальным.
· Написать метод, вычисляющий значение x2 + y2. С его помощью определить с какой парой чисел (a, b) или (с, d) значение будет максимальным.
· Написать метод, вычисляющий значение x2 * y3 * . С его помощью определить с какой тройкой чисел (a, b, c) или (d, e, f) значение будет максимальным.
· Написать метод, который у чётных чисел меняет знак, а нечётные числа оставляет без изменения. С его помощью обработать ряд чисел от 1 до 10.
· Написать метод, который положительные числа возводит в квадрат, а отрицательные - в куб. С его помощью обработать ряд чисел от -10 до 10.
· Написать метод, который вычисляет значения x=sin2(a) и y=cos2(a). Напечатать таблицу значений от -р до р с шагом р/4.
· Написать метод, который вычисляет значения x=a2 и y=. Напечатать таблицу значений от -10 до 10 с шагом 1.
· Написать метод, который в переданной строке заменяет все точки на многоточие. С его помощью обработать пять разных строк и отобразить их на экране.
· Написать метод, который в переданной строке заменяет все строчные буквы на заглавные и наоборот. С его помощью обработать пять разных строк и отобразить их на экране.
· Написать метод, который разделяет переданную строку на две отдельных строки: первая содержит исходную строку до первой точки, а вторая - исходную строку после первой точки. С его помощью обработать пять разных строк и отобразить результаты на экране.
Лабораторная работа №14. Сортировка и поиск
Цель лабораторной работы: освоить основные алгоритмы сортировки, написать программу с использованием этих алгоритмов.
14.1 Общие понятия
Сортировка - это процесс упорядочения элементов массива или списка по возрастанию или убыванию. Существует много алгоритмов сортировки, отличающихся по ряду характеристик:
· Время работы, или вычислительная сложность - количество операций, затрачиваемых алгоритмом. Обычно оценивается худший сценарий, когда исходный массив оказывается максимально неупорядочен с точки зрения алгоритма.
· Затрачиваемая память (помимо исходного массива) - некоторые алгоритмы требуют выделения дополнительной памяти для временного хранения данных или формирования нового выходного массива.
Кроме того, алгоритмы можно разделить по типу доступа к данным:
· Алгоритмы внутренней сортировки применяются для сортировки данных, целиком находящихся в оперативной памяти.
· Алгоритмы внешней сортировки оперируют данными, не помещающимися в оперативную память. Такие алгоритмы используют внешнюю память, доступ к которой требует существенно большего времени, поэтому требуются специальные алгоритмические решения, чтобы каждый элемент использовался алгоритмом минимальное количество раз.
14.2 Алгоритмы сортировки. Метод пузырька
Данный алгоритм является достаточно простым и поэтому получил широкое распространение. Вычислительная сложность алгоритма квадратичная - O(n2), поэтому алгоритм эффективен только на небольших массивах данных.
Алгоритм проходит все элементы массива и попарно сравнивает их друг с другом. Если порядок сравниваемых элементов неверный, алгоритм меняет элементы местами:
// Сортировка пузырьком
void BubbleSort(ref int[] Array)
{
// Перебираем элементы массива (без последнего)
for (int i = 0; i < Array.Length - 1; i++)
// Перебираем все элементы справа от i
for (int j = i + 1; j < Array.Length; j++)
// Правильный ли порядок элементов?
if (Array[i] > Array[j])
{
// Нет - меняем порядок
int t = Array[i];
Array[i] = Array[j];
Array[j] = t;
}
}
14.3 Сортировка выбором
Сортировка выбором имеет квадратичную сложность O(n2) и, как и предыдущий метод пузырька, эффективен лишь на небольших объемах данных.
Алгоритм находит номер минимального значения в текущем списке, меняет этот элемент со значением первой неотсортированной позиции (если минимальный элемент не находится на данной позиции), а затем сортирует хвост списка, исключив из рассмотрения уже отсортированные элементы:
// Сортировка выбором
void SelectionSort(ref int[] Array)
{
// Перебираем все элементы массива (безпоследнего)
// i - позиция первого неотсортированного элемента
for (int i = 0; i < Array.Length - 1; i++)
{
// Позиция минимального элемента справа от i
int min = i;
// Перебираем все элементы справа от i
for (int j = i + 1; j < Array.Length; j++)
// Меньше ли очередной элемент минимального?
if (Array[j] < Array[min])
// Да - теперь это минимальный элемент
min = j;
// Минимальный элемент не первый?
// Меняем местами!
if (min != i)
{
int t = Array[i];
Array[i] = Array[min];
Array[min] = t;
}
}
}
14.4 Быстрая сортировка
Алгоритм быстрой сортировки является одним из самых быстрых алгоритмов сортировки: в лучшем случае он имеет логарифмическую сложность, в худшем - квадратичную. Алгоритм выполняется следующим образом:
· Выбирается некоторый элемент, который называется опорным.
· Реорганизуем массив таким образом, чтобы все элементы, меньшие или равные опорному элементу, оказались слева от него, а все элементы, большие опорного - справа от него.
· Рекурсивно упорядочиваем массивы, лежащие слева и справа от опорного элемента.
// Быстрая сортировка
void QuickSort(ref int[] Array, int Left, int Right)
{
// i и j - индексы границ разделяемого массива
int i = Left;
int j = Right;
// x - индекс опорного элемента
int x = Array[(Left + Right) / 2];
do
{
// Ищем элемент слева, который больше опорного
while (Array[i] < x)
++i;
// Ищем элемент справа, который меньше опорного
while (Array[j] > x)
--j;
// Если индексы не поменялись местами,
// то обмениваем элементы
if (i <= j)
{
int t = Array[i];
Array[i] = Array[j];
Array[j] = t;
i++;
j--;
}
} while (i <= j);
// Рекурсивно выполняем быструю сортировку
// для массивов слева и справа
if (Left < j)
QuickSort(ref Array, Left, j);
if (i < Right)
QuickSort(ref Array, i, Right);
}
14.5 Поиск элемента
Алгоритмы поиска позволяют найти индекс элемента с требуемым значением.
Если массив не упорядочен, то возможен лишь простой поиск: перебор всех элементов массива до тех пор, пока не встретится элемент с нужным значением или не закончится массив. Если элемент найден, поиск должен быть прекращён, поскольку дальнейший просмотр массива не имеет смысла:
// Простой поиск элемента в массиве
int IndexOf(ref int[] Array, int Value)
{
// Перебираем все элементы массива
for (int i = 0; i < Array.Length; i++)
// Нашли нужное значение? Возвращаем его индекс
if (Array[i] == Value)
return i;
// Перебор закончился безрезультатно - возвращаем -1
return -1;
}
Если алгоритм поиска не нашёл подходящий элемент, он должен каким-то образом сигнализировать об этом вызывающей программе. Чаще всего в таком случае возвращается значение -1 - число, которое заведомо не может использоваться в качестве индекса массива.
Вычислительная сложность алгоритма простого поиска - линейная O(n).
Если массив упорядочен по возрастанию, то возможно использование дихотомического рекурсивного алгоритма: массив каждый раз делится пополам и если искомый элемент меньше среднего, то поиск продолжается в левой его половине, иначе - в правой:
// Дихотомический поиск элемента в массиве
static int IndexOf(ref int[] Array, int Value,
int Left, int Right)
{
// Находим середину диапазона
int x = (Left + Right) / 2;
// Если нашли значение - возвращаем его индекс
if (Array[x] == Value)
return x;
// Если середина совпадает с левой или
// правой границами - значение не найдено
if ((x == Left) || (x == Right))
return -1;
// Продолжаем поиск слева или справа от середины
if (Array[x] < Value)
return IndexOf(ref Array, Value, x, Right);
else
return IndexOf(ref Array, Value, Left, x);
}
Вычислительная сложность алгоритма - логарифмическая.
14.6 Индивидуальное задание
Общая часть задания: сформировать массив из 100 случайных чисел. Выполнить простой поиск элемента, подсчитать количество итераций. Отсортировать массив методом, указанным в своём варианте. Выполнить поиск элемента методом дихотомии, подсчитать количество итераций. Сделать выводы.
· Метод пузырька
· Сортировка выбором
· Быстрая сортировка
Лабораторная работа №15. Рекурсия
Цель лабораторной работы: изучить рекурсивные методы, написать программу с использованием рекурсии.
15.1 Общие понятия
Рекурсивным называют метод, если он вызывает сам себя в качестве вспомогательного. В основе рекурсивного метода лежит так называемое рекурсивное определение какого-либо понятия. Классическим примером рекурсивного метода является метод, вычисляющий факториал.
Из курса математики известно, что 0!=1!=1, n!=1*2*3…*n. С другой стороны n!=(n-1)!*n. Таким образом, известны два частных случая параметра n, а именно n= 0 и n=1, при которых мы без каких-либо дополнительных вычислений можем определить значение факториала. Во всех остальных случаях, то есть для n>1, значение факториала может быть вычислено через значение факториала для параметра n-1. Таким образом, рекурсивный метод будет иметь вид:
long F(int n)
{
// Дошли до 0 или 1?
if (n == 0 || n == 1)
// Нерекурсивная ветвь
return 1;
else
// Шаг рекурсии: повторный вызов
// метода с другим параметром
return n * F(n - 1);
}
// Пример вызова рекурсивного метода
long f = F(3);
MessageBox.Show(f.ToString());
Рассмотрим работу описанного выше рекурсивного метода для n=3.
Рис. 14.1. Структура рекурсивных вызовов
Первый вызов метода осуществляется из основной программы, в нашем случае командой f = F(3). Этап вхождения в рекурсию обозначим стрелками с подписью «шаг». Он продолжается до тех пор, пока значение переменной n не становится равной 1. После этого начинается выход из рекурсии (стрелки с подписью «возврат»). В результате вычислений получается, что F(3) = 3 * 2 * 1.
Рассмотренный вид рекурсии называют прямой. Метод с прямой рекурсией обычно содержит следующую структуру:
if (<условие>)
<оператор>;
Else
<вызов этого же метода с другими параметрами>;
В качестве <условия> обычно записываются некоторые граничные случаи параметров, передаваемых рекурсивному методу, при которых результат его работы заранее известен, поэтому далее следует простой оператор или блок, а в ветви else происходит рекурсивный вызов данного метода с другими параметрами.
Что необходимо знать для реализации рекурсивного процесса? Со входом в рекурсию осуществляется вызов метода, а для выхода необходимо помнить точку возврата, т. е. то место программы откуда мы пришли и куда нам нужно будет возвратиться после завершения метода. Место хранения точек возврата называется стеком вызовов и для него выделяется определенная область оперативной памяти. В этом стеке запоминаются не только адреса точек возврата, но и копии значений всех параметров. По этим копиям восстанавливается при возврате вызывающий метод. При развертывании рекурсии за счет создания копий параметров возможно переполнение стека. Это является основным недостатком рекурсивного метода. С другой стороны, рекурсивные методы позволяют перейти к более компактной записи алгоритма.
Следует понимать, что любой рекурсивный метод можно преобразовать в обычный метод с использованием циклов. И практически любой метод можно преобразовать в рекурсивный, если выявить рекуррентное соотношение между вычисляемыми в методе значениями.
Рассмотрим пример кода для создания набора самоподобных структур. В нашем случае это будет набор увеличивающихся квадратов (рис. 15.2).
При проектировании данной программы были созданы два метода:
private void MyDraw(Graphics g, int N, int x, int y)
{
Рис. 15.2. Набор квадратов
if (N == 0)
return;
else
{
// Отрисовка прямоугольника
g.DrawRectangle(new Pen(Brushes.Blue, 2),
0, 0, x, y);
// Увеличение x и y на 50
x += 50;
y += 50;
N--;
// Рекурсивный вызов с новыми параметрами
MyDraw(g, N, x, y);
}
}
private void Form1_Paint(object sender,
PaintEventArgs e)
{
Graphics g = e.Graphics;
// Первый вызов метода и вход в рекурсию
MyDraw(g, 7, 50, 50);
}
Координаты левого верхнего угла всех прямоугольников неизменны и находятся в точке (0, 0). Поэтому в параметрах метода MyDraw достаточно передавать x и y для правого нижнего угла. Также в параметрах передается N, значение которой определяет текущую вложенность рекурсии (сколько вызовов рекурсии еще будет).
15.2 Формирование задержки с помощью таймера
Графические конструкции иногда требуется рассматривать динамически в процессе их построения. Поэтому зачастую используется такая схема вывода графики:
· Вывод графического элемента;
· Задержка на n миллисекунд;
· Повторение 1 и 2 этапа до вывода всех графических элементов.
Реализация задержки с помощью таймера возможна следующим способом:
// Глобальное поле flag
private bool flag = false;
...
// Далее следует часть программы,
// где необходимо организовать задержку
// Включаем таймер
timer1.Enabled = true;
// Устанавливаем flag в значение true
flag = true;
// Организуем бесконечный цикл
while (flag);
// Выключаем таймер после выхода из цикла
timer1.Enabled = false;
// Обработчик тика таймера
private void timer1_Tick_1(object sender,
EventArgs e)
{
// Сбрасываем flag в значение false
flag = false;
}
Идея данного подхода заключается в организации бесконечного цикла, который будет проверять значение некого флага. Однако значение флага может измениться при наступлении события Tick таймера, то есть через заданный в таймере промежуток времени. Однако бесконечный цикл, описанный выше, останется бесконечным и программа просто зависнет. В чем же дело? Дело в том, что при такой организации цикла программа не может опросить очередь сообщений, в которое и будет поступать, в том числе, и событие Tick от таймера. Тем самым мы не попадем никогда в обработчик события timer1_Tick_1. Что бы решить данную проблему надо в теле цикла написать Application.DoEvents(), что фактически будет заставлять приложение опрашивать очередь сообщений и в свою очередь приведет к срабатыванию обработчика события timer1_Tick_1.
Перед выполнением индивидуального задания по лабораторной работе, разработайте приложение строящее ряд увеличивающихся квадратов (рис. 15.2). Квадраты выводятся последовательно через одну секунду.
15.3 Индивидуальное задание
· Напишите приложение, которое строит ряд окружностей. Центр окружностей совпадает с центром экрана. Число окружностей задается при первом вызове рекурсивного метода.
· Напишите приложение, которое строит ряд квадратов. Центр квадратов совпадает с центром экрана. Число квадратов задается при первом вызове рекурсивного метода.
· Напишите приложение, которое строит ряд окружностей по диагонали. Число окружностей задается при первом вызове рекурсивного метода.
· Напишите приложение, которое строит ряд увеличивающихся окружностей по диагонали. Число окружностей задается при первом вызове рекурсивного метода.
· Напишите приложение, которое строит ряд окружностей, центры которых лежат на окружности. Число окружностей задается при первом вызове рекурсивного метода.
· Напишите приложение, которое строит ряд квадратов, центры которых лежат на окружности. Число квадратов задается при первом вызове рекурсивного метода.
· Напишите приложение, которое строит ряд увеличивающихся окружностей, центры которых лежат на окружности. Число окружностей задается при первом вызове рекурсивного метода.
· Напишите приложение, которое строит ряд увеличивающихся окружностей, центры которых лежат на спирали. Число окружностей задается при первом вызове рекурсивного метода.
· Вычислить, используя рекурсию, выражение:
· Напишите приложение, которое строит ряд окружностей. Число окружностей удваивается на каждом шаге (в рекурсивном методе происходит два рекурсивных вызова). Центры окружностей выбираются каждый раз произвольно (случайно). Линии связывают центры окружностей «предка» и «порожденных» от нее. Число рекурсий задается при первом вызове рекурсивного метода.
· Напишите приложение, которое строит ряд увеличивающихся окружностей. Число окружностей удваивается на каждом шаге (в рекурсивном методе происходит два рекурсивных вызова). Центры окружностей выбираются каждый раз произвольно (случайно). Толщина линий также увеличивается. Число рекурсий задается при первом вызове рекурсивного метода.
· Напишите приложение, которое строит ряд уменьшающихся окружностей. Число окружностей удваивается на каждом шаге (в рекурсивном методе происходит два рекурсивных вызова). Число рекурсий задается при первом вызове рекурсивного метода.
· Напишите приложение, которое строит приведенное ниже изображение. Число рекурсий задается при первом вызове рекурсивного метода. На каждом шаге число окружностей увеличивается в четыре раза (в рекурсивном методе происходит четыре рекурсивных вызова).
· Постройте ковер Серпинского.
Индивидуальные задания повышенной сложности
Для решения геометрических задач повышенной сложности необходимо:
1) знать, как представляются на плоскости такие геометрические объекты, как точка, прямая, отрезок и окружность;
2) уметь находить уравнение прямой, соединяющей две заданные точки;
3) уметь определять координаты точки пересечения двух прямых;
4) знать, как провести перпендикуляр к прямой или определить, являются ли прямые параллельными;
5) уметь находить скалярное и векторное произведение;
6) находить площадь многоугольника;
7) уметь работать с фигурами на плоскости.
Напомним основные моменты, связанные с этими понятиями.
Каждую точку плоскости можно считать вектором с началом в точке (0,0). Обозначим через a=(x, y) вектор с координатами (x, y). Длина вектора (его модуль) вычисляется по формуле .
Рис. 16.1. Иллюстрация к скалярному произведению векторов
Скалярное произведение двух векторов - это число, равное произведению модулей этих векторов на косинус угла между ними, (a,b)=|a| • |b| • cos ц. Если вектор a имеет координаты (x1, y1), а вектор b координаты - (x2, y2), то скалярное произведение вычисляется по формуле (a,b)= x1 • x2 + y1 • y2.
Заметим, что если угол ц острый, то скалярное произведение (a,b)>0, если угол ц тупой, то (a,b)<0. Если два вектора перпендикулярны, то их скалярное произведение равно нулю.
Векторным произведением двух векторов a и b называется вектор [a Ч b], такой, что
· длина его равна |[a Ч b]|=|a| • |b| • sin ц;
· вектор [a Ч b] перпендикулярен векторам a и b;
· вектор [a Ч b] направлен так, что из его конца кратчайший поворот от a к b виден происходящим против часовой стрелки.
Длина векторного произведения равна площади параллелограмма, построенного на векторах a и b.
Через координаты векторов a и b векторное произведение выражается следующим образом:
[a Ч b]== (y1 • z2 - z1 • y2) i + (x1 • z2 - z1 • x2) j + (x1 • y2 - y1 • x2) k,
где i, j, k - единичные вектора осей Ox, Oy, Oz соответственно.
При решении задач на плоскости координаты z1 и z2 равны нулю. В этом случае [a Ч b]=(x1 • y2 - x2 • y1 )• k.
Если вектор a образует с осью Ох угол б, а вектор b - угол в, то для скалярного произведения справедлива формула [a Ч b]=(|a| • |b| • sin(в-б ))• k. Это означает, что для ненулевых векторов векторное произведение равно нулю тогда и только тогда, когда векторы параллельны. Если поворот от вектора а к вектору b по наименьшему углу выполняется против часовой стрелки, то [a Ч b]>0, если по часовой стрелке, то [a Ч b]<0.
Рис. 16.2. Иллюстрация к векторному произведению
Рассмотрим задачи, при решении которых используются скалярное и векторное произведения.
Задача 1 «Штраф за левые повороты» [1]. В городе Х водителям запрещено выполнять левые повороты. За каждый такой поворот водитель должен уплатить штраф в размере М рублей. Для слежки за водителями в городе установлена компьютерная система, фиксирующая координаты автомобиля в начале движения, в конце движения и во время поворота.
Исходные данные: N - количество зафиксированных координат автомобиля, (xi, yi) - координаты автомобиля в процессе движения, i=1,2, …, N, где (x1, y1) - точка начала движения, (xN, yN) - последняя точка маршрута автомобиля.
Требуется по заданной последовательности координат движения вычислить сумму штрафа водителя.
Рис. 16.3
Траекторию движения автомобиля можно представить в виде ломаной, состоящей из направленных отрезков из точек (xi, yi) в точки (xi+1, yi+1), i=1,2,…,N-1. Поворот считается левым, если направление текущего отрезка пути ai+1 меняется относительно предыдущего отрезка ai в левую сторону, т.е. против часовой стрелки.
Таким образом, решение задачи сводится к вычислению количества пар участков пути ai и ai+1, для которых выполняется условие [ai Ч ai+1]>0. Координаты векторов ai и ai+1 вычисляются через координаты точек (xi, yi): ai=(xi - xi-1, yi - yi-1), ai+1=(xi+1 - xi, yi+1 - yi), следовательно,
[ai Ч ai+1]= (xi - xi-1) (yi+1- yi) - (yi - yi-1)(xi+1 - xi), i=2, …, N-1.
Задание 1. Реализуйте задачу «Штраф за левые повороты»
Задача 2 «Здесь будет город-сад». Жители одного дома города Х решили высадить у себя во дворе несколько деревьев. Так как жильцы не смогли договориться, как должны быть расположены посадки, то каждый посадил дерево в том месте двора, где ему захотелось. После проведения посадок полученный сад решили обнести забором. Но пока доски не привезли, деревья обвязали одной длинной веревкой.
Исходная информация: N - количество деревьев в саду, (xi, yi) - координаты деревьев, i=1,2, …, N. Так как были высажены молодые саженцы, то их толщиной можно пренебречь.
Требуется определить, к каким из посаженных деревьев надо привязать веревку так, чтобы все деревья оказались внутри обнесенной зоны, а длина веревки была минимальная.
Эта и подобные ей задачи сводятся к определению для заданного множества точек на плоскости выпуклой оболочки, то есть выпуклого многоугольника с вершинами в некоторых точках из заданного множества, охватывающего все его точки. В [2] приведено несколько вариантов решения такой задачи с учетом временных затрат на выполнение алгоритмов. Здесь мы рассмотрим способ, использующий свойства скалярного произведения векторов.
Будем строить выпуклую оболочку в порядке обхода участка по часовой стрелке. Найдем самую левую точку М0=(x0, y0), x0=min{xi}. Если таких точек несколько, то возьмем самую нижнюю из них. Эта точка наверняка принадлежит искомой выпуклой оболочке. Зададим первоначальный вектор a0 с началом в точке (x0, y0), параллельный оси Oy.
Следующей точкой оболочки будет такая точка М1, чтобы вектор a1 с началом в точке М0 и концом в точке М1 образовывал с первоначальным вектором a0 минимальный угол. Если таких точек несколько, то выбирается точка, расстояние до которой максимально.
Далее процесс продолжаем, то есть ищем точку М2 с минимальным углом между вектором a1 и вектором a2 с началом в точке М1 и концом в точке М2, затем точку М3 и т.д. Процесс прекращаем, когда дойдем до первой выбранной точки или количество точек в оболочке станет равно N.
Для определения угла между векторами используется скалярное произведение. Причем сам угол можно не вычислять, так как минимальному углу соответствует максимальный косинус угла.
Задание 2. Реализуйте задачу «Здесь будет город-сад»
Задача 3 «Заяц» [3]. Недалеко от города Х находится зоосад. Здешний житель, заяц, хаотично прыгая, оставил след в виде замкнутой самопересекающейся ломаной, охватывающей территорию его владения. Найти площадь минимального по площади выпуклого многоугольника, описанного вокруг этой территории.
В данной задаче необходимо не только найти выпуклую оболочку множества точек, но и вычислить площадь выпуклого многоугольника с заданным набором вершин.
Исходные данные: N - количество вершин выпуклого многоугольника, (xi, yi) - координаты вершин, i=1,2, …, N.
Требуется определить площадь выпуклого N-угольника.
...Подобные документы
Ознакомление с языком программирование PHP. Операторы управления и передачи данных, конструкции разветвления и повторения. Создание функции в PHP. Работа с числами, строками и датой/временем в PHP. Работа с массивами данных. Работа с файловой системой.
курсовая работа [1,5 M], добавлен 09.09.2011Объектно-ориентированная технология создания программ. Среда разработки Visual Studio.NET. Особенности среды Microsoft Visual Studio 2010. Приложения C# для расчетов по формулам, консольный ввод-вывод. Форматирование значений данных. Программы с циклами.
методичка [2,1 M], добавлен 11.09.2014Символьные типы данных, работа со строками, составление блок-схемы алгоритма и программы для работы с массивами. Организация программы с использованием процедур и функций. Процедуры и функции, использующиеся при обработке файлов; компонентные файлы.
контрольная работа [52,9 K], добавлен 03.10.2010Изучение алгоритмов, написание программ на языке C#. Работа с массивами, строками, перечислениями, структурами, интерфейсами. Разработка и функциональность Windows-приложения. Создание и подключение баз данных в среде программирования Visual Studio 2019.
отчет по практике [6,7 M], добавлен 18.10.2020Основы языка программирвоания C++. Элементы управления в Microsoft Visual C++. Алгоритмические конструкции языка программирования Visual C++ и базовые элементы управления. Глобальные константы и переменные. Управление программой с помощью клавиатуры.
курсовая работа [1,7 M], добавлен 08.04.2015Разработка игры "Угадай персонажа", ее суть и содержание. Запоминание новых персонажей и вопросов, коррекция базы данных. Использование языка программирования С++ и среды разработки Microsoft Visual Studio 2010. Алгоритмы и методы, структура программы.
курсовая работа [571,9 K], добавлен 14.07.2012Особенности синтаксиса языка программирования С++. Создание панели меню, для получения информации о программе, сохранения результата и выхода из программы. Работа с файлами, двумерными и одномерными динамическими массивами, функциями, строками и циклами.
курсовая работа [782,3 K], добавлен 06.02.2016Рассмотрение основ работы в Microsoft Visual Studio 2010 с языком программирования С#. Реализация программы обработки данных авиапассажиров. Выбор метода ввода данных из текстового файла. Создание фильтра для обработки списка по определенным критериям.
курсовая работа [1,4 M], добавлен 17.01.2016Виды и принципы компьютерного моделирования. Среда моделирования Microsoft Robotic Studio. Моделирование пространства и объектов рабочей области с помощью визуальной среды Visual Simulation Environment. Создание программы управления мобильным роботом.
дипломная работа [5,0 M], добавлен 15.06.2014Изучение методов разработки приложений в среде визуального программирования Visual Studio. Создание программы, реализующей заказ железнодорожных билетов. Язык SQL-запросов в системе управления базами данных MS Access. Тестирование созданной программы.
курсовая работа [1,0 M], добавлен 03.07.2016Понятие и общая характеристика языка программирования РНР, принципы и этапы его работы, синтаксис и ассоциируемые массивы. Обработка исключений в языке Java. Работа с базами данных с помощью JDBC. Изучение порядка разработки графического интерфейса.
презентация [192,3 K], добавлен 13.06.2014Принципы визуального программирования. Создание программы, генерирующей звук через определенные промежутки времени. Visual Basic как средство разработки прототипов программы, для разработки приложений баз данных и компонентного способа создания программ.
лабораторная работа [1,1 M], добавлен 10.12.2014Основы работы с языком программирования Visual Basic 6.0, разработка и обработка созданных баз данных. Создание экранной формы и запросов по таблице VIP. Алгоритм совместного запроса по таблицам VIP и PROD. Методика разработки пользовательского меню.
курсовая работа [2,7 M], добавлен 04.06.2009Проведение сравнительного анализа языков программирования. Создание алгоритма и специфика составления математической модели программы "Механические часы, показывающие текущее время" в среде Microsoft Visual Studio 2010, на базе языка программирования С++.
курсовая работа [408,9 K], добавлен 11.03.2013Встроенные типы данных, основные конструкции, структуры и применение языка Javа. Введение в интегрированную среду разработки Eclipse. Листинг программы, иллюстрирующей работу с одномерными массивами (создание массива). Спецификация класса Figure.
методичка [1,4 M], добавлен 30.06.2009Microsoft Visual C++ и среда программирования Microsoft Developer Studio 6.0. Решение интеллектуальной задачи на компьютере. Построение алгоритма кодирования на Visual C++. Алгоритм решения задачи. Описание программы "Sort". Инструкции пользователя.
курсовая работа [46,0 K], добавлен 27.11.2007Изучение принципов построения линейных алгоритмов и простых расчетных программ на языке программирования C. Разработка программы расчета математических выражений на основе вводимых данных. Создание консольных приложений в среде Microsoft Visual Studio.
лабораторная работа [254,4 K], добавлен 23.11.2014Исследование алгоритма взаимодействия пользователя с сервером, на котором находится база данных. Реализация безопасности информационной системы с помощью возможностей программного комплекса Visual Studio. Анализ особенностей интерфейса веб-приложения.
курсовая работа [1,3 M], добавлен 17.06.2017Создание программы, реализующей игру "Линии". Среда разработки программы, описание ее общего вида. Основные алгоритмы программы. Реализация программы в среде разработки Microsoft Visual Studio 2008 на языке объектно-ориентированного программирования С++.
курсовая работа [639,0 K], добавлен 16.03.2012Работа с элементом управления в VB.net. Работа с файлами, организация последовательного доступа с помощью объектов Streareader и Streamwriter. Последовательный доступ с помощью класса File, программирование задач с использованием циклов с параметром.
лабораторная работа [644,8 K], добавлен 27.12.2013