Это одно из мест, с помощью которого привязка данных, используемая во многих новых фреймворках JavaScript, будет очень полезна для вас ...
Итак, если вы используете Angular, React или любые другие фреймворки, которые делают два способа связывания данных, эта проблема просто исправлена для вас, поэтому простым языком ваш результат undefined
на первом этапе, поэтому вы получили result = undefined
до получения данных, а затем, как только вы получите результат , он будет обновляться и присваиваться новому значению, которое отвечает на ваш вызов Ajax ...
Но как вы можете сделать это в чистом javascript или jQuery, например, как вы задали этот вопрос?
Вы можете использовать обратный вызов, обещание и недавно наблюдаемое, чтобы обрабатывать его для вас, например, в обещаниях мы имеем некоторые функции, такие как success () или then (), которые будут выполняться, когда ваши данные будут готовы для вас, с функцией обратного вызова или подписки на наблюдаемые.
Например, в вашем случае, в котором вы используете jQuery, вы можете сделать что-то вроде этого:
$(document).ready(function(){
function foo() {
$.ajax({url: "api/data", success: function(data){
fooDone(data); //after we have data, we pass it to fooDone
}});
};
function fooDone(data) {
console.log(data); //fooDone has the data and console.log it
};
foo(); //call happens here
});
Для получения дополнительной информации n изучение обещаний и наблюдаемых, которые являются новыми способами для создания асинхронных материалов.
Алгоритм Кучи, вероятно, не является ответом на какой-либо разумный вопрос интервью. Существует гораздо более интуитивный алгоритм, который будет производить перестановки в лексикографическом порядке; хотя он амортизируется O (1) (за перестановку) вместо O (1), на практике он не заметно медленнее, и его намного легче вывести на лету.
Алгоритм лексикографического порядка чрезвычайно просто описать. Для некоторой перестановки найдите следующую:
Оба этапа (1) и (3) являются в худшем случае O (n), но нетрудно доказать, что среднее время для этих шагов равно O (1).
Индикация того, как сложный алгоритм Кучи (в деталях) заключается в том, что ваше выражение это немного неправильно, потому что он делает один дополнительный обмен; дополнительный swap - это no-op, если n четный, но создает проблему, когда n нечетно. См. https://en.wikipedia.org/wiki/Heap%27s_algorithm для правильного алгоритма (по крайней мере, это правильно сегодня) или см. Обсуждение в Генератор перестановок алгоритма Heap's
Чтобы увидеть, как работает алгоритм Хипа, вам нужно посмотреть, что представляет собой полная итерация цикла для вектора, как в четном, так и в нечетном случае. Для вектора четной длины полная итерация алгоритма Куба оставит вектор повернутым влево на одну позицию. Если вектор имеет нечетную длину, то в конце алгоритма вектор будет обратным. Вы можете доказать, что оба эти факта верны с использованием индукции, хотя это не дает никакой интуиции относительно того, почему это правда. Глядя на диаграмму на странице Википедии, может помочь.
Причина, по которой алгоритм Куба строит все перестановки, состоит в том, что он присоединяет каждый элемент к каждой перестановке остальных элементов. Когда вы выполняете алгоритм кучи, рекурсивные вызовы на входы с длинной длиной помещают элементы n, (n-1), 2, 3, 4, ..., (n-2), 1
в последнюю позицию, а рекурсивные вызовы на входах с нечетной длиной помещают элементы n, (n-3), (n-4), (n-5), ..., 2, (n-2), (n-1), 1
в последнюю позицию. Таким образом, в любом случае все элементы связаны со всеми перестановками элементов n - 1
.
Если вы хотите более подробное графическое объяснение, посмотрите эту статью .
Я нашел статью, которая пытается объяснить это здесь: Почему алгоритм Хипа работает?
Однако, я думаю, что это трудно понять, поэтому придумал объяснение, которое, мы надеемся, будет легче понять:
Пожалуйста, просто предположите, что эти утверждения верны на мгновение (я покажу это позже):
(I), где n нечетно, оставляет элементы в том же порядке, когда они закончены.
(II), где n четно, вращает элементы в справа, например, ABCD становится DABC.
, когда
Наконец, давайте посмотрим, почему исходные утверждения верны:
(III) Эта серия свопов приводит к повороту вправо на одну позицию:
A[0] <-> A[n - 1]
A[1] <-> A[n - 1]
A[2] <-> A[n - 1]
...
A[n - 2] <-> A[n - 1]
Например, попробуйте с последовательностью ABCD :
A[0] <-> A[3]: DBCA
A[1] <-> A[3]: DACB
A[2] <-> A[3]: DABC
(IV) Эта серия шагов оставляет последовательность в том же порядке, что и раньше:
Repeat n times:
Rotate the sub-sequence a[0...(n-2)] to the right
Swap: a[0] <-> a[n - 1]
Интуитивно , это правда:
Если у вас есть последовательность длины 5, затем поверните ее 5 раз, она не изменится.
Принимая элемент в 0 перед вращением, тогда после поворота, заменяющего его новым элементом на 0, не изменяет результат (если он вращается n раз).
Теперь мы можем видеть, почему (I) и (II) истинны:
Если n равно 1: Тривиально, после вызова функции порядок не изменяется.
Если n равно 2: рекурсивные вызовы «сгенерируют (n - 1, A) «оставьте заказ ng без изменений (потому что он вызывает генерировать с первым аргументом, равным 1). Поэтому мы можем просто игнорировать эти призывы.
Если n равно 3: рекурсивные вызовы «generate (n - 1, A)» приводят к правому вращению, см. (III).
вращение. Таким образом, полные этапы этого вызова равны (IV) => Последовательность не изменяется.
Повторите для n = 4, 5, 6, ...
Я знаю, что этот вопрос требует языкового агностика, но Ruby во многих случаях читает лучше, чем псевдокод, и его легче запоминать, потому что он очень компактен:
def gen_perms (list, n=list.size - 1 )
return p list if n.zero?
for i in 0..n do
gen_perms list, n - 1
list[1], list[n] = list[n], list[1] if n.even?
list[i], list[n] = list[n], list[i] if n.odd?
end
end
list = ['a','b','c']
gen_perms list