Суммы элементов между диагоналями
Поможем в ✍️ написании учебной работы
Поможем с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой

Далее идут функции, осуществляющие подсчёт сумм элементов выше и ниже пересечения диагоналей, а так же смену местами этих элементов. Главной диагональю считается множество элементов матрицы, индексы которых совпадают, побочной диагональю считается та, которая идёт по диагонали из нижнего левого угла матрицы.

Функции GetSumAbove и GetSumBelow проходят соответствующие половины строк матрицы, для каждой строки высчитывая диапазон столбцов, из которых нужно суммировать элементы:

 

1 {возвращает сумму элементов выше пересечения диагоналей матрицы arr}

2 function GetSumAbove (const arr: TMatrix): Int64;

3 var

4 RowN, ColN: integer;

5 lastColumn: integer;//номер столбца, содержащего элемент дальней диагонали минус 1

6 begin

7 Result:= 0;

8 for RowN:= 0 to (high(arr) div 2) do

9 begin//с нулевой, по средюю строку

10 lastColumn:= high(arr)-RowN-1;//определим номер столбца последнего элемента, подлежащего суммированию

11 //если число столбцов меньше числа строк, то последний столбец может оказаться ближе

12 if lastColumn > high(arr[RowN]) then lastColumn:= high(arr[RowN]);

13 for ColN:= RowN+1 to lastColumn do //просуммируем элементы в высчитаных пределах

14 Result:= Result + arr[RowN, ColN];

15 end;

16 end;

17 {возвращает сумму элементов ниже пересечения диагоналей матрицы arr}

18 function GetSumBelow(const arr: TMatrix): Int64;

19 var

20 RowN, ColN: integer;

21 lastColumn: integer;//номер столбца, содержащего элемент дальней диагонали минус 1

22 begin

23 Result:= 0;

24 for RowN:= (high(arr) div 2)+1 to high(arr) do

25 begin//со средней по последнюю строку

26 lastColumn:= RowN-1;//определим номер столбца последнего элемента, подлежащего суммированию

27 //если число столбцов меньше числа строк, то последний столбец может оказаться ближе

28 if lastColumn > high(arr[RowN]) then lastColumn:= high(arr[RowN]);

29 for ColN:= high(arr)-RowN+1 to lastColumn do //просуммируем элементы в высчитаных пределах

30 Result:= Result + arr[RowN, ColN];

31 end;

32 end;

 

Процедура SwapAboveBelow таким же образом, как функция GetSumAbove, определяет, какие элементы лежат выше пересечения диагоналей, но не суммирует их, а каждый меняет местами с элементом того же столбца, симметричным текущему относительно верхней и нижней границ матрицы. Для смены используется вспомогательная процедура swap для целых чисел, определённая в этом же модуле:

 

1 {вспомогательная процедура: поменять местами два целых числа}

2 procedure swap(var first, second: integer);

3 var tmp: integer;

4 begin

5 tmp:= first;

6 first:= second;

7 second:= tmp;

8 end;

9 {поменять местами элементы выше и ниже пересечения диагоналей матрицы arr}

10 procedure SwapAboveBelow (var arr: TMatrix);

11 var

12 RowN, ColN: integer;

13 lastColumn: integer;//номер столбца, содержащего элемент дальней диагонали минус 1

14 begin

15 for RowN:= 0 to (high(arr) div 2) do

16 begin//с нулевой, по средюю строку

17 lastColumn:= high(arr)-RowN-1;//определим номер столбца последнего элемента, подлежащего суммированию

18 //если число столбцов меньше числа строк, то последний столбец может оказаться ближе

19 if lastColumn > high(arr[RowN]) then lastColumn:= high(arr[RowN]);

20 for ColN:= RowN+1 to lastColumn do//для каждого элемента в высчитаных пределах

21 //поменяем его местами с элементом того же столбца, отстаящем на то же число строк, но от нижней границы матрицы

22 swap(arr[RowN, ColN], arr[high(arr) - RowN, ColN]);

23 end;

24 end;

Циклический сдвиг строк

