Побитовый сдвиг для генерации всех возможных перестановок в C
Возможный дубликат:
Создание нескольких номеров с определенным количеством бит, установленным
Я пытаюсь написать некоторый код, который поместит каждую возможную комбинацию чисел в массив, сдвинув биты.
Например, я хотел найти все возможные комбинации из 3 бит (где максимальная цифра может быть равна 6), массив должен содержать:
000111
001011
001101
001110
010011
010101
010110
011001
011010
011100
100011
И так далее...
Из того, что я интерпретировал, когда бит последней позиции равен 1, мы сдвигаем число на 1 (x → 1) и добавляем 1 в начале. Однако я не уверен, как закодировать остальные. Я использую C, чтобы написать это.
Кроме того, насколько я могу судить, это последовательность colex, однако, я все уши, если есть другая последовательность, которая даст мне тот же конечный результат (массив со всеми возможными комбинациями k-бит с ограничением из N).
Ответы
Ответ 1
Вы можете решить эту проблему путем генерации последовательностей рекурсивно.
Определим рекурсивную функцию f(int index, int bits, int number)
, которая будет принимать текущий index
бит и число bits
, оставленное на место, и number
, сгенерированное до сих пор. Затем у вас есть возможность установить текущий бит в 1 или 0 и вернуться к нему.
В целом, сложность времени должна быть O (количество последовательностей) или O (N выбор B), где N - количество цифр, а B - количество бит, установленное в 1.
Функция выглядит примерно так:
void f(int index, int bits, int number) {
if (index == 0) {
if (bits == 0) { // all required bits have been used
emit_answer(number); // chuck number into an array, print it, whatever.
}
return;
}
if (index-1 >= bits) { // If we can afford to put a 0 here
f(index-1, bits, number);
}
if (bits > 0) { // If we have any 1s left to place
f(index-1, bits-1, number | (1 << (index-1)));
}
}
// to call:
f(6, 3, 0);
Для N,B = 6,3
вывод соответствует вашему, и находится в отсортированном порядке. Ссылка на рабочий пример: http://codepad.org/qgd689ZM
Ответ 2
Нет необходимости в какой-либо причудливой рекурсии. Некоторая простая математика будет достаточной (требуется деление на значение, которое всегда будет состоять из двух).
Function nextBits(ByVal prevVal As Integer)
Dim lsOne As Integer = ((prevVal - 1) And Not prevVal) + 1
Dim nextZero As Integer = (prevVal + lsOne) And Not prevVal
Dim lowBits As Integer = ((nextZero \ lsOne \ 2) - 1)
Return prevVal + lsOne + lowBits
End Function
Приятно и легко.
Ответ 3
Вероятно, более эффективный способ, но вы можете просто прокручивать числа и отклонять числа, которые не имеют бит в 3 раза? См. этот ответ для подсчета бит.