
Минобрнауки России
Санкт-петербургский государственный
Электротехнический университет
«ЛЭТИ» им. В.И. Ульянова (Ленина)
Кафедра вычислительной техники
Отчёт
Лабораторная работа №2
По дисциплине «АиСД»
Тема: множества как классы
Студент гр. 3316 |
|
Руденский И.М. |
Преподаватель |
|
Манирагена Валенс |
Санкт-Петербург
2024
Постановка задачи
Цель работы: исследование четырёх способов хранения множеств в памяти ЭВМ с использованием классов.
Задание на обработку множеств:
Русские буквы |
Множество, содержащее буквы, имеющиеся в A или общие для B и C, но не встречающиеся в D |
Формализация задания: E = (A ∪ (B ∩ C)) \ D
Ход работы
1) Представим множества как массив символов. Возьмём как пример множеств мою фамилию, а также фамилии троих моих друзей.
a = РУДЕНСКИЙ
b = ЧЕТВЕРТАК
c = КИРЕЙКОВА
d = КОТОВ
На скриншотах отображена консоль, в которую выводятся все названия вызываемых функций по порядку, создание и уничтожение объектов, и время с момента создания и уничтожения каждого объекта.
Результат для массива символов:
Рисунок 1 - Результат для массива символов
2) Повторим то же самое, но представим множества в виде списков.
Рисунок 2 - Результат для списков
3) Повторим то же самое, но представим множества в виде машинных слов.
Рисунок 3 - Результат для машинных слов
4) Повторим то же самое, но представим множества в виде массивов байт.
Рисунок 4 - Результат для массивов байт
Получили следующие результаты: самый быстрый способ – машинные слова.
Результаты измерения времени
|
Массив символов |
Список |
Массив байт |
Машинные слова |
Время без использования классов, мс |
29 |
28 |
26 |
25 |
Время с использованием классов |
21 |
18 |
15 |
7 |
Вывод
В результате сравнения методов без использования классов и с их использованием можно сделать вывод, что программы с классами работают примерно в 2-3 раза быстрее (см. таблицу результатов измерения времени). На скриншотах из контрольных примеров показано, как вызываются функции и разрушаются объекты. Все описанные функции вызываются так, как и предусмотрено. Так же, как и в прошлой лабораторной работе, использование машинных слов в основе класса Set показало наиболее эффективный результат работы (разница в 3 раза по сравнению с массивом символов). Очевидно, что использование классов целесообразно, т.к. это делает код гораздо более читаемым, расширяет универсальность программы и ускоряет её работу.
Использованные источники
1) Бьёрн Страуструп – Язык программирования С++, 1986г.
2) Скотт Майерс - Эффективный и современный С++, 2014г.
Текст программы
main.cpp
#include "CharArrSet.h"
#include "ListSet.h"
#include "WordSet.h"
#include "BitArrSet.h"
#include <locale>
int main()
{
setlocale(LC_ALL, "russian");
BitArrSet a{ "РУДЕНСКИЙ" };
BitArrSet b{ "ЧЕТВЕРТАК" };
BitArrSet c{ "КИРЕЙКОВА" };
BitArrSet d{ "КОТОВ" };
b.Intersect(c);
b.Print();
a.Union(b);
a.Print();
a.Substract(d);
a.Print();
}
CharArrSet.h
#pragma once
#include <string>
#include <chrono>
class CharArrSet
{
public:
CharArrSet(const std::string &other);
~CharArrSet();
void Intersect(CharArrSet& other);
void Union(CharArrSet& other);
void Substract(CharArrSet& other);
void Print();
std::string &Get();
private:
std::string set;
std::chrono::system_clock::time_point start;
std::chrono::system_clock::time_point end;
};
CharArrSet.cpp
#include "CharArrSet.h"
#include <iostream>
CharArrSet::CharArrSet(const std::string &other)
{
std::cout << "Creating set object\n";
start = std::chrono::system_clock::now();
set = other;
}
CharArrSet::~CharArrSet()
{
std::cout << "Destroying set object\n";
end = std::chrono::system_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "Miliseconds passed: " << elapsed.count() << '\n';
}
void CharArrSet::Intersect(CharArrSet& other)
{
std::cout << __FUNCTION__ << std::endl;
const char* arr1 = set.c_str();
const char* arr2 = other.Get().c_str();
std::string result;
result.resize(100);
int k = 0; // Индекс для записи пересечения в result
// Для каждого элемента в arr1 проверяем, есть ли он в arr2
for (int i = 0; i < strlen(arr1); ++i) {
for (int j = 0; j < strlen(arr2); ++j) {
if (arr1[i] == arr2[j]) {
// Проверяем, не был ли этот элемент уже добавлен в результат
bool alreadyExists = false;
for (int l = 0; l < k; ++l) {
if (result[l] == arr1[i]) {
alreadyExists = true;
break;
}
}
// Если элемент не добавлен ранее, добавляем его в результат
if (!alreadyExists) {
result[k++] = arr1[i];
}
break; // Достаточно найти одно совпадение
}
}
}
result[k] = '\0'; // Завершаем строку нулевым символом
set = result;
}
void CharArrSet::Union(CharArrSet& other)
{
std::cout << __FUNCTION__ << std::endl;
const char* arr1 = set.c_str();
const char* arr2 = other.Get().c_str();
std::string result;
result.resize(100);
int k = 0; // Индекс для записи в result
// Добавляем все уникальные элементы из arr1 в result
for (int i = 0; i < strlen(arr1); ++i) {
// Проверяем, не был ли этот элемент уже добавлен в результат
bool alreadyExists = false;
for (int l = 0; l < k; ++l) {
if (result[l] == arr1[i]) {
alreadyExists = true;
break;
}
}
// Если элемент не добавлен ранее, добавляем его в результат
if (!alreadyExists) {
result[k++] = arr1[i];
}
}
// Добавляем все уникальные элементы из arr2 в result
for (int i = 0; i < strlen(arr2); ++i) {
// Проверяем, не был ли этот элемент уже добавлен в result
bool alreadyExists = false;
for (int l = 0; l < k; ++l) {
if (result[l] == arr2[i]) {
alreadyExists = true;
break;
}
}
// Если элемент не добавлен ранее, добавляем его в результат
if (!alreadyExists) {
result[k++] = arr2[i];
}
}
result[k] = '\0'; // Завершаем строку нулевым символом
set = result;
}
void CharArrSet::Substract(CharArrSet& other)
{
std::cout << __FUNCTION__ << std::endl;
const char* arr1 = set.c_str();
const char* arr2 = other.Get().c_str();
std::string result;
result.resize(100);
int k = 0; // Индекс для записи в result
// Проходим по каждому элементу arr1
for (int i = 0; i < strlen(arr1); ++i) {
bool foundInArr2 = false;
// Проверяем, есть ли этот элемент в arr2
for (int j = 0; j < strlen(arr2); ++j) {
if (arr1[i] == arr2[j]) {
foundInArr2 = true;
break; // Элемент найден во втором массиве, пропускаем его
}
}
// Если элемент не найден во втором массиве, добавляем его в результат
if (!foundInArr2) {
result[k++] = arr1[i];
}
}
result[k] = '\0'; // Завершаем строку нулевым символом
set = result;
}
void CharArrSet::Print()
{
std::cout << __FUNCTION__ << std::endl;
std::cout << set << std::endl;
}
std::string &CharArrSet::Get()
{
std::cout << __FUNCTION__ << std::endl;
return set;
}
ListSet.h
#pragma once
#include <string>
#include <list>
#include <chrono>
class ListSet
{
public:
ListSet(const std::string &other);
~ListSet();
void Intersect(ListSet& list);
void Union(ListSet& list);
void Substract(ListSet& list);
void Print() const;
std::list<char>& Get();
private:
std::list<char> set;
std::chrono::system_clock::time_point start;
std::chrono::system_clock::time_point end;
};
ListSet.cpp
#include "ListSet.h"
#include <iostream>
ListSet::ListSet(const std::string& other)
{
std::cout << "Creating set object\n";
start = std::chrono::system_clock::now();
for (char c : other)
set.push_back(c);
}
ListSet::~ListSet()
{
std::cout << "Destroying set object\n";
end = std::chrono::system_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "Miliseconds passed: " << elapsed.count() << '\n';
}
void ListSet::Intersect(ListSet& list)
{
std::cout << __FUNCTION__ << std::endl;
std::list<char> list2 = list.Get();
std::list<char> result;
for (char c : set) {
if (std::find(list2.begin(), list2.end(), c) != list2.end()) {
if (std::find(result.begin(), result.end(), c) == result.end()) {
result.push_back(c);
}
}
}
set = result;
}
void ListSet::Union(ListSet& list)
{
std::cout << __FUNCTION__ << std::endl;
std::list<char> list2 = list.Get();
std::list<char> result = set;
for (char c : list2) {
if (std::find(result.begin(), result.end(), c) == result.end()) {
result.push_back(c);
}
}
set = result;
}
void ListSet::Substract(ListSet& list)
{
std::cout << __FUNCTION__ << std::endl;
std::list<char> list2 = list.Get();
std::list<char> result;
for (char c : set) {
if (std::find(list2.begin(), list2.end(), c) == list2.end()) {
result.push_back(c);
}
}
set = result;
}
void ListSet::Print() const
{
std::cout << __FUNCTION__ << std::endl;
for (char c : set)
std::cout << c << " ";
std::cout << std::endl;
}
std::list<char>& ListSet::Get()
{
std::cout << __FUNCTION__ << std::endl;
return set;
}
WordSet.h
#pragma once
#include <string>
#include <chrono>
class WordSet
{
public:
WordSet(const std::string& other);
~WordSet();
void Intersect(WordSet& other);
void Union(WordSet& other);
void Substract(WordSet& other);
void Print();
uint32_t Get();
private:
uint32_t set;
const int ALPHABET_SIZE = 32;
std::chrono::system_clock::time_point start;
std::chrono::system_clock::time_point end;
};
WordSet.cpp
#include "WordSet.h"
#include <iostream>
typedef uint32_t Set;
WordSet::WordSet(const std::string& other)
{
std::cout << "Creating set object\n";
start = std::chrono::system_clock::now();
Set _set = 0;
for (char c : other) {
if (c >= 'А' && c <= 'Я') {
_set |= (1 << (c - 'А')); // Устанавливаем бит для буквы
}
}
set = _set;
}
WordSet::~WordSet()
{
std::cout << "Destroying set object\n";
end = std::chrono::system_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "Miliseconds passed: " << elapsed.count() << '\n';
}
void WordSet::Intersect(WordSet& other)
{
std::cout << __FUNCTION__ << std::endl;
set &= other.Get();
}
void WordSet::Union(WordSet& other)
{
std::cout << __FUNCTION__ << std::endl;
set |= other.Get();
}
void WordSet::Substract(WordSet& other)
{
std::cout << __FUNCTION__ << std::endl;
set &= ~other.Get();
}
void WordSet::Print()
{
std::cout << __FUNCTION__ << std::endl;
for (int i = 0; i < ALPHABET_SIZE; ++i) {
if (set & (1 << i)) {
std::cout << static_cast<char>('А' + i);
}
}
std::cout << std::endl;
}
uint32_t WordSet::Get()
{
std::cout << __FUNCTION__ << std::endl;
return set;
}
BitArrSet.h
#pragma once
#include <string>
#include <chrono>
#include <bitset>
static const int ALPHABET_SIZE = 32;
class BitArrSet
{
public:
BitArrSet(const std::string& other);
~BitArrSet();
void Intersect(BitArrSet& other);
void Union(BitArrSet& other);
void Substract(BitArrSet& other);
void Print();
std::bitset<ALPHABET_SIZE> Get();
private:
std::bitset<ALPHABET_SIZE> set;
std::chrono::system_clock::time_point start;
std::chrono::system_clock::time_point end;
};
BitArrSet.cpp
#include "BitArrSet.h"
#include <iostream>
BitArrSet::BitArrSet(const std::string& other)
{
std::cout << "Creating set object\n";
start = std::chrono::system_clock::now();
for (char c : other) {
if (c >= 'А' && c <= 'Я') {
set.set(c - 'А'); // Помещаем буквы в нужный бит
}
}
}
BitArrSet::~BitArrSet()
{
std::cout << "Destroying set object\n";
end = std::chrono::system_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "Miliseconds passed: " << elapsed.count() << '\n';
}
void BitArrSet::Intersect(BitArrSet& other)
{
std::cout << __FUNCTION__ << std::endl;
set &= other.Get();
}
void BitArrSet::Union(BitArrSet& other)
{
std::cout << __FUNCTION__ << std::endl;
set |= other.Get();
}
void BitArrSet::Substract(BitArrSet& other)
{
std::cout << __FUNCTION__ << std::endl;
set &= ~other.Get();
}
void BitArrSet::Print()
{
std::cout << __FUNCTION__ << std::endl;
for (int i = 0; i < ALPHABET_SIZE; ++i) {
if (set[i]) {
std::cout << static_cast<char>('А' + i);
}
}
std::cout << std::endl;
}
std::bitset<ALPHABET_SIZE> BitArrSet::Get()
{
std::cout << __FUNCTION__ << std::endl;
return set;
}