Распечатайте список уникальных элементов в порядке их частоты появления

Допустим, у нас есть массив целых чисел или даже непрерывный поток целых чисел. Идея состоит в том, чтобы печатать уникальные элементы в порядке убывания частоты появления. Например, для 7, 4, 2, 4, 9, 6, 5, 6, 2, 0, 2, 1 мы должны получить: 2, 4, 6, 7, 9, 5, 0, 1, поскольку 2 появляется три раз, 4 и 6 два раза, а остальные только один раз.

Есть ли лучший и эффективный подход, чем (sorting map based by value) подсчет вхождений элементов, сохранение их на карте, а затем сортировка карты на основе значения?


person whiteErru    schedule 23.03.2017    source источник
comment
какой язык программирования?   -  person RomanPerekhrest    schedule 23.03.2017
comment
Предположим, что это Java, однако это скорее поиск эффективного алгоритма, чем использование мощности языка программирования и библиотек, поскольку в конце концов языки программирования используют интеллектуальные алгоритмы.   -  person whiteErru    schedule 23.03.2017
comment
очевидным выбором будет отсортированная карта, как вы уже упоминали, но, возможно, также стоит изучить использование полноценной СУБД и использовать возможности индексации базы данных, в зависимости от размера ваших данных, которые также должны работать для потоковой передачи список значений, и вам не нужно беспокоиться о проблемах с нехваткой памяти с картами памяти и т. д.   -  person xander    schedule 23.03.2017


Ответы (3)


Однако, мне кажется, для этого должен быть гораздо более эффективный алгоритм, так как, вероятно, есть способ сортировки частот на лету.

Эта проблема на самом деле Omega(nlogn) в модели алгебраического дерева (в этой модели хеширование не разрешено), с сокращением от Проблема отличительности элементов, поэтому, если вы надеетесь получить одну (или постоянное количество) итераций для ее решения без какой-либо вспомогательной структуры данных под капотом для ее решения - это невозможно, так как это позволит нам решить отчетливость элементов за O(n) в модели алгебраического дерева.

Канонические решения для этих типов задач:

  1. (Ваше предложение): Создайте карту, удалите дубликаты и отсортируйте по частоте
  2. Аналогичен 1, но вместо карты — сортировать элементы, а найти количество повторений каждого элемента легко с помощью бинарного поиска.
person amit    schedule 23.03.2017

Если вы используете Python, используйте класс collections.Counter и его счетчик. метод most_common()

from collections import Counter
counted = Counter([7, 4, 2, 4, 9, 6, 5, 6, 2, 0, 2, 1])
ordered = [value for value, count in counted.most_common()]
print(ordered)  # [2, 4, 6, 0, 1, 5, 7, 9]

Доступен источник, показывающий, что heapq используется в наиболее общий()

person Paddy3118    schedule 23.03.2017

Сосредоточив внимание на требовании в вопросе возможного принятия ввода в виде потока целых чисел, одним из решений будет модифицированная сортировка вставками...

Создайте список (здесь именуемый countlist) списков, изначально пустых. Каждый раз, когда вы принимаете новое значение, итерируйте по убыванию каждый список в countlist, ища значение. Если вы найдете значение в countlist[i], удалите значение из текущего списка и вставьте его в countlist[i+1], при необходимости добавив новый список в countlist. Если вы так и не найдете значение, вставьте его в countlist[1].

Цель итерации по убыванию вместо возрастания состоит в том, что это позволяет вам поддерживать указатель на то место, куда значение будет вставлено в countlist[i], если вы найдете его в countlist[i-1]. Если вам не нужна подсортировка по значениям с одинаковым счетчиком, вы можете пропустить этот указатель и выполнить итерацию по возрастанию.

Я считаю, что этот алгоритм в целом O(n2). Обработка каждого нового значения — O(n), а результаты сортируются по ходу. В любой момент вы можете напечатать правильный порядок (на данный момент), итерируя по убыванию через countlist и печатая каждый список.

Пример запуска, используя пример в вопросе...

input: 7, 4, 2, 4, 9, 6, 5, 6, 2, 0, 2, 1

After accepting 7:
countlist[1] = 7

After accepting 4:
countlist[1] = 4, 7

After accepting 2:
countlist[1] = 2, 4, 7

After accepting 4:
countlist[1] = 2, 7
countlist[2] = 4

After accepting 9:
countlist[1] = 2, 7, 9
countlist[2] = 4

After accepting 6:
countlist[1] = 2, 6, 7, 9
countlist[2] = 4

After accepting 5:
countlist[1] = 2, 5, 6, 7, 9
countlist[2] = 4

After accepting 6:
countlist[1] = 2, 5, 7, 9
countlist[2] = 4, 6

After accepting 2:
countlist[1] = 5, 7, 9
countlist[2] = 2, 4, 6

After accepting 0:
countlist[1] = 0, 5, 7, 9
countlist[2] = 2, 4, 6

After accepting 2:
countlist[1] = 0, 5, 7, 9
countlist[2] = 4, 6
countlist[3] = 2

After accepting 1:
countlist[1] = 0, 1, 5, 7, 9
countlist[2] = 4, 6
countlist[3] = 2
person James Droscha    schedule 23.03.2017
comment
Интересный подход, но я считаю, что сортировка карты по значению будет O (nlogn), что лучше, чем O (n ^ 2). - person whiteErru; 23.03.2017
comment
Согласованный. Я сосредоточился на случае (упомянутом в вопросе), когда вход представляет собой поток целых чисел. Итак, я построил алгоритм, чтобы не требовалось знать, сколько значений мы получим, и не требовалось повторной сортировки после принятия каждого ввода. - person James Droscha; 23.03.2017