Далее функция CircuarShift, осуществляющая циклический сдвиг строк матрицы вверх, или вниз. Направление сдвига определяется булевым параметром shiftUp, передаваемым процедуре:

 

1 {

2 осуществляет циклический сдвиг строк матрицы arr вверх при shiftUp = true,

3 и вниз, при shiftUp = false

4 }

5 procedure CircuarShift(var arr: TMatrix; shiftUp: boolean);

6 var

7 RowN: integer;

8 tmpRow: TVector;//временная переменная для хранения строки иатрицы

9

10 begin

11

12 if high(arr) < 1 then exit;//если в матрице меньше двух строк - выходим

13 if shiftUp then

14 begin//если сдвиг вверх

15 tmpRow:= arr[high(arr)];//сохраним последнюю строку матрицы

16 arr[high(arr)]:= arr[0];//приравняем последнюю строку первой

17 for rowN:= 0 to high(arr)-2 do

18 begin//для строк с нулевой по пред-предпоследнюю

19 arr[rowN]:= arr[rowN+1];//текущая строка равна нижней

20 end;

21 arr[high(arr)-1]:= tmpRow;//предпоследнюю строку приравняем последней

22 end

23 else

24 begin//иначе, если сдвиг вниз

25 tmpRow:= arr[0];//сохраним нулвую строку

26 arr[0]:= arr[high(arr)];//приравняем нулевую строку последней

27 for rowN:= high(arr) downto 2 do

28 begin//для строк с последней по вторую

29 arr[RowN]:= arr[RowN-1];//текущая строка равна верхней

30 end;

31 arr[1]:= tmpRow;//первую строку приравняем нулевой

32 end;

33 end;

«Разворачивание» матрицы

Процедура UnwindMatrix осуществляет "разворачивание" матрицы в одномерный массив против часовой стрелки. Эта процедура в своих локальных переменных хранит координаты текущего элемента, текущее направление обхода (посредством перечислимого типа TDirection), а так же границы ещё не обойдённой части матрицы, которые сужаются каждый раз, когда проходится целая строка, или столбец. В этот же момент меняется направление обхода и текущим становится элемент в этом направлении. Обход завершается, когда число пройденных элементов станет равняться количеству элементов в матрице:

 

1 //перечисление - направления

2 type TDirection = (down, right, up, left);

3

4 {обходит матрицу arr против часовой стрелки и наполняет элементами массив res}

5 procedure UnwindMatrix(const arr: TMatrix; var res: TVector);

6 var

7 count, cur: integer;//число элементов в матрице и счётчик элементов

8

9 RowN, ColN: integer;

10 leftB, bottomB, rightB, topB: integer;//границы обхода - меняются при проходе полной строки или столбца

11 direction: TDirection;//текущее направление обхода

12

13 begin

14 if (length(arr) = 0) or (length(arr[0]) = 0) then exit;//если в матрице нет элементов - выходим

15 count:= length(arr) * length(arr[0]);//подсчитаем число элементов в матрице

16 SetLength(res, count);//выделим память для хранения всех элементов матрицы

17

18 //начальные условия обхода: текущий элемент [0,0], границы совпадают с граниуцами матриы, направление - вниз

19 direction:= down;

20 RowN:= 0;

21 ColN:= 0;

22 leftB:= 0;

23 bottomB:= high(arr);

24 rightB:= high(arr[0]);

25 topB:= 0;

26

27 for cur:= 0 to count-1 do

28 begin//пока не пройдём count элементов

29 res[cur]:= arr[RowN, ColN];//добавляем текущий элемент в массив

30 //дальненйшие действия зависят от текущего направления обхода

31 case direction of

32 down://если вниз

33 if RowN < bottomB then inc(RowN)//если не дошли до нижней границы - сдвигаемся вниз

34 else

35 begin//иначе - прошли левый столбец

36 direction:= right;//сменим направление на "вправо"

37 inc(leftB);//сдвинем левую границу к центру

38 inc(ColN);//сдвинемся вправо

39 end;

40

41 right://если вправо

42 if ColN < rightB then inc(ColN)//если не дошли до правой границы - сдвигаемся вправо

43 else

44 begin//иначе - прошли нижнюю строку

45 direction:= up;//сменим направление на "вверх"

46 dec(bottomB);//сдвинем нижнюю границу к центру

47 dec(RowN);//сдвинемся вверх

48 end;

49

50 up://если вверх

51 if RowN > topB then dec(RowN)//если не дошли до верхней границы - сдвигаемся вверх

52 else

53 begin//иначе - прошли правый столбец

54 direction:= left;//сменим направление на "влево"

55 dec(rightB);//сдвинем правую границу к центру

56 dec(ColN);//сдвинемся влево

57 end;

58

59 left://если влево

60 if ColN > leftB then dec(ColN)//если не дошли до левой границы - сдвигаемся влево

61 else

62 begin//иначе - прошли верхнюю строку

63 direction:= down;//сменим направление на "вниз"

64 inc(topB);//сдвинем верхнюю границу к центру

65 inc(RowN);//сдвинемся вниз

66 end;

67 end;

68 end;

69 end;

Сортировка строк матрицы

Наконец упорядочивание строк матрицы по убыванию суммы элементов каждой строки. Вспомогательная функция getRowSum возвращает сумму элементов заданной строки:

 

1 {возвращает сумму элементов RowN-ой строки матрицы arr}

2 function getRowSum(const arr: TMatrix; RowN: integer): Int64;

3 var ColN: integer;

4 begin

5 Result:= 0;

6 if RowN > high(arr) then exit;//если в матрице нет RowN-ой строки - выходим

7 for ColN:= 0 to high(arr[RowN]) do//суммируем элементы строки

8 Result:= Result + arr[RowN, ColN];

9 end;

 

Сама сортировка осуществляется посредством процедуры SortRows. Был выбран алгоритм прямой вставки, так как число строк в матрице не предполагается большим, а этот алгоритм эффективен на небольших наборах данных. В любом случае сортировка осуществляется быстро, так как при перемене мест строк не происходит копирование данных, но просто переставляются местами указатели. Листинг этой функции:

 

1 {сортирует строки матрицы по убыванию сумм элементов каждой строки}

2 procedure SortRows(var arr: TMatrix);

3 var

4 i, k: integer;//переменные для алгоритма сортировки

5 tmpRow: TVector;//временная переменная для алгоритма сортировки

6 begin

7 //алгоритм сортировки методом прямой вставки

8 for i:= 1 to high(arr) do

9 begin//для строк с первой по последнюю

10 k:= i;//начиная с текущей строки

11 while (k > 0) and (getRowSum(arr, k) > getRowSum(arr, k-1)) do

12 begin//пока не дошли до нулевой строки, и сумма строки над текущей строкой больше текущей суммы

13 swap(arr[k-1], arr[k]);//поменяем текущую строку и строку над ней местами

14 dec(k);//сдвинемся вверх

15 end;

16 end;

17 end;

 

Модуль fileIO

Этот модуль содержит процедуры для файлового ввода/вывода матриц. Используются текстовые файлы, которые предварительно необходимо открыть и подготовить к чтению/записи.

Формат файла, содержащего матрицу таков: матрица записана построчно, начиная с первой строки, элементы в каждой строке записаны слева направо и разделены произвольным количеством пробелов. Именно такой файл создаёт процедура Write 2 DArray:

 

1 {

2 записывает матрицу arr в текстовый файл outFile. Файл должен быть

3 предварительно открыт

4 }

5 procedure Write2DArray(const arr: TMatrix; const outFile: TextFile);

6 var

7 rowN, colN: integer;

8 begin

9 for rowN:= low(arr) to high(arr) do

10 begin

11 for colN:= low(arr[rowN]) to high(arr[rowN]) do

12 begin

13 //ширина поля 12, так как -2147483648 - 11 символов

14 Write(outFile, arr[rowN, colN]: 12);

15 end;

16 Writeln(outFile);

17 end;

18 end;


Процедура Read 2 DArray читает файл по строкам, разбирая каждую строку на подстрока пробелами с помощью процедуры ExtractStrings:

 

1 { читает матрицу arr из текстового файла inFile. Файл должен быть

2 предварительно открыт}

3 procedure Read2DArray(var arr: TMatrix; const inFile: TextFile);

4 var

5 rowN, colN: integer;

6 colCount: integer; //максимальное количество чисел в строке (число столбцов матрицы)

7 lineStr: string; //текущая строка

8 strNumbers: TStringList;//текущая строка, разделённая на подстроки пробелами

9 begin

10 rowN:= 0;

11 colCount:= 0;

12 strNumbers:= TStringList.Create;

13 arr:= nil;

14 while not Eof(inFile) do

15 begin

16 Readln(inFile, lineStr);

17 strNumbers.Clear;

18 ExtractStrings([' '], [], PChar(lineStr), strNumbers); //разделим пробелами на подстроки

19 if colCount < strNumbers.Count then colCount:= strNumbers.Count;

20 SetLength(arr, rowN+1, colCount);//выделим память под новую строку

21 for colN:= 0 to strNumbers.Count-1 do //для каждого числа в строке

22 arr[rowN, colN]:= StrToIntDef(strNumbers[colN], 0);

23 Inc(rowN);

24 end;

25 strNumbers.Destroy;

26 end;

 


Модуль form

Модуль, содержащий форму, переменную для хранения исходной матрицы, процедуры синхронизации содержания матрицы и элементов формы, а так же процедуру задания размеров матрицы.

Так как задача чётко разделена на задания, оперирующие одними и теми же исходными данными (целочисленным двумерным массивом), было принято решение разделить интерфейс приложения на две части. В верхней части формы отображается матрица исходных данных, которую можно редактировать и размеры которой можно менять. Нижняя часть формы представляет собой набор закладок, каждая из которых соответствует одной из поставленных задач. На каждой закладке содержится описание задания, кнопка «выполнить», а так же элементы, необходимы для отображения результата в рамках этого задания. Некоторые задания состоят в изменении исходной матрицы, результат выполнения таких заданий отображается непосредственно в исходных данных в верхней части формы. Всего существует как минимум три способа выбрать задачу: щёлкнуть мышкой по закладке, выбрать нужный пункт в меню «Задачи», нажать одну из кнопок F1 - F5.

Опишем важные процедуры формы. Процедура ReadMatrix осуществляет чтение исходных данных из таблицы на форме в двумерный массив. Перед началом чтения процедура устанавливает размер массива:

 

1 {заполнить матрицу в соответствии с содержанием таблицы на форме}

2 procedure TMainForm.ReadMatrix;

3 var rowN, colN: integer;

4 begin

5 SetLength(workMatrix, G_Matrix.RowCount-1, G_Matrix.ColCount-1);

6 for rowN:= 0 to G_Matrix.RowCount-2 do

7 for colN:= 0 to G_Matrix.ColCount-2 do

8 workMatrix[rowN, colN]:= StrToIntDef(G_Matrix.Cells[colN+1, rowN+1], 0);

9 end;

 

Процедура writeMatrix осуществляет обратную операцию, она заполняет поля таблицы в соответствии с массивом. Кроме этого она меняет значения числа строк и столбцов в соответствии с размерами массива:

 

1 {заполнить таблицу на форме в соответствии с содержанием матрицы}

2 procedure TMainForm.writeMatrix;

3 var rowN, colN: integer;

4 begin

5 G_Matrix.Cells[1, 1]:= '';//если матрица пуста

6 E_RowsN.Text:= IntToStr(high(workMatrix) + 1);

7 if(E_RowsN.Text <> '0') then

8 E_ColsN.Text:= IntToStr(high(workMatrix[low(workMatrix)]) + 1)

9 else E_ColsN.Text:= '0';

10 B_SetDimmsClick(self);

11 //заполним таблицу

12 for rowN:= low(workMatrix) to high(workMatrix) do

13 for colN:= low(workMatrix[rowN]) to high(workMatrix[rowN]) do

14 G_Matrix.Cells[colN+1, rowN+1]:= IntToStr(workMatrix[rowN, colN]);

15 end;

 

Процедура B_SetDimmsClick является обработчиком нажатия кнопки «задать размеры». Она проверяет, не стали ли размеры меньше единицы, меняет число строк и столбцов в таблицах формы, а так же проставляет номера строк и столбцов:

 

1 {обраюотчик уствновки размеров матрицы}

2 procedure TMainForm.B_SetDimmsClick(Sender: TObject);

3 var

4 i: integer;

5 RowsN, ColsN: integer;

6 begin

7 //значения размеров не должны быть меньше 1

8 RowsN:= StrToIntDef(E_RowsN.Text, 0);

9 if RowsN < 1 then begin RowsN:= 1; E_RowsN.Text:= '1' end;

10 ColsN:= StrToIntDef(E_ColsN.Text, 0);

11 if ColsN < 1 then begin ColsN:= 1; E_ColsN.Text:= '1' end;

12 //число строк и столбцов в таблице, учитывая колонку и строку с номерами

13 G_Matrix.RowCount:= RowsN + 1;

14 G_Matrix.ColCount:= ColsN + 1;

15 //в этих таблицах отображаются одномерные массивы из первого задания

16 G_Task1B.RowCount:= RowsN;

17 G_Task1C.RowCount:= RowsN;

18 //одномерный массив из четвёртого задания имеет длину, равную числу элементов исходной матрицы

19 G_Task4.ColCount:= RowsN * ColsN;

20 //расставим номера строк и столбцов

21 for i:= 0 to RowsN do

22 begin

23 G_Matrix.Cells[0, i+1]:= IntToStr(i+1);

24 G_Task1B.Cells[0, i]:= IntToStr(i+1);

25 G_Task1C.Cells[0, i]:= IntToStr(i+1);

26 end;

27 for i:= 0 to ColsN do

28 G_Matrix.Cells[i+1, 0]:= IntToStr(i+1);

29 for i:= 0 to RowsN * ColsN do

30 G_Task4.Cells[i, 0]:= IntToStr(i+1);

31 G_Matrix.Refresh;

32 end;

 

Процедура FormDestroy выполняется при уничтожении формы и выполняет очень важную функцию – освобождает память, которая выделялась во время работы приложения под матрицу исходных данных.

Процедура saveClick является обработчиком щелчка по пункту меню Файл->Сохранить. Она отображает диалог выбора файла для сохранения, создаёт выбранный файл, а после окончания записи закрывает его:

 

1 {обработчик Файл->Сохранить}

2 procedure TMainForm.saveClick(Sender: TObject);

3 var

4 outFile: TextFile;

5 begin

6 //отобразим диалог выбора файла для сохранения, если отмена - выходим

7 if SaveDialog.Execute = false then exit;

8 AssignFile(outFile, SaveDialog.Files[0]);

9 ReWrite(outFile);//создадим файл

10  readMatrix;//прочтём матрицу из таблицы

11 Write2DArray(workMatrix, outFile);//запишем матрицу в файл

12 CloseFile(outFile);//закроем файл.


Процедура loadClick ведёт себя так же, только не создаёт файл, а открывает его для чтения:

 

1 {обработчик Файл->Загрузить}

2 procedure TMainForm.loadClick(Sender: TObject);

3 var

4 inFile: TextFile;

5 begin

6 //отобразим диалог выбора фала для загрузки, если отмена - выходим

7 if OpenDialog.Execute = false then exit;

8 AssignFile(inFile, OpenDialog.Files[0]);

9 Reset(inFile);//подготовим файл к чтению

10 Read2DArray(workMatrix, inFile);//прочтём матрицу из файла

11 writeMatrix;//отобразим матрицу

12 CloseFile(inFile);//закроем файл

13 end;

 

Остальные процедуры просто вызывают процедуры и функции других модулей, наполняют результатами соответствующие заданию элементы формы, а в конце обязательно освобождают динамическую память, если таковая была выделена в рамках процедуры.

 


Дата: 2019-07-30, просмотров: 156.