Ваш код хорош, если вы хотите проверить, является ли один конкретный номер числом помех. Когда вы хотите создать список номеров для помех, это неэффективно.
Вы можете использовать подход снизу вверх: Начните с 1, а затем рекурсивно размножайтесь с 2, 3 и 5, чтобы получить все номера помех до определенного предела. Вы должны позаботиться о дубликатах, потому что вы можете добраться до 6 через 2 · 3 и 3 · 2. Набор может позаботиться об этом.
В приведенном ниже коде будут генерироваться все номера помех, которые вписываются в 32-битный беззнаковый int. Он заполняет набор, «распространяя» все номера хамминга. Затем он создает отсортированный вектор из набора, который вы можете использовать, чтобы найти номер Хэмминга в определенном индексе:
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
typedef unsigned int uint;
const uint umax = 0xffffffff;
void spread(std::set<uint> &hamming, uint n)
{
if (hamming.find(n) == hamming.end()) {
hamming.insert(n);
if (n < umax/2) spread(hamming, n * 2);
if (n < umax/3) spread(hamming, n * 3);
if (n < umax/5) spread(hamming, n * 5);
}
}
int main()
{
std::set<uint> hamming;
spread(hamming, 1);
std::vector<uint> ordered(hamming.begin(), hamming.end());
for (size_t i = 0; i < ordered.size(); i++) {
std::cout << i << ' ' << ordered[i] << '\n';
}
return 0;
}
Этот код работает быстрее, чем ваш линейный метод, даже если вы в конечном итоге создание более Хэмминг числа, чем вы необходимость.
Вам даже не нужен набор, если вы убедитесь, что не строите номер дважды. Каждый кривляется число может быть записано в виде h = 2^n2 + 3^n3 + 5^n5
, так что если вы нашли средство для перебирать эти уникально, вы сделали:
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
typedef unsigned int uint;
int main()
{
const uint umax = 0xffffffff;
std::vector<uint> hamming;
for (uint k = 1;; k *= 2) {
for (uint l = k;; l *= 3) {
for (uint m = l;; m *= 5) {
hamming.push_back(m);
if (m > umax/5) break;
}
if (l > umax/3) break;
}
if (k > umax/2) break;
}
std::sort(hamming.begin(), hamming.end());
for (size_t i = 0; i < hamming.size(); i++) {
std::cout << i << ' ' << hamming[i] << '\n';
}
return 0;
}
Странная break
синтаксис для петель требуется, потому что мы должны проверить размер перед переполнением. Если бы umax*5
не были переполнены, эти условия могли быть записаны в состоянии части цикла.
Примеры кода в ссылке, опубликованной Koshinae, используют аналогичные стратегии, но я удивлен, как долго некоторые из них.
Отметьте: http://rosettacode.org/wiki/Hamming_numbers – Koshinae
Также здесь: http://en.wikipedia.org/wiki/Regular_number – Koshinae
Вам нужно всего лишь сделать 1 деление, чтобы добраться до числа, которое вы уже сделали. Memoize. – stark