Интересная проблема, если вы ограничены в прохождении массива строка за строкой.
Я разделил прямоугольник на три области. верхний левый треугольник , нижний правый треугольник и ромб в середине .
Для верхнего левого треугольника значения в первом столбце (x = 0) могут быть рассчитаны с использованием общего арифметического ряда 1 + 2 + 3 + .. + n = n*(n+1)/2
. Поля в этом треугольнике с одним и тем же значением x + y имеют одинаковую диагональ, и там это значение равно сумме из первого столбца + x.
Тот же подход работает для нижнего правого треугольника . Но вместо x
и y
используются w-x
и h-y
, где w
- ширина, а h
- высота прямоугольника. Это значение должно быть вычтено из наибольшего значения w*h-1
в массиве.
Существует два случая ромбоида в середине . Если ширина прямоугольника больше (или равна) высоты, то нижнее левое поле прямоугольника является полем с наименьшим значением в ромбоиде и может быть вычислено по этой сумме ранее для h-1
. Отсюда вы можете представить, что ромбоид представляет собой прямоугольник со значением x x+y
и значением y y
от исходного прямоугольника. Таким образом, вычисления оставшихся значений в этом новом прямоугольнике просты.
В другом случае, когда высота больше ширины, тогда поле в x=w-1
и y=0
может быть вычислено с использованием этой арифметической суммы, а ромбоид может быть представлен в виде прямоугольника со значением x x
и y- значение y-(w-x-1)
.
Код можно оптимизировать, например, путем предварительного вычисления значений. Я думаю, что есть также одна формула для всех этих случаев. Может быть, я подумаю об этом позже.
inline static int diagonalvalue(int x, int y, int w, int h) {
if (h > x+y+1 && w > x+y+1) {
// top/left triangle
return ((x+y)*(x+y+1)/2) + x;
} else if (y+x >= h && y+x >= w) {
// bottom/right triangle
return w*h - (((w-x-1)+(h-y-1))*((w-x-1)+(h-y-1)+1)/2) - (w-x-1) - 1;
}
// rhomboid in the middle
if (w >= h) {
return (h*(h+1)/2) + ((x+y+1)-h)*h - y - 1;
}
return (w*(w+1)/2) + ((x+y)-w)*w + x;
}
for (y=0; y<h; y++) {
for (x=0; x<w; x++) {
array[x][y] = diagonalvalue(x,y,w,h);
}
}
Конечно, если такого ограничения нет, нечто подобное должно быть намного быстрее:
n = w*h;
x = 0;
y = 0;
for (i=0; i<n; i++) {
array[x][y] = i;
if (y <= 0 || x+1 >= w) {
y = x+y+1;
if (y >= h) {
x = (y-h)+1;
y -= x;
} else {
x = 0;
}
} else {
x++;
y--;
}
}