Краткий ответ: вы не можете.
Чуть дольше отвечу:
Вам понадобится дополнительное место для хранения «возраста» вашей записи, что позволит вам различать идентичные приоритеты. И вам понадобится место для информации, которая позволит быстро вставлять и извлекать. Плюс ваша полезная нагрузка (значение и приоритет).Ω(n)Ω(n)
И для каждой полезной нагрузки, которую вы храните, вы сможете «скрыть» некоторую информацию в адресе (например, означает, что Y старше X). Но в этой «скрытой» информации вы либо скрыте «возраст», либо ИЛИ «быстрый поиск» информации. Не оба.addr(X)<addr(Y)
Очень длинный ответ с неточной ложной математикой:
Примечание: самый конец второй части отрывочен, как уже упоминалось. Если бы какой-нибудь математик мог предоставить лучшую версию, я был бы благодарен.
Давайте подумаем о количестве данных, которые задействованы на X-битной машине (скажем, 32- или 64-битной), с шириной записей (значение и приоритет) машинных слов.P
У вас есть набор потенциальных записей, которые частично упорядочены: и но вы не можете сравнить и .(a,1)<(a,2)(a,1)=(a,1)(a,1)(b,1)
Однако вы хотите иметь возможность сравнивать два несопоставимых значения из вашего набора записей на основе того, когда они были вставлены. Так что у вас есть здесь еще один набор значений: те , которые были вставлены, и вы хотите повысить его с помощью частичного порядка: тогда и только тогда был вставлен перед .X<YXY
В худшем случае ваша память будет заполнена записями в форме (с Разными для каждого), поэтому вам придется полностью полагаться на время вставки, чтобы решить, какой из них идет вышел первым.(?,1)?
- Время вставки (относительно других записей, все еще находящихся в структуре) требует битов информации (с полезной нагрузкой P-байтов и доступных байтов памяти).X−log2(P)2X
- Полезная нагрузка (значение и приоритет вашей записи) требует машинных слов информации.P
Это означает, что вы должны каким-то образом хранить дополнительные биты информации для каждой сохраняемой вами записи. И это для записей.X−log2(P)O(n)n
Теперь, сколько бит информации каждая ячейка памяти предоставляет нам?
- W бит данных ( - ширина слова машины).W
- X бит адреса.
Теперь предположим, что (полезная нагрузка имеет ширину хотя бы одного машинного слова (обычно один октет)). Это означает, что , поэтому мы можем разместить информацию о порядке вставки в адресе ячейки. Вот что происходит в стеке: ячейки с наименьшим адресом поступают в стек первыми (и выходят последними).P≥1X−log2(P)<X
Итак, для хранения всей нашей информации у нас есть две возможности:
- Сохраните порядок вставки в адресе, а данные - в памяти.
- Сохраните оба в памяти и оставьте адрес свободным для другого использования.
Очевидно, чтобы избежать потерь, мы будем использовать первое решение.
Теперь для операций. Я полагаю, вы хотите иметь:
- Insert(task,priority) с сложностью по времени.O(logn)
- StableExtractMin() с сложностью по времени.O(logn)
Давайте посмотрим на :StableExtractMin()
Действительно действительно общий алгоритм выглядит так:
- Найдите запись с минимальным приоритетом и минимальным «временем вставки» в .O(logn)
- Удалите его из структуры в .O(logn)
- Верни это.
Например, в случае с кучей, она будет немного по-другому организована, но работа такая же: 1. Найдите минимальную запись в
2. Удалите ее из структуры в
3. Исправьте все так, чтобы в следующий раз # 1 и # 2 все еще были то есть "восстановить кучу". Это нужно сделать в «O (log n)» 4. Вернуть элемент.0(1)O(1)O(1)
Возвращаясь к общему алгоритму, мы видим, что, чтобы найти запись за , нам нужен быстрый способ выбрать правильный из кандидатов (в худшем случае, память полный).O(logn)2(X−log2(P))
Это означает, что нам нужно хранить битов информации для извлечения этого элемента (каждый бит делит пополам пространство-кандидат, поэтому у нас есть делений, что означает сложность времени).X−log2(P)O(logn)O(logn)
Эти биты информации могут быть сохранены как адрес элемента (в куче, минимальное значение находится на фиксированном адресе), или, например, с указателями (в двоичном дереве поиска (с указателями)), вы должны следовать в среднем чтобы добраться до мин).O(logn)
Теперь, при удалении этого элемента, нам нужно увеличить следующую запись min, чтобы в ней было правильное количество информации, чтобы в следующий раз разрешить поиск , то есть, так как у него есть битов информация, отличающая его от других кандидатов.O(logn)X−log2(P)
То есть, если у вас недостаточно информации, вам нужно добавить ее. В (несбалансированном) бинарном дереве поиска информация уже есть: вам придется поместить NULL-указатель куда-нибудь, чтобы удалить элемент, и без каких-либо дальнейших операций BST будет доступен для поиска за времени на средний.O(logn)
После этого, это немного отрывочно, я не уверен, как это сформулировать. Но у меня есть сильное чувство, что каждый из оставшихся элементов в вашем наборе должен будет иметь биты информации, которые помогут найти следующую минуту и дополнить ее достаточным количеством информации, чтобы ее можно было найти в время в следующий раз.O ( l o g n )X−log2(P)O(logn)
Алгоритм вставки, как правило, просто нуждается в обновлении части этой информации, я не думаю, что его быстродействие будет стоить дороже (с точки зрения памяти).
Теперь это означает, что нам нужно хранить больше битов информации для каждого элемента. Итак, для каждого элемента имеем:X−log2(P)
- Время вставки, бит.X−log2(P)
- Полезная нагрузка машинных слов.P
- Информация «быстрого поиска», бит.X−log2(P)
Поскольку мы уже используем содержимое памяти для хранения полезной нагрузки и адрес для хранения времени вставки, у нас не осталось места для хранения информации «быстрого поиска». Таким образом, нам придется выделить дополнительное пространство для каждого элемента, и таким образом «тратить» дополнительное пространство.Ω(n)