
ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО ОБРАЗОВАНИЯ "САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ ТЕЛЕКОММУНИКАЦИЙ ИМ. ПРОФ. М. А. БОНЧ-БРУЕВИЧА"
Факультет инфокоммуникационных сетей и систем
Кафедра сетей связи и передачи данных
ЛАБОРАТОРНАЯ РАБОТА №3
«Рекурсивные структуры данных»
по дисциплине «Алгоритмы и структуры данных»
Выполнили:
студенты 2-го курса
дневного отделения
группы ИКПИ-92
Козлов Никита
Смирнов Дмитрий
Тюришев Матвей
Пурин Иван
Санкт-Петербург
2021
Содержание
Рекурсивные алгоритмы 3
Итеративные алгоритмы 3
Описание программы 4
Результаты 5
Код программы 7
Рекурсивные алгоритмы
Рекурсивный алгоритм – функция, которая в процессе работы вызывает саму себя. Такой алгоритм прост для понимания и реализации, но при этом очень медленный, ввиду особенности своей работы. Ниже представлен пример рекурсивного алгоритма.
int foo(int pose) { if (pose == 0 || pose == 1) { return 1; } else { return foo(pose - 1) + (pose - 2); } } |
Вычисление числа Фибоначчи при помощи рек. алгоритма
Итеративные алгоритмы
Итеративный алгоритм – функция, в которой действия повторяются многократно, пока не будет достигнут результат. Такой алгоритм сложнее в написании и понимании, но гораздо более эффективен, чем рекурсивный алгоритм. Ниже представлен пример итеративного алгоритма.
int foo(int pose) { int a = 0; int b = 1; for (int i = 0; i < pose; i++) { int c = 0;
c = a + b; a = b; b = c; } } |
Вычисление числа Фибоначчи при помощи итер. алгоритма
Описание программы
Программа реализована на языке C++20, среда разработки - Microsoft Visual Studio 2019.
Характеристики компьютера, производящего расчёты:
Операционная система: Windows 10 Pro
Процессор: Intel Core i7-8700 3.20 Ghz
Оперативная память: 16 гб
Функционал программы:
Программа использует два файла – имплементационный файл main.cpp и заголовочный файл algs.h.
В файле main.cpp находится точка входа в проект и алгоритм расчёта затраченного времени на исполнение каждой функции.
В файле algs.h находятся следующие функции для расчёта лабораторной задачи:
unsigned int recursiveFibonachi(_In_ unsigned int lFibPoint)
unsigned int iterativeFibonachi(_In_ unsigned int lFibPoint)
unsigned int recursiveFactorial(_In_ unsigned int value)
unsigned int iterativeFactorial(_In_ unsigned int value)
Результаты
В ходе работы программы были получены следующие результаты эффективности. Каждый из алгоритмов для удобства изображён на графиках:
Из графика сразу можно заметить, как ведёт себя рекурсивный алгоритм – его временные затраты растут с настолько большой скоростью, что временные затраты итерационного алгоритма визуально не изменяются на графике.
На данном графике, так же, как и на предыдущем, отчётливо заметно, что временные затраты рекурсивного алгоритма во много раз больше, чем затраты итеративного алгоритма.
Код программы
main.cpp
#include <iostream> #include "algs.h"
#ifndef sal #include <sal.h> #endif // !sal
#ifdef ALGS_H
#include <chrono> #include <fstream> #include <vector>
#define MAX_ITERATION 10000
double mean(std::vector<std::chrono::duration<double>> arr) { double z = 0;
for (size_t i{}; i < arr.size(); i++) { z += arr[i].count(); }
return z / arr.size(); }
int main(_In_ int argc, _In_ char* argv[]) { std::ofstream OutReFib, OutItFib, OutReFac, OutItFac;
std::vector<std::chrono::duration<double>>secArrayReFib; std::vector<std::chrono::duration<double>>secArrayItFib; std::vector<std::chrono::duration<double>>secArrayReFac; std::vector<std::chrono::duration<double>>secArrayItFac;
std::chrono::system_clock::time_point beg; std::chrono::system_clock::time_point end; std::chrono::duration<double> sec;
OutReFib.open("OutReFab.txt"); OutItFib.open("OutItFab.txt"); OutReFac.open("OutReFac.txt"); OutItFac.open("OutItFac.txt");
if (!OutReFib.is_open() || !OutItFib.is_open() || !OutReFac.is_open() || !OutItFac.is_open()) { return -1; }
for (size_t i{}; i < 21; i++) { for (size_t j{}; j < MAX_ITERATION; j++) { beg = std::chrono::system_clock::now(); recursiveFibonachi(i); end = std::chrono::system_clock::now(); sec = end - beg; secArrayReFib.push_back(sec); sec.zero();
beg = std::chrono::system_clock::now(); iterativeFibonachi(i); end = std::chrono::system_clock::now(); sec = end - beg; secArrayItFib.push_back(sec); sec.zero();
beg = std::chrono::system_clock::now(); recursiveFactorial(i); end = std::chrono::system_clock::now(); sec = end - beg; secArrayReFac.push_back(sec); sec.zero();
beg = std::chrono::system_clock::now(); iterativeFactorial(i); end = std::chrono::system_clock::now(); sec = end - beg; secArrayItFac.push_back(sec); sec.zero(); }
OutReFib << i << "\t" << mean(secArrayReFib) << "\n"; OutItFib << i << "\t" << mean(secArrayItFib) << "\n"; OutReFac << i << "\t" << mean(secArrayReFac) << "\n"; OutItFac << i << "\t" << mean(secArrayItFac) << "\n";
secArrayItFac.clear(); secArrayReFac.clear(); secArrayItFib.clear(); secArrayReFib.clear();
std::cout << "End of iteration " << i << std::endl; }
OutReFib.close(); OutItFib.close(); OutReFac.close(); OutItFac.close();
return 0; } #else int main(_In_ int argc, _In_ char* argv[]) { std::cout << "Algorithm directories not found\n"; return 0; } #endif // ALGS_H |
algs.h
#pragma once
#include <sal.h>
#ifndef ALGS_H #define ALGS_H
unsigned int recursiveFibonachi(_In_ unsigned int lFibPoint) { if (lFibPoint == 0 || lFibPoint == 1) { return 1; }
return recursiveFibonachi(lFibPoint - 1) + recursiveFibonachi(lFibPoint - 2); }
unsigned int iterativeFibonachi(_In_ unsigned int lFibPoint) { unsigned int a = 0; unsigned int b = 1;
for (unsigned int i{}; i < lFibPoint; i++) { static unsigned int c;
c = a + b; a = b; b = c; }
return b; }
unsigned int recursiveFactorial(_In_ unsigned int value) { return (value < 2) ? 1 : value * recursiveFactorial(value - 1); }
unsigned int iterativeFactorial(_In_ unsigned int value) { unsigned int i; for (i = 0x00000001; value > 0x00000001; i *= (value--));
return i; }
#endif // !ALGS_H |