我正在研究张开树,我决定使用一篇带有正面评价的文章以及来自 habr 的分析和代码:https ://habr.com/ru/company/JetBrains-education/blog/210296/
在文章中,顶点是由一个类来描述的,并没有对代码如何处理多个顶点进行注释。可能是我的实践知识不足以理解创建类元素的过程(我学过OOP,但没有在实践中使用,函数式的方法就够了)。
因此,为了让代码正常工作,我引入了一个列表li,其中我将类实例一个一个放置(一个实例 - 一个顶点),整个树的重建只是通过更改指向孩子和父母的指针,我不对列表进行排序本身。当然,我不得不重写列表下的整个代码(我的部分代码如下)。
问题:我做了正确的事情吗,或者代码可以不改变,但是对于顶点,有必要做一些不同的事情——更多的 OOP 或更高效?
文章中的示例代码(带引号),文章中的所有代码都按照评论中的要求在下面给出:
“要描述树的结构,我们需要一个描述单个顶点的简单类,”
class Node:
def __init__(self, key, left = None, right = None, parent = None):
self.left = left
self.right = right
self.parent = parent
self.key = key
“以及两个用于处理指向父母的指针的辅助程序。”
def set_parent(child, parent):
if child != None:
child.parent = parent
def keep_parent(v):
set_parent(v.left, v)
set_parent(v.right, v)
和插入过程:
def insert(root, key):
left, right = split(root, key)
root = Node(key, left, right)
keep_parent(root)
return root
我对应的一段代码带了一个列表(类我就不重复了,描述方式和文章一样,我不引用函数调用来减少题量):
def set_parent(child, parent):
if child != None:
# Изменение относительно исходного кода
li[child].parent = parent
def keep_parent(v):
# Изменения относительно исходного кода
set_parent(li[v].left, v)
set_parent(li[v].right, v)
def insert(root, key):
left, right = split(root, key)
# Изменение относительно исходного кода
li[root] = Node(key, left, right)
keep_parent(root)
return root
# Объявление списка
li = []
n = input()
for _ in range (n):
number = input ()
# Добавление в список вершины
li.append(Node(number))
来自文章https://habr.com/ru/company/JetBrains-education/blog/210296/的完整代码:
class Node:
def __init__(self, key, left = None, right = None, parent = None):
self.left = left
self.right = right
self.parent = parent
self.key = key
def set_parent(child, parent):
if child != None:
child.parent = parent
def keep_parent(v):
set_parent(v.left, v)
set_parent(v.right, v)
def rotate(parent, child):
gparent = parent.parent
if gparent != None:
if gparent.left == parent:
gparent.left = child
else:
gparent.right = child
if parent.left == child:
parent.left, child.right = child.right, parent
else:
parent.right, child.left = child.left, parent
keep_parent(child)
keep_parent(parent)
child.parent = gparent
def splay(v):
if v.parent == None:
return v
parent = v.parent
gparent = parent.parent
if gparent == None:
rotate(parent, v)
return v
else:
zigzig = (gparent.left == parent) == (parent.left == v)
if zigzig:
rotate(gparent, parent)
rotate(parent, v)
else:
rotate(parent, v)
rotate(gparent, v)
return splay(v)
def find(v, key):
if v == None:
return None
if key == v.key:
return splay(v)
if key < v.key and v.left != None:
return find(v.left, key)
if key > v.key and v.right != None:
return find(v.right, key)
return splay(v)
def split(root, key):
if root == None:
return None, None
root = find(root, key)
if root.key == key:
set_parent(root.left, None)
set_parent(root.right, None)
return root.left, root.right
if root.key < key:
right, root.right = root.right, None
set_parent(right, None)
return root, right
else:
left, root.left = root.left, None
set_parent(left, None)
return left, root
def insert(root, key):
left, right = split(root, key)
root = Node(key, left, right)
keep_parent(root)
return root
def merge(left, right):
if right == None:
return left
if left == None:
return right
right = find(right, left.key)
right.left, left.parent = left, right
return right
def remove(root, key):
root = find(root, key)
set_parent(root.left, None)
set_parent(root.right, None)
return merge(root.left, root.right)
感谢 Roman 的评论(下文引用),很明显我误解了代码如何组织树元素的存储。
问题的答案:我做错了,代码必须保持不变才能存储树的元素。
简而言之,文章代码创建的所有元素都是没有名称的对象,代码本身通过放置在这些对象中的指针来查找这些对象。部分为此,使用了类。
"
insert创建一个新的根节点并向其添加现有树的片段。要使用树(并且只有两个操作:insert- 添加新元素和find- 搜索元素),您需要有一个指向根的链接节点,是她被输入输入,什么在insert,什么在。find剩余的节点可以通过链从根访问left,例如,在搜索时,决定在树中移动的位置(即从哪个子树当前节点)向右或向左。rightfind树的工作如下所示:
首先树是空的:
tree = None添加第一个元素:
tree = insert(tree, 3),等等:
tree = insert(tree, value_to_insert)那些。在
tree使用树的客户端中,它存储了到树根的链接,它不应该存储其他顶点。修改操作总是返回一个新的树根,客户端必须保存并在将来使用”