Структура данных для телефонной книги, которая может искать номер по имени, а также искать имя по номеру - PullRequest
7 голосов
/ 01 апреля 2012

Знаете ли вы решение следующего вопроса для интервью?

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


Подробности:

Решения, найденные в stackoverflow, основаны на хеш-таблицах, но для этого мне потребуется создать 2 хеш-таблицы, для которых требуется вдвое больше места.

Как сделать это только с одной структурой данных с экономией времени и пространства и безопасностью типов?

Ответы [ 5 ]

16 голосов
/ 02 апреля 2012

Такие структуры данных известны как многоиндексные контейнеры .Они не очень распространены в большинстве языков программирования, потому что интерфейс может быть довольно сложным.Существуют реализации в Java , C # и - что наиболее заметно - в C ++ с библиотекой Boost, см. Документацию Boost.MultiIndex , в частности пример 4 о двунаправленные карты :

Двунаправленная карта - это контейнер пар (const FromType, const ToType), в котором не существует двух элементов с одним и тем же первым или вторым компонентом (std :: map гарантирует только уникальность первого компонента).Быстрый поиск предусмотрен для обоих ключей.В программе имеется небольшой испано-английский словарь с онлайн-запросом слов на обоих языках.

Основная идея многоиндексных контейнеров заключается в том, что многие контейнеры хранят свои элементыв узлах, которые содержат указатели / ссылки на другие узлы (например, двойные связанные списки).Вместо того чтобы хранить только указатели / ссылки для одного контейнера, узел содержит ссылки для нескольких структур индекса.Это работает по крайней мере со связанными списками, отсортированными деревьями и уникальными хеш-индексами.И реализация очень эффективна, потому что для каждого элемента требуется только одно выделение памяти.

4 голосов
/ 11 апреля 2012

Хорошо .. Я согласен с мультииндексом, и это правильный способ сделать это.Тем не менее, для собеседования на работу, они, вероятно, хотят, чтобы вы подумали об этом и что-то объяснили, а не просто использовали повышение.Если они спрашивают о внутренностях повышения, это может быть неудобно, если вы не можете объяснить это должным образом.

Итак, вот возможное решение.

Прежде всего, не используйте для этого хеш-таблицу.Телефоны и имена могут быть легко отсортированы, и вам, вероятно, следует использовать сбалансированное дерево поиска или три, если вы хотите интерактивный поиск (http://en.wikipedia.org/wiki/Trie). ИМХО, в этом случае хеш-таблица - это большая трата пространства.

Пустьмы предполагаем, что имена уникальны, а числа уникальны. Затем вы можете сделать:

1- Структура данных для хранения ваших данных

struct Phone {
 // implement the phone here whatever they need
 // assume that whatever representation used can be converted into a unique id (number)
}; //
struct PhoneBookEntry {
   std::string name;
   Phone number;
}; 

2- Создать два дерева одно для имени иодин для телефона

BalancedSearchTree<PhoneBookEntry> tree_by_name;
BalancedSearchTree<PhoneBookEntry> tree_by_number; 

3 Вот и все. Найдите в каждом дереве все, что вам нужно

bool PhoneBook::getByName(const std::string &name, PhoneBookEntry &o) {
  tree_by_name.get(name, o);
  return !o.empty();
}
bool PhoneBook::getByNumber(const Phone &p, PhoneBookEntry &o) {
 tree_by_number.get(p, o);
 return !o.empty();
}

Удачи

3 голосов
/ 01 апреля 2012

Хеш все (то есть в обоих направлениях) в один и тот же стол.

1 голос
/ 02 апреля 2012

Разве это не легко?

Использование массива записи / структуры / кортежа пары значений (номер телефона, имя).

  1. Выполнить линейный поиск в поисках ключа поиска;O (n / 2) для совпадения, O (n) для пропуска,

  2. верните запись / структуру / кортеж и сделайте все, что нужно.

Редактировать:Этот алгоритм может быть улучшен многими способами.

Я думаю, что этот вопрос интервью может быть намеренно недооценен, чтобы выяснить, как реагирует собеседник.(Это то, что я делаю, когда я беру интервью).Поэтому, возможно, более важно относиться к нему как к такому, а не предполагать, что это всего лишь вопрос информатики.

Думаю, стоит поговорить с интервьюером.Например:

  1. Важно ли, чтобы это было достаточно быстро для персонального телефонного справочника, например, на мобильном телефоне (маловероятно, что любой разумный алгоритм будет слишком медленным), или для приложения инфраструктуры телекоммуникации странового размерагде могут быть доступность, одновременное обновление и дополнительные требования, например, контроль доступа к некоторому подмножеству имен и номеров?
  2. Какова целевая технология?Возможно, вы захотите выбрать разные подходы, например, для Python, C ++, ассемблера, ...
  3. Являются ли их качества, которые нужно продемонстрировать, эффективнее времени и пространства?Например, должно ли быть легко доказать правильность или проверить?Стоит ли экономить ресурсы процессора за счет быстрого подхода, затрачивая человеческое время на тестирование?
  4. Насколько квалифицированными или знающими могут быть люди, поддерживающие и повторно использующие код?Будут ли предпочтительны простые подходы на основании стоимости обслуживания.

и т. Д.

Я думаю, что более важно взаимодействовать с интервьюером, а не фокусироваться только на техническом решении.Когда я беру интервью, я ищу человека, который на самом деле пытается понять всю проблему, а не (обычно небольшую) часть, которую легко определить.

0 голосов
/ 30 ноября 2013

Вы можете использовать 36-разрядное дерево (26 для алфавитов и 10 для цифр) и иметь ссылки, указывающие как на алфавит, так и на цифру на один и тот же узел.(Строго говоря, это не будет «деревом», но вы поняли).Таким образом, вы не будете получать постоянный поиск по времени, но вам не придется повторять данные, и поиск все равно будет довольно быстрым.

Конечно, вам придется обрабатывать коллизии, но вам придетсяприходится обрабатывать их при использовании хеш-таблиц тоже.Возможно, вы можете использовать два указателя, чтобы указать на следующий сталкивающийся узел по имени и номеру.

...