Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 157 additions & 0 deletions src/kr_2/kr_2_queue.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
class BinomialNode:
"""Узел биномиального дерева"""
def __init__(self, key, value=None):
self.key = key # приоритет (меньше = выше приоритет)
self.value = value # данные, хранимые в узле
self.degree = 0 # степень узла(количество детей)
self.parent = None # родительский узел
self.child = None # указатель на крайнего левого ребенка
self.sibling = None # указатель на правого брата

class BinomialHeap:
"""Биномиальная куча (очередь с приоритетами)"""
def __init__(self):
self.head = None # голова списка корней

def is_empty(self):
"""Проверка на пустоту"""
return self.head is None


def insert(self, key, value=None):
"""Вставка элемента в кучу"""
# создаем новую кучу из одного элемента
node = BinomialNode(key, value)
new_heap = BinomialHeap()
new_heap.head = node

# сливаем с текущей кучей
self._union(new_heap)

def get_minimum(self):
"""Поиск минимального элемента"""
if self.head is None:
return None

min_node = self.head
current = self.head.sibling

while current:
if current.key < min_node.key:
min_node = current
current = current.sibling

return min_node

def _union(self, other_heap):
"""Слияние двух биномиальных куч"""
merged_head = self._merge_root_lists(self.head, other_heap.head)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_merge_root_lists ничего не возвращает, а значит дальнейшее выполнение функции неверно


if merged_head is None:
self.head = None
return

prev = None
x = merged_head
next_node = x.sibling

while next_node:
# степени разные или три дерева подряд одинаковой степени
if x.degree != next_node.degree or (next_node.sibling == x.degree and next_node.sibling.degree == x.degree):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

next_node.sibling -- это объект, x.degree -- это число, их сравнение всегда будет False. Нужно было проверять что next_node.sibling это не None.

prev = x
x = next_node
else:
if x.key <= next_node.key:
x.sibling = next_node.sibling
self._link_trees(next_node, x)
else:
if prev is None:
merged_head = next_node
else:
prev.sibling = next_node
self._link_trees(x, next_node)
x = next_node

next_node = x.sibling
self.head = merged_head

def _merge_root_lists(self, head_1, head_2):
"""Слияние двух списков корней в один отсортированный по степени"""
temp = BinomialNode(0)
tail = temp

while head_1 and head_2:
if head_1.degree <= head_2.degree:
tail.sibling = head_1
head_1 = head_1.sibling
else:
tail.sibling = head_2
head_2 = head_2.sibling
tail = tail.sibling

if head_1:
tail.sibling = head_1
else:
tail.sibling = head_2

def _link_trees(self, child, parent):
"""Связывание двух деревьев одинаковой степени"""
child.parent = parent
child.sibling = parent.child
parent.child = child
parent.degree += 1

def extract_min(self):
"""Извлечение узла с минимальным значением ключа"""
if self.head is None:
return None

min_node = self.head
min_prev = None
prev = None
current = self.head

while current:
if current.key < min_node.key:
min_node = current
min_prev = prev
prev = current
current = current.sibling

if min_prev is None:
self.head = min_node.sibling
else:
min_prev.sibling = min_node.sibling

child_head = None
child = min_node.child
while child:
next_child = child.sibling
child.sibling = child_head
child.parent = None
child_head = child
child = next_child

child_heap = BinomialHeap()
child_heap.head = child_head
self._union(child_heap)
return min_node


def decrease(self, node, value):
"""Уменьшает ключ элемента, присваивая новое значение"""
if value > node.key:
return
node.key = value
parent = node.parent
while parent and node.key < parent.key:
node.key, parent.key = parent.key, node.key
node.value, parent.value = parent.value, node.value

node = parent
parent = node.parent

def delete(self, node):
"""Удаление ключа"""
decrease(self, node, -10**9)

Check failure on line 156 in src/kr_2/kr_2_queue.py

View workflow job for this annotation

GitHub Actions / Ruff Check

Ruff (F821)

src/kr_2/kr_2_queue.py:156:9: F821 Undefined name `decrease`

Check failure on line 156 in src/kr_2/kr_2_queue.py

View workflow job for this annotation

GitHub Actions / Ruff Check

Ruff (F821)

src/kr_2/kr_2_queue.py:156:9: F821 Undefined name `decrease`
extract_min(self)

Check failure on line 157 in src/kr_2/kr_2_queue.py

View workflow job for this annotation

GitHub Actions / Ruff Check

Ruff (F821)

src/kr_2/kr_2_queue.py:157:9: F821 Undefined name `extract_min`

Check failure on line 157 in src/kr_2/kr_2_queue.py

View workflow job for this annotation

GitHub Actions / Ruff Check

Ruff (F821)

src/kr_2/kr_2_queue.py:157:9: F821 Undefined name `extract_min`
Comment on lines +156 to +157
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

def delete(self, node):
        self.decrease(node, -float('inf'))
        self.extract_min()

Comment on lines +141 to +157
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Эти методы ожидают объект node, но ни один публичный метод не возвращает его, мы просто не сможем никак вызвать heap.decrease() или heap.delete().

47 changes: 47 additions & 0 deletions src/kr_2/kr_2_queue_tests.py
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ruff ругается

Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""
Запуск: pytest kr_2_queue_tests.py -v
"""
from kr_2_queue import BinomialHeap

class TestBasicOperations:
"""Проверка базовых операций вставки, поиска и извлечения минимума"""
def test_empty_heap(self):
"""Проверка пустой кучи"""
heap = BinomialHeap()
assert heap.is_empty() == True

Check failure on line 11 in src/kr_2/kr_2_queue_tests.py

View workflow job for this annotation

GitHub Actions / Ruff Check

Ruff (E712)

src/kr_2/kr_2_queue_tests.py:11:16: E712 Avoid equality comparisons to `True`; use `heap.is_empty():` for truth checks

Check failure on line 11 in src/kr_2/kr_2_queue_tests.py

View workflow job for this annotation

GitHub Actions / Ruff Check

Ruff (E712)

src/kr_2/kr_2_queue_tests.py:11:16: E712 Avoid equality comparisons to `True`; use `heap.is_empty():` for truth checks
assert heap.get_minimum() is None
assert heap.extract_min() is None

def test_single_insert(self):
"""Вставка одного элемента"""
heap = BinomialHeap()
heap.insert(10, "A")

assert heap.is_empty() == False

Check failure on line 20 in src/kr_2/kr_2_queue_tests.py

View workflow job for this annotation

GitHub Actions / Ruff Check

Ruff (E712)

src/kr_2/kr_2_queue_tests.py:20:16: E712 Avoid equality comparisons to `False`; use `not heap.is_empty():` for false checks

Check failure on line 20 in src/kr_2/kr_2_queue_tests.py

View workflow job for this annotation

GitHub Actions / Ruff Check

Ruff (E712)

src/kr_2/kr_2_queue_tests.py:20:16: E712 Avoid equality comparisons to `False`; use `not heap.is_empty():` for false checks
min_node = heap.get_minimum()
assert min_node.key == 10
assert min_node.value == "A"

def test_multiple_inserts(self):
"""Вставка нескольких элементов"""
heap = BinomialHeap()
heap.insert(10, "A")
heap.insert(5, "B")
heap.insert(20, "C")
heap.insert(3, "D")
heap.insert(7, "E")

# проверка поиска минимума
min_node = heap.get_minimum()
assert min_node.key == 3
assert min_node.value == "D"

# проверка извлечения минимума
extracted = heap.extract_min()
assert extracted.key == 3
assert extracted.value == "D"

# проверка нового минимума
min_node = heap.get_minimum()
assert min_node.key == 5
assert min_node.value == "B"
Loading