概念
置换树permutation tree,是一棵多叉树,这个数据结构网上发表于Peter Luschny的博客Permutation Trees
。该树有个特点,根节点为0,子节点比父节点大,从左到右,右节点比左节点大。置换树能唯一表示一个排列,表示排列是从右到左的DFS。我举个例子:
这棵树从右到左DFS的结果是
[
2
,
3
,
4
,
1
]
[2,3,4,1]
[2,3,4,1],代表
[
2
,
3
,
4
,
1
]
[2,3,4,1]
[2,3,4,1]这个排列顺序。
由排列生成树就是挨个遍历,如果比前一个大,就作为前一个元素的子节点插入。如果比前一个元素小,那么就作为左兄弟节点插入。
算法的关键在于找到前一个元素在树中的位置。如果使用二分查找,如果查不到则往下从子节点继续查找的算法,性能会比较低,所以这里建议直接使用字典、HashMap等数据结构,快速查找。但是查找到之后,还是要继续使用二分查找进行精确的定位。
这个算法就是树的DFS,无须赘述。不过我至今没搞懂把排列用这种树表示,有什么用途。
完整代码
# _*_ coding:utf-8 _*_
class Node:
def __init__(self):
self.__value = None
self.__parent = None
self.__children = []
@property
def value(self):
return self.__value
@value.setter
def value(self, val):
self.__value = val
@property
def parent(self):
return self.__parent
@parent.setter
def parent(self, p):
self.__parent = p
@property
def children(self):
return self.__children
@children.setter
def children(self, c):
self.__children = c
def find_parent(self, e):
x = self
prev = x
while x.value >= e:
prev = x
x = x.parent
return x, prev
def __str__(self):
return self.__value
class Tree:
def __init__(self):
root = Node()
root.value = 0
self.__root = root
@property
def root(self):
return self.__root
@root.setter
def root(self, r):
self.__root = r
def of(self, array):
dict = {}
for i, e in enumerate(array):
node = Node()
node.value = e
dict[e] = node
if i > 0:
prev = array[i - 1]
prev_node = dict[prev]
if e > prev:
# as child
prev_node.children.append(node)
node.parent = prev_node
else:
# as left sibling
p, sib = prev_node.find_parent(e)
c = p.children
index = self.index_of(c, e)
c.insert(index, node)
node.parent = p
else:
self.__root.children.append(node)
node.parent = self.__root
def to_dot_string(self):
s = 'digraph {\n'
stack = [self.__root]
s += f'n{self.__root.value}[label="{self.__root.value}"]\n'
while len(stack) > 0:
v = stack.pop()
for x in v.children:
s += f'\tn{x.value}[label="{x.value}"]\n'
s += f'\tn{v.value} -> n{x.value}\n'
stack.append(x)
s += '}\n'
return s
def to_permutation(self):
array = []
stack = [self.__root]
while len(stack) > 0:
v = stack.pop()
if v.value != 0:
array.append(v.value)
for x in v.children:
stack.append(x)
return array
def index_of(self, c, e):
start = 0
end = len(c) - 1
while start != end:
mid = (start + end) // 2
if e < c[mid].value:
end = mid
elif e == c[mid]:
return mid
else:
start = mid
return start
if __name__ == '__main__':
tree = Tree()
tree.of([3,4,2,1])
print(tree.to_dot_string())
print(tree.to_permutation())
测试结果:
digraph {
n0[label="0"]
n1[label="1"]
n0 -> n1
n2[label="2"]
n0 -> n2
n3[label="3"]
n0 -> n3
n4[label="4"]
n3 -> n4
}
效果如图:
置换树转排列的结果也是正确的:
[3, 4, 2, 1]