Merge pull request '[1] data_structures' (#186) from pomelovsd/2026-rff_mp:data_structures into develop
Reviewed-on: #186
This commit is contained in:
commit
ec1d4f155d
58
pomelovsd/DataStruct/BinaryTree.py
Normal file
58
pomelovsd/DataStruct/BinaryTree.py
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
def create_node(name, phone):
|
||||
return {"name": name, "phone": phone, "left": None, "right": None}
|
||||
|
||||
def bst_insert(root, name, phone):
|
||||
if root is None:
|
||||
return create_node(name, phone)
|
||||
if name < root["name"]:
|
||||
root["left"] = bst_insert(root["left"], name, phone)
|
||||
elif name > root["name"]:
|
||||
root["right"] = bst_insert(root["right"], name, phone)
|
||||
else:
|
||||
root["phone"] = phone
|
||||
return root
|
||||
|
||||
def bst_insert_sort(sorted_data, left, right):
|
||||
if left > right:
|
||||
return None
|
||||
mid = (left + right) // 2
|
||||
name, phone = sorted_data[mid]
|
||||
root = create_node(name, phone)
|
||||
root["left"] = bst_insert_sort(sorted_data, left, mid - 1)
|
||||
root["right"] = bst_insert_sort(sorted_data, mid + 1, right)
|
||||
return root
|
||||
|
||||
def bst_find(root, name):
|
||||
if root is None:
|
||||
return None
|
||||
if name == root["name"]:
|
||||
return root["phone"]
|
||||
if name < root["name"]:
|
||||
return bst_find(root["left"], name)
|
||||
return bst_find(root["right"], name)
|
||||
|
||||
def bst_delete(root, name):
|
||||
if root is None:
|
||||
return None
|
||||
if name < root["name"]:
|
||||
root["left"] = bst_delete(root["left"], name)
|
||||
elif name > root["name"]:
|
||||
root["right"] = bst_delete(root["right"], name)
|
||||
else:
|
||||
# Нет детей или только один ребенок
|
||||
if root["left"] is None:
|
||||
return root["right"]
|
||||
if root["right"] is None:
|
||||
return root["left"]
|
||||
|
||||
# Два ребенка
|
||||
current = root["right"]
|
||||
while current["left"] is not None:
|
||||
current = current["left"]
|
||||
|
||||
root["name"] = current["name"]
|
||||
root["phone"] = current["phone"]
|
||||
# Удаляем преемника
|
||||
root["right"] = bst_delete(root["right"], current["name"])
|
||||
|
||||
return root
|
||||
30
pomelovsd/DataStruct/HashTable.py
Normal file
30
pomelovsd/DataStruct/HashTable.py
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
from LinkedList import ll_insert, ll_find, ll_delete, ll_list_all
|
||||
|
||||
def create_ht(size = 1000):
|
||||
return[None] * size
|
||||
|
||||
def hash_function(name, size = 1000):
|
||||
value = 0
|
||||
for char in name:
|
||||
value = (value * 31 + ord(char)) % size
|
||||
return value
|
||||
|
||||
def ht_insert(buckets, name, phone):
|
||||
index = hash_function(name, len(buckets))
|
||||
buckets[index] = ll_insert(buckets[index], name, phone)
|
||||
return buckets
|
||||
|
||||
def ht_delete(buckets, name):
|
||||
index = hash_function(name, len(buckets))
|
||||
buckets[index] = ll_delete(buckets[index], name)
|
||||
return buckets
|
||||
|
||||
def ht_find(buckets, name):
|
||||
index = hash_function(name, len(buckets))
|
||||
return ll_find(buckets[index], name)
|
||||
|
||||
def ht_list_all(buckets):
|
||||
records = []
|
||||
for bucket in buckets:
|
||||
if buckets is not None:
|
||||
records.extend(ll_list_all(buckets))
|
||||
60
pomelovsd/DataStruct/LinkedList.py
Normal file
60
pomelovsd/DataStruct/LinkedList.py
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# Создание узла
|
||||
def create_node(name, phone):
|
||||
return {"name": name, "phone": phone, "next": None}
|
||||
|
||||
def ll_insert(head, name, phone):
|
||||
node = create_node(name, phone)
|
||||
|
||||
# Случай для пустого списка
|
||||
if head is None:
|
||||
return node
|
||||
|
||||
# Случай если надо перезаписать имя
|
||||
current = head
|
||||
while current:
|
||||
if current["name"] == name:
|
||||
current["phone"] = phone
|
||||
return head
|
||||
current = current["next"]
|
||||
|
||||
# Случай добавления нового элемента
|
||||
current = head
|
||||
while current["next"]:
|
||||
current = current["next"]
|
||||
current["next"] = node
|
||||
return head
|
||||
|
||||
def ll_find(head, name):
|
||||
current = head
|
||||
while current:
|
||||
if current["name"] == name:
|
||||
return current["phone"]
|
||||
current = current["next"]
|
||||
return "Нет данных"
|
||||
|
||||
def ll_delete(head, name):
|
||||
# Случай для пустого списка
|
||||
if head is None:
|
||||
return None
|
||||
|
||||
# Удаление головы
|
||||
if head["name"] == name:
|
||||
return head["next"]
|
||||
|
||||
# Случай для поиска элемента
|
||||
current = head
|
||||
while current["next"]:
|
||||
if current["next"]["name"] == name:
|
||||
current['next'] = current["next"]["next"]
|
||||
return head
|
||||
current = current['next']
|
||||
return head
|
||||
|
||||
def ll_list_all(head):
|
||||
records = []
|
||||
current = head
|
||||
while current:
|
||||
records.append((current["name"],current["phone"]))
|
||||
current = current["next"]
|
||||
records.sort(key=lambda x: x[0]) # Сортировка элементов по алфавиту
|
||||
return records
|
||||
BIN
pomelovsd/DataStruct/analysis.png
Normal file
BIN
pomelovsd/DataStruct/analysis.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 228 KiB |
BIN
pomelovsd/DataStruct/analysis_midle.png
Normal file
BIN
pomelovsd/DataStruct/analysis_midle.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 135 KiB |
844
pomelovsd/DataStruct/data_structures.ipynb
Normal file
844
pomelovsd/DataStruct/data_structures.ipynb
Normal file
File diff suppressed because one or more lines are too long
19
pomelovsd/DataStruct/results.csv
Normal file
19
pomelovsd/DataStruct/results.csv
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
Структура,Режим,Операция,Время (сек)
|
||||
LinkedList,случайный,вставка,7.90476148960006
|
||||
LinkedList,сортированный,вставка,5.470369223799935
|
||||
LinkedList,случайный,поиск,0.043889598400346584
|
||||
LinkedList,сортированный,поиск,0.04527814500015666
|
||||
LinkedList,случайный,удаление,0.03798479180004506
|
||||
LinkedList,сортированный,удаление,0.020613410200166982
|
||||
HashTable,случайный,вставка,0.06718570920002094
|
||||
HashTable,сортированный,вставка,0.015257699599897024
|
||||
HashTable,случайный,поиск,0.00032641679972584826
|
||||
HashTable,сортированный,поиск,0.0003182652002578834
|
||||
HashTable,случайный,удаление,0.00020438940009626094
|
||||
HashTable,сортированный,удаление,0.00020722279987239745
|
||||
BinaryTree,случайный,вставка,0.025759428999845114
|
||||
BinaryTree,сортированный,вставка,0.00637738920013362
|
||||
BinaryTree,случайный,поиск,0.00039911679978104074
|
||||
BinaryTree,сортированный,поиск,0.00043057159964519085
|
||||
BinaryTree,случайный,удаление,0.00042884459980996326
|
||||
BinaryTree,сортированный,удаление,0.0005684383997504483
|
||||
|
41
pomelovsd/DataStruct/results.md
Normal file
41
pomelovsd/DataStruct/results.md
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# Предложенные вопросы:
|
||||
## Сравните:
|
||||
1) Как порядок входных данных влияет на скорость вставки в BST(деградация до O(n) на отсортированных данных).
|
||||
2) Почему хеш-таблица почти не чувствительна к порядку.
|
||||
3) Почему связный список всегда медленен при поиске.
|
||||
4) Как удаление работает в каждой структуре.
|
||||
5) Вывод должен содержать ответ на вопрос: какую структуру и для каких задач (частые вставки, частый поиск, необходимость получать данные в порядке) стоит выбирать в реальной жизни.*
|
||||
# Анализ результатов:
|
||||
![[analysis.png]]
|
||||
![[analysis_midle.png]]
|
||||
>График созданный для на основе замеров времени работы разных типов данных
|
||||
>P.s. Данные на графиках не точные, а приблизительные, из-за во многом случайных замеров значений
|
||||
## Выводы:
|
||||
### 1) **Как порядок входных данных влияет на скорость вставки в BST?**
|
||||
Порядок отличается очень сильно, если в обычном случае сложность равна $O(log(n))$, а в худшем случае(как раз в случае отсортированных данных) равна $O(n)$.
|
||||
>В моём случае время работы мало отличимо так как, во время замеров, я заметил, что данные записываются крайне долго за счёт особенностей реализации(бинарное дерево вырождалось в связный список) и пришлось добавить ещё одну функцию, которая будет искусственно разбивать отсортированный массив на 2 ветки, а не записывать все ветви подряд
|
||||
### 2) **Почему хеш-таблица почти не чувствительна к порядку?**
|
||||
Из-за особенностей записи данных в память. Хеш-таблица вычисляет, номер строки при помощи формулы т.е мы можем найти любой сколь угодный элемент за $O(1)$
|
||||
### 3) **Почему связный список всегда медленен при поиске?**
|
||||
Из-за способа записи. Так-как мы можем добраться до следующего элемента только путём перебора равного номеру поисковой строки, при сложности $O(n)$
|
||||
### 4) Как удаление работает в каждой структуре?
|
||||
- **Связный список**
|
||||
Рассматривается 3 случая:
|
||||
1) Если список пустой, **возращаем пустой список**
|
||||
2) Если удаляем голову, то **возвращаем, как голову следующий элемент списка**
|
||||
3) Если мы удаляем промежуточный элемент, ищем нужный элемент а потом **подменяем элементу стоящем перед элементом, который мы ищем ссылку элемента идущему после удаления**
|
||||
- **Хеш-таблица**
|
||||
Реализация считает при помощи Хеш-ключа, номер элемента
|
||||
> P.s. В моей реализации Хеш-таблица и связный список схожи по реализации, потому что Хеш-таблица использует функцию связного списка)
|
||||
- **Бинарное дерево**
|
||||
Рассмотрим так же 4 случая(немного схожа со связным списком с поправкой на то, что потомок может быть не один):
|
||||
1) Если список пустой, **возращаем пустой список**
|
||||
2) Если элемент слева, то **спускаемся в левую ветвь**
|
||||
3) Если элемент справа, то **спускаемся в правую ветвь**
|
||||
4) Если ветки 2, то **как-то оцениваем обе вершины и двигаемся к нужному результату**
|
||||
При нахождении элемента элементу слева от найденного передаём ссылку на правый от найденного элемента и наоборот левому элементу ссылку на правый
|
||||
###
|
||||
5) Какую структуру и для каких задач (частые вставки, частый поиск, необходимость получать данные в порядке) стоит выбирать в реальной жизни?
|
||||
- Для частых вставок и поиска элементов следует использовать Хеш-таблицы, из-за особенностей добавления (определение номера в таблицы при помощи математической формулы, а не порядковым номером)
|
||||
- В случае, если нам надо использовать упорядоченные данные, то следует использовать бинарное дерево(из-за особенностей хранения)
|
||||
>P.s. Вывод 0) Как же долго работает функция print()...
|
||||
Loading…
Reference in New Issue
Block a user