Skip to content

Instantly share code, notes, and snippets.

@gluschenko
Last active June 26, 2020 20:13
Show Gist options
  • Save gluschenko/55a8fec986dca1e0023e0e80a7a17e69 to your computer and use it in GitHub Desktop.
Save gluschenko/55a8fec986dca1e0023e0e80a7a17e69 to your computer and use it in GitHub Desktop.
#include <iostream>
#include <fstream>
using namespace std;
/*
Задан целочисленный двухмерный массив a из n строк и m столбцов. Найти номер первого максимального
значения среди отрицательных элементов, расположенных до первого элемента, равного Т. Матрицу рассматривать
по строкам. В случае отсутствия отрицательных или равных Т элементов или невозможности поиска вывести
соответствующие поясняющие сообщения.
*/
/*
Узел связного списка:
value -- значение
right -- соседний узел (условно справа)
down -- соседний узел (условной снизу)
*/
struct Node
{
int value;
Node* right;
Node* down;
};
/*
Представление матрицы:
M -- количество столбцов
N -- количество строк
Root -- корневой узел, имеющий M - 1 соседей вправо и N - 1 соседей вниз (все соседи тоже имеют соседей)
*/
struct Matrix
{
int M;
int N;
Node* Root;
};
Node* CreateNode();
Node* CreateLinkedList(int len, bool is_horizontal);
void AddRow(Matrix** p);
void AddCol(Matrix** p);
void Delete(Matrix** p);
void DeleteNode(Node* node, bool move_right);
Node* At(Matrix* p, int index);
Node* At(Matrix* p, int x, int y);
Matrix* ReadFile();
void Trace(Matrix* mtx);
// Создает новый узел, который = 0 и ни к чему не привязан
Node* CreateNode()
{
Node* p = new Node;
p->value = 0;
p->right = NULL;
p->down = NULL;
return p;
}
/*
Создает линейно связный список узлов, связанных либо вертикально, либо горизонтально
*/
Node* CreateLinkedList(int len, bool is_horizontal)
{
Node* start = CreateNode();
Node* last = start;
len--;
while (len > 0)
{
if (is_horizontal)
{
last->right = CreateNode();
last = last->right;
}
else
{
last->down = CreateNode();
last = last->down;
}
len--;
}
return start;
}
/*
Создает объект матрицы размером 1 * 1, а затем постепенно
привязывает нужное количество столбцов и строк
*/
Matrix* Create(int m, int n)
{
Matrix* mtx = new Matrix;
mtx->M = 1;
mtx->N = 1;
mtx->Root = CreateNode();
for (int y = 1; y < n; y++)
{
AddRow(&mtx);
}
for (int x = 1; x < m; x++)
{
AddCol(&mtx);
}
return mtx;
}
/*
Создает линейно связный список длиной равной количеству столбцов в матрице.
Затем ищет самый левый элемент в самом нижнем ряду и связывает каждый его элемент
с каждым низлежащим элементом нового ряда.
Связывание: присвоение ссылки на элемент к node->down
*/
void AddRow(Matrix** p)
{
Matrix* mtx = *p;
int width = mtx->M;
int height = mtx->N;
Node* list = CreateLinkedList(width, true);
Node* endRow = mtx->Root;
while (Node* next = endRow->down) {
endRow = next;
}
Node* next = endRow;
while (next) {
endRow->down = list;
list = list->right;
next = next->right;
endRow = next;
}
mtx->N++;
*p = mtx;
}
/*
Аналогично предыдущему методу создает колонку в виде вертикально направленного односвязного списка, который
затем мнимо подставляется справа от матрицы и каждый элемент самого правого столбца связывается с
соответсвующим ему элементу нового столбца.
*/
void AddCol(Matrix** p)
{
Matrix* mtx = *p;
int width = mtx->M;
int height = mtx->N;
Node* list = CreateLinkedList(height, false);
Node* endCol = mtx->Root;
while (Node* next = endCol->right) {
endCol = next;
}
Node* next = endCol;
while (next) {
endCol->right = list;
list = list->down;
next = next->down;
endCol = next;
}
mtx->M++;
*p = mtx;
}
// Удаляет содержимое матрицы: вызывает рекурсивную функцию вычищения связных списков
void Delete(Matrix** p)
{
Matrix* mtx = *p;
DeleteNode(mtx->Root, true);
delete mtx;
}
// Удаляет элемент связного списка, предварительно вызвав самого себя применительно к соседним элементам.
// move_right -- нужен, чтобы правых соседей могли удалять только вызовы из первой итерации.
void DeleteNode(Node* node, bool move_right)
{
if (node->right && move_right)
DeleteNode(node->right, move_right);
if (node->down)
DeleteNode(node->down, false);
delete node;
}
/*
Доступ к узлам матрицы по индексу (M * y) + x
x - i-й элемент с нуля
y - j-й элемент с нуля
*/
Node* At(Matrix* mtx, int index)
{
int x = index % mtx->M;
int y = (index - x) / mtx->N;
return At(mtx, x, y);
}
/*
Достает элемент матрицы по x/y.
Сначала промативыет список на x - 1 раз вправо, затем на y - 1 раз вниз
x - i-й элемент с нуля
y - j-й элемент с нуля
*/
Node* At(Matrix* mtx, int x, int y)
{
if (x < mtx->M && y < mtx->N) {
Node* cur = mtx->Root;
while (x-- > 0) cur = cur->right;
while (y-- > 0) cur = cur->down;
return cur;
}
return NULL;
}
/*
Вытаскивает числа из файла:
Сначала читаются первые два числа -- создается объект матрицы шириной и длиной в соответствии с первыми двумя числами в файле.
Затем для каждого последующиего числа вычисляется номер элемента в матрице, по кторому и происходит присвоение к нужной позиции.
*/
Matrix* ReadFile()
{
fstream file("mat.txt", ios_base::in);
Matrix* mtx = NULL;
int m = 0;
int n = 0;
int i = 0;
int a = 0;
while (file >> a)
{
if (i == 0) m = a;
if (i == 1) n = a;
if (i == 2) {
mtx = Create(m, n);
}
if (i > 1) {
int index = i - 2;
Node* item = At(mtx, index);
item->value = a;
}
i++;
}
return mtx;
}
/*
Выводит содержимое матрицы на экран.
if(a >= 0) cout << " ";
if(a < 10) cout << " "; ---- это все сделано, чтобы числа с разным количеством разрядов и наличием минуса смотрелись в ровной сетке а не в кучу
if(a < 100) cout << " ";
*/
void Trace(Matrix* mtx)
{
for (int y = 0; y < mtx->N; y++)
{
for (int x = 0; x < mtx->M; x++)
{
Node* node = At(mtx, x, y);
int a = node ? node->value : 0;
if(a >= 0) cout << " ";
if(a < 10) cout << " ";
if(a < 100) cout << " ";
cout << " " << a;
}
cout << endl << endl;
}
}
int main()
{
setlocale(LC_ALL, "Russian");
Matrix* mtx = NULL;
bool exit = false;
while (!exit)
{
cout << endl << "-----------------------------------------------------" << endl;
cout << "Введите команду:" << endl;
cout << "1. Загрузить матрицу" << endl;
cout << "2. Изменить элемент" << endl;
cout << "3. Изменить размер матрицы" << endl;
cout << "4. По заданию" << endl;
cout << "5. Очистить память" << endl;
cout << "6. Выход" << endl;
cout << "-----------------------------------------------------" << endl << endl;
int command = 0;
cin >> command;
switch (command)
{
case 1:
// Читает файл, присваивает матрицу к mtx, выводит на экран содержимое
cout << "Чтение из файла:" << endl;
mtx = ReadFile();
Trace(mtx);
break;
case 2:
// Проверяет, что матрица загружена
if (mtx)
{
int m = 0;
int n = 0;
cout << endl << "M = ";
cin >> m;
cout << endl << "N = ";
cin >> n;
// Достает элемент матрицы, ждет ввода пользователя, присваивает введенное число в значение элемента
if (m >= 0 && n >= 0 && m < mtx->M && n < mtx->N)
{
Node* node = At(mtx, m, n);
cout << node->value << " = ";
cin >> node->value;
cout << endl;
Trace(mtx);
}
else
{
cout << "Нет такого элемента" << endl;
}
}
else
{
cout << "Матрица не загружена из файла" << endl;
}
break;
case 3:
if (mtx)
{
int m = 0;
int n = 0;
cout << endl << "M = ";
cin >> m;
cout << endl << "N = ";
cin >> n;
if (m >= 1 && n >= 1)
{
Matrix* new_mtx = Create(m, n);
for (int x = 0; x < new_mtx->M && x < mtx->M; x++)
{
for (int y = 0; y < new_mtx->N && y < mtx->N; y++)
{
At(new_mtx, x, y)->value = At(mtx, x, y)->value;
}
}
Delete(&mtx);
mtx = new_mtx;
Trace(mtx);
}
else
{
cout << "Введите валидные величины" << endl;
}
}
else
{
cout << "Матрица не загружена из файла" << endl;
}
break;
case 4:
{
if (mtx)
{
int T = 0;
cout << "Введите T:" << endl;
cin >> T;
//
int len = mtx->M * mtx->N;
int negMax = INT32_MIN; // Если ничего не найдено, то здесь остается это значение (самое минимульно возможное значение int32)
for (int i = 0; i < len; i++) {
Node* item = At(mtx, i); // Достается элемент по индексу
if (item->value < 0)
{
if (item->value > negMax)negMax = item->value;
}
if (item->value == T) break;
}
if (negMax == INT32_MIN)
{
cout << "Не удалось найти максимальное среди отрицательных" << endl;
}
else
{
cout << "Максимальное среди отрицательных: " << negMax << endl;
}
}
else
{
cout << "Матрица не загружена из файла" << endl;
}
}
break;
case 5:
//
if (mtx)
{
Delete(&mtx);
mtx = NULL;
}
else
{
cout << "Матрица не загружена из файла" << endl;
}
//
break;
case 6:
exit = true;
break;
default:
break;
}
}
cout << "Press any key to exit..." << endl;
system("pause");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment