Отсортировать элементы матрицы - Pascal
Формулировка задачи:
Дано натуральное N (1 ≤ N ≤ 10), целочисленный квадратный массив-матрица (aij), 0 ≤ i ,j < N. Отсортировать элементы матрицы так, чтобы при прохождении по схеме они были бы упорядочены по не убыванию. Методом быстрой рекурсивной сортировки.
Змейка из двух частей: вначале сверху вниз по строкам «вправо-влево» до побочной диагонали матрицы, потом снизу вверх по строкам «вправо-влево» от побочной диагонали матрицы.
Важное ограничение. При сортировке элементов матрицы не разрешается использовать дополнительные структуры данных (массивы), то есть вся сортировка должна производиться «на месте» – в исходном массиве. Кроме этого нужно сохранить временную сложность алгоритма сортировки: другими словами нельзя вводить дополнительных циклов (например, для вычисления координат) по сравнению с теми, что уже есть в сортировке.
0 1 2 3 6 5 4 15 7 8 14 13 9 10 11 12
Решение задачи: «Отсортировать элементы матрицы»
textual
Листинг программы
//глобальные константа и переменные: видны и в программе, и во всех подпрограммах
const m = 10; //максимальный размеры массива
var n, tn, gi, gj: integer; //размер массива, треугольное число, индексы массива
a: array [0..m-1, 0..m-1] of integer; //массив
//процедура генерации массива (можно при желании заменить процедурой ввода)
procedure gen(n: integer);
var i, j: integer;
begin
for i := 0 to n - 1 do
for j := 0 to n - 1 do a[i, j] := -99 + random(199)
end;
//процедура печати массива,
//параметры: s - заголовок, n - размер массива
procedure prn(s: string; n: integer);
var i, j: integer;
begin
writeln(s);
for i := 0 to n - 1 do
begin
for j := 0 to n - 1 do write(a[i, j]: 4);
writeln
end
end;
//функция получения индексов массива, возвращает i, а также i и j в глобальных переменных
//параметр: номер элемента в "хитрой змейке"
//возвращаемые значения: i в gij и в gi, j в gj
//например, a[gij(x), gj]
// ^ ^
//сначала функция вычисляет i и j и возвращает i -+ |
//теперь j (и i тоже) вычислены, можно использовать j ---+
function gij(k: integer): integer;
var p, v: integer; //номер строки с треугольным числом, верхняя граница треугольника
w: boolean; //флаг нижнего треугольника
begin
w := k >= tn; //определяем, который треугольник
if w //если нижний треугольник
then v := n * n //то граница - последний номер элемента
else v := tn; //иначе граница - треугольное число
p := v - 1 - k; //вычисляем номер строки
gi := trunc(sqrt(1 + 8 * p) - 1) div 2; //индекс i
gj := p - gi * (gi + 1) div 2; //индекс j
if odd(n - gi) then gj := gi - gj; //коррекция gj для чётного n-1-i
if w then gj := n - 1 - gj; //коррекция j для нижнего треугольника
inc(gi); //общая коррекция i
if not w then gi := n - gi; //коррекция i для верхнего треугольника
gij := gi //сама функция возвращает i (а ещё дублирует i и помещает j в глобальные переменные gi и gj)
end;
//рекурсивная функция быстрой сортировки (она же - сортировка Хоара)
//параметры: границы сортировки в виде номеров "хитрой змейки"
procedure hoar(l, r: integer);
var i, j, x, y: integer; //текущие границы в "хитрой змейке", середина этого интервала, буферная переменная
begin
i := l; //сохраняем текущие границы
j := r;
x := a[gij((l + r) div 2), gj]; //вычисляем середину
repeat //цикл сортировки в пределах текущих границ
while a[gij(i), gj] < x do inc(i); //если элемент нижней границы меньше элемента средней, то отсортировано, увеличиваем нижнюю границу
while x < a[gij(j), gj] do dec(j); //если элемент верхней границы больше элемента средней, то отсортировано, уменьшаем верхнюю границу
if i <= j //если индексы не пересеклись,
then begin //то
if a[gij(i), gj] > a[gij(j), gj] //если элементы на границах не в том порядке,
then begin
y := a[gij(j), gj]; //то меняем их местами
a[gij(j), gj] := a[gij(i), gj];
a[gi, gj] := y
end;
inc(i); //увеличиваем границы, по-любому за границами уже отсортировано
dec(j)
end;
until i >= j; //если границы встретились или поменялись местами, то сортировка текущего интекрвала закончена
if l < j then hoar(l, j); //если j больше нижней границы, рекурсивный вызов сортировки интервала от нижней границы до j
if i < r then hoar(i, r); //если i меньше нижней границы, рекурсивный вызов сортировки интервала от i до нижней границы
end;
begin
randomize; //инициализация ГПСЧ
repeat //ввод размера массива с проверкой
write('n in [1..', m, ']; n = ');
readln(n)
until n in [1..m];
gen(n); //генерация массива
prn('Исходный массив:', n); //печать исходного массива
tn := n * (n + 1) div 2; //вычисление треугольного числа для последней строки массива
hoar(0, n * n - 1); //сортировка массива
prn('Отсортированный массив:', n); //вывод отсортированного массива
readln
end.
Объяснение кода листинга программы
- Объявляются глобальная константа
mсо значением 10, и глобальные переменныеn,tn,gi,gjтипа целое число, иa- массив целых чисел размеромmнаm. - Происходит определение процедуры
gen, которая инициализирует значения массиваaслучайными числами. - Определяется процедура
prnдля печати значений элементов массива. - Функция
gijполучает индексы массива по числуkвхитрой змейке. - Реализуется рекурсивная функция
hoarдля быстрой сортировки, с использованиемхитрой змейкидля доступа к элементам массива. - В основном блоке программы инициализируется генератор псевдослучайных чисел, происходит ввод размера массива, инициализация массива, печать исходного массива, вычисление треугольного числа и сортировка массива при помощи функции
hoar, вывод отсортированного массива. Note: Последующий код приведен в языке Pascal.