#javascript #arrays #sorting #set
#javascript #массивы #сортировка #установить
Вопрос:
Мне нужно добавить элемент в массив, только если его еще нет в Javascript. По сути, я рассматриваю массив как набор.
Мне нужно, чтобы данные хранились в массиве, иначе я бы просто использовал объект, который можно использовать как набор.
Я написал следующий прототип массива и хотел услышать, знает ли кто-нибудь лучший способ. Это O (n) вставка. Я надеялся выполнить O (ln (n)) insert, однако я не видел простого способа вставить элемент в отсортированный массив. Для моих приложений длина массива будет очень маленькой, но я бы все же предпочел что-то, что подчинялось принятым правилам для хорошей эффективности алгоритма:
Array.prototype.push_if_not_duplicate = function(new_element){
for( var i=0; i<this.length; i ){
// Don't add if element is already found
if( this[i] == new_element ){
return this.length;
}
}
// add new element
return this.push(new_element);
}
Комментарии:
1. Вы говорите, что это отсортированный массив, но я не понимаю, как ваш алгоритм обеспечивает какой-либо порядок. Я что-то упустил?
2. Эй, Расти, сортировка не применяется для этого массива, потому что алгоритм проверяет все элементы в массиве перед вставкой. Чтобы вставить уникальный элемент в O(ln (n)), массив должен быть уже отсортирован.
Ответ №1:
Если я правильно понимаю, у вас уже есть отсортированный массив (если у вас нет отсортированного массива, вы можете использовать метод Array.sort для сортировки ваших данных), и теперь вы хотите добавить к нему элемент, если он еще не присутствует в массиве. Я извлек метод двоичной вставки (который использует двоичный поиск) в библиотеке закрытия Google. Сам соответствующий код будет выглядеть примерно так, и это операция O (log n), потому что двоичный поиск равен O (log n) .
function binaryInsert(array, value) {
var index = binarySearch(array, value);
if (index < 0) {
array.splice(-(index 1), 0, value);
return true;
}
return false;
};
function binarySearch(arr, value) {
var left = 0; // inclusive
var right = arr.length; // exclusive
var found;
while (left < right) {
var middle = (left right) >> 1;
var compareResult = value > arr[middle] ? 1 : value < arr[middle] ? -1 : 0;
if (compareResult > 0) {
left = middle 1;
} else {
right = middle;
// We are looking for the lowest index so we can't return immediately.
found = !compareResu<
}
}
// left is the index if found, or the insertion point otherwise.
// ~left is a shorthand for -left - 1.
return found ? left : ~left;
};
Используется binaryInsert(массив, значение). Это также поддерживает сортировку массива.
Ответ №2:
Удалил мой другой ответ, потому что я пропустил тот факт, что массив отсортирован.
Алгоритм, который вы написали, проходит через каждый элемент в массиве и, если совпадений нет, добавляет новый элемент в конце. Я предполагаю, что это означает, что после вы выполняете другую сортировку.
Весь алгоритм можно улучшить, используя алгоритм «разделяй и властвуй». Выберите элемент в середине массива, сравните с новым элементом и продолжайте, пока не найдете место для вставки. Это будет немного быстрее, чем ваш приведенный выше алгоритм, и впоследствии не потребует сортировки.
Если вам нужна помощь в разработке алгоритма, не стесняйтесь спрашивать.
Ответ №3:
Раньше я создавал (простой и неполный) Set
тип, подобный этому:
var Set = function (hashCodeGenerator) {
this.hashCode = hashCodeGenerator;
this.set = {};
this.elements = [];
};
Set.prototype = {
add: function (element) {
var hashCode = this.hashCode(element);
if (this.set[hashCode]) return false;
this.set[hashCode] = true;
this.elements.push(element);
return true;
},
get: function (element) {
var hashCode = this.hashCode(element);
return this.set[hashCode];
},
getElements: function () { return this.elements; }
};
Вам просто нужно найти хорошую hashCodeGenerator
функцию для ваших объектов. Если ваши объекты являются примитивами, эта функция может вернуть сам объект. Затем вы можете получить доступ к элементам набора в форме массива из средства getElements
доступа. Вставки равны O (1). Требования к пространству — O (2n).
Ответ №4:
Если ваш массив представляет собой двоичное дерево, вы можете вставить в O(log n), поместив новый элемент в конец и вставив его на место. Для проверки дубликатов также потребуется O (log n).
Комментарии:
1. Спасибо за ваш ответ, написание моего собственного алгоритма пузырьков — это определенно не то, на что я хочу потратить время.
2. Алгоритм действительно не так уж плох. Обычно, чем ближе вы подходите к эффективному алгоритму, тем дальше вы отходите от очевидного, простого в программировании алгоритма. Например, посмотрите на кучу Фибоначчи по сравнению с двоичной кучей. Двоичную кучу легче кодировать и понимать, но куча Фибоначчи имеет некоторые преимущества, которые вы никогда не получите от более простого решения.
3. Это не значит, что проще никогда не бывает лучше. Просто эффективность обычно более сложна с математической точки зрения.
4. Эй, Расти, прошу прощения, если я ошибаюсь, но я предполагаю, что ты либо учишься в школе, либо недавно закончил. Одной вещи, которой вас не учат в колледже, является то, что в производственной среде обычно очень плохая идея внедрять алгоритмы с нуля. Для этого есть две очень веские причины: 1) ВРЕМЯ — вы можете сделать гораздо больше за свое время, если будете использовать ранее существующий код. 2) ОШИБКИ — написание алгоритмов с нуля сопряжено с риском наличия в нем ошибок. Использование проверенного и надежного кода сводит к минимуму этот риск.
5. Ха, я надеюсь, вы не поняли неправильно и не подумали, что я бы посоветовал кому-нибудь реализовать свою собственную кучу Фибоначчи. Это, как вы говорите, пустая трата времени.