PDA

Просмотр полной версии : [Вопрос] Упорядочить массив



m1n1vv
04.02.2019, 19:13
Как переставить нули в конец массива? Для этого нужен двойной цикл?

Сделал так, но сомневаюсь, что правильно

main() {

const
size = 5;

static
m[size] = {0, 8, 0, 3, 1};

for (new i = 0; i < size; i++)
{
if (m[i] == 0)
{
for (new j = i; j < size; j++)
{
if (m[j] != 0)
{
m[i] = m[j];
m[j] = 0;
break;
}
}
}
printf("%i", m[i]);
}
}

x86
04.02.2019, 19:59
new arr[] = {1,0,6,2,1,0,0,1,1,2};
new cnt = 0, i = 0, c;
while (i<sizeof(arr)) {
c = arr[i++];
if (c == 0)
continue;
arr[cnt++] = c;
}
while (cnt < n) {
arr[cnt++] = 0;
}

Seviel
04.02.2019, 21:35
Возможно поможет алгоритмы сортировки (https://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8)

x86
04.02.2019, 21:55
Возможно поможет алгоритмы сортировки (https://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8)

Действительно, можно сделать сортировку по убыванию. Однако на сортировку уходит достаточно приличное время, чем на код, который я предоставил выше.

Daniel_Cortez
05.02.2019, 00:27
new arr[] = {1,0,6,2,1,0,0,1,1,2};
new cnt = 0, i = 0, c;
while (i<sizeof(arr)) {
c = arr[i++];
if (c == 0)
continue;
arr[cnt++] = c;
}
while (cnt < n) {
arr[cnt++] = 0;
}

Код в целом оптимальный, но первый цикл можно было скомпоновать чуть удачнее:

do {
if ((c = arr[i++]) != 0)
arr[cnt++] = c;
} while (++i < sizeof(arr));

Во-первых, do-while подходит больше, т.к. размер массива не может быть меньше 1. Бонусом вместо 3 джампов (1-й в самом начале цикла, после проверки условия выхода, 2-й в виде continue и 3-й в конце тела цикла while) получаем всего 2 (1-й в виде if и 2-й после проверки условия выхода из do-while).
Во-вторых, присваивание в переменную 'c' перемещено в выражение внутри if, чтобы вместо 2 обращений к 'c' (запись в 'c', затем оттуда же чтение) было всего 1 (сначала запись значения в 'c', а затем "повторное использование" того же значения в проверке на равенство нулю, вместо того чтобы заново считывать его из 'c').
(На самом деле даже это не самый удачный вариант цикла, просто те 2 оптимизационных приёма было проще всего объяснить.)

m1n1vv
05.02.2019, 09:17
Делаю, чтобы из диалогового окна пропадал выбранный вариант. Для этой задачи этого может хватить. Игрок не может сразу выбрать 2 пункта.

main()
{
const
size = 5;

new
m[size] = {1, 8, 2, 0, 3},
index_i;

for (new i = 0; i < size; i++)
{
if (m[i] == 0)
{
index_i = i == size - 1 ? 0 : 1;
m[i] = m[i+index_i];
m[i+index_i] = 0;
}

printf("%i", m[i]);
}
}

x86
05.02.2019, 15:29
Код в целом оптимальный, но первый цикл можно было скомпоновать чуть удачнее:

do {
if ((c = arr[i++]) != 0)
arr[cnt++] = c;
} while (++i < sizeof(arr));

Во-первых, do-while подходит больше, т.к. размер массива не может быть меньше 1. Бонусом вместо 3 джампов (1-й в самом начале цикла, после проверки условия выхода, 2-й в виде continue и 3-й в конце тела цикла while) получаем всего 2 (1-й в виде if и 2-й после проверки условия выхода из do-while).
Во-вторых, присваивание в переменную 'c' перемещено в выражение внутри if, чтобы вместо 2 обращений к 'c' (запись в 'c', затем оттуда же чтение) было всего 1 (сначала запись значения в 'c', а затем "повторное использование" того же значения в проверке на равенство нулю, вместо того чтобы заново считывать его из 'c').
(На самом деле даже это не самый удачный вариант цикла, просто те 2 оптимизационных приёма было проще всего объяснить.)

Можно было вообще вот так сделать:

while ((i < sizeof(arr)) && (c = arr[i++]))
arr[cnt++] = c;


Запихивать операцию присваивания в условый оператор - не лучшая затея. А вообще плохо, что компилятор глуп на такие оптимизации.

Daniel_Cortez
06.02.2019, 16:36
А вообще плохо, что компилятор глуп на такие оптимизации.
Это простой компилятор для простого скриптового языка, а не какой-то там "комбайн" на основе LLVM. Абсолютно ничего необычного.

x86
06.02.2019, 17:18
Это простой компилятор для простого скриптового языка, а не какой-то там "комбайн" на основе LLVM. Абсолютно ничего необычного.

И без LLVM компиляторы пишутся. Причем такая конструкция проста для простого компилятора для простого скриптового языка. В нем же поддерживаются шаблоны инструкций для оптимизации.

Daniel_Cortez
06.02.2019, 19:04
Делаю, чтобы из диалогового окна пропадал выбранный вариант. Для этой задачи этого может хватить. Игрок не может сразу выбрать 2 пункта.

main()
{
const
size = 5;

new
m[size] = {1, 8, 2, 0, 3},
index_i;

for (new i = 0; i < size; i++)
{
if (m[i] == 0)
{
index_i = i == size - 1 ? 0 : 1;
m[i] = m[i+index_i];
m[i+index_i] = 0;
}

printf("%i", m[i]);
}
}
Так а зачем нужно тратить время на перестановку элементов, когда можно одним циклом найти ноль, а другим просто скопировать последующие элементы на место предыдущего и обнулить последний элемент?

main()
{
static arr[] = {1, 8, 2, 0, 3};
new i = 0;

do {
if (arr[i] == 0)
{
do {
arr[i] = arr[++i];
} while (i < sizeof(arr) - 1);
arr[sizeof(arr) - 1] = 0;
break;
}
} while (++i < sizeof(arr) - 1);
}



И без LLVM компиляторы пишутся. Причем такая конструкция проста для простого компилятора для простого скриптового языка. В нем же поддерживаются шаблоны инструкций для оптимизации.
Новые оптимизации никто не добавит - боятся сломать хаки в чьём-нибудь инклуде. Собственно, слова про "ничего необычного" были про сам компилятор, про развиваемый сообществом SA-MP форк (https://github.com/pawn-lang/compiler) разговор отдельный.