二叉平衡樹 python 列表 遞迴
二叉平衡樹-python-列表-遞迴
用列表遞迴的方式表示二叉樹,例如:只有根root的樹用列表來表示就是 [None, None], 再例如一個這樣的樹:
用列表來表示就是:
[[None, None, 222], [None, [None, None, 444], 333], 111]
可以簡單的認為看見一個 ‘ [ ] ’ 括號就認為它是一個節點,裡面的元素有該節點的左kid,右kid,以及這個節點的data.
所以,我構建了一個這樣的樹結構:
class Node(object):
def __init__(self, data=None, l_kid=None, r_kid=None):
self.data = data
self.left = l_kid
self.right = r_kid
class Tree(object):
list_with_node = None # 例 :只有根的二叉樹為 [None, None, root]
list_only = None # 例 :只有根的二叉樹為 [None, None]
list_with_data = None # 例 :只有根的二叉樹為 [None, None, root.data]
def __init__(self, root=None):
self.root = root
# 例:[None, None, root]表示一個只有root節點的樹,有三個元素:左子樹,右子樹,該節點物件
def list_with_node_travel(self, node):
if not node:
return None
total = [
self.list_with_node_travel(node.left),
self.list_with_node_travel(node.right),
node,
]
return total
# 例:[None, None]表示一個只有root節點的樹, [[None, None], [None, None]]表示一個第三層全為None的平衡樹
def list_only_travel(self, node):
if not node:
return None
total = [
self.list_only_travel(node.left),
self.list_only_travel(node.right),
# node,
]
return total
# 例:[None, None, root.data]表示一個只有root節點的樹,有三個元素:左子樹,右子樹,該節點的data
def list_with_data_travel(self, node):
if not node:
return None
total = [
self.list_with_data_travel(node.left),
self.list_with_data_travel(node.right),
node.data,
]
return total
def update_list(self):
Tree.list_with_node = self.list_with_node_travel(self.root)
Tree.list_only = self.list_only_travel(self.root)
Tree.list_with_data = self.list_with_data_travel(self.root)
# 層次遍歷list,也可以說是樹,當遇到第一個None時,返回None在該層的index,以及該層的深度depth
# depth從2開始,預設root存在, 換句話說Tree.list_only預設為list型別.
def _append(self, x, depth=2):
if isinstance(x, list):
if None in x:
# 返回該層第一次出現None的index和該層的depth
return x.index(None), depth
# 如果該層沒有None,說明該層滿了,那就用迴圈開啟x內的所有list,並把他們拼在一起
# 這步的意思就是,進入下一層,遞迴判斷第一次出現None的座標
a = []
for i in x:
a.extend(i)
depth += 1
y = depth
return self._append(a, depth=y)
# 傳入一個node,新增在樹的結構裡
def append(self, node):
index, depth = self._append(Tree.list_only)
code = self._arithmetic(index, depth)
if len(code) == 1:
# [None, None, node]為這個新node,左右子樹為None, 節點物件為node.
Tree.list_with_node[int(code)] = [None, None, node]
# 為該node物件建立父子關係
if int(code) == 0:
self.root.left = node
else:
self.root.right = node
return self.update_list()
current_list = Tree.list_with_node
last = int(code[-1])
# 先走到這個新節點的父輩節點.
code_to_father = code[:-1]
for i in code_to_father:
current_list = current_list[int(i)]
# 此時current_list來到父節點[x, x, 父node],這時再看最後一步的方向來設定新node為父節點的哪邊。
if last == 0:
current_list[-1].left = node
else:
current_list[-1].right = node
current_list[last] = [None, None, node]
return self.update_list()
# 根據depth和該層第一次出現None的index,得到一個神祕碼(反映出該None在數中的座標)
def _arithmetic(self, index, depth):
"""
這個演算法建議畫圖琢磨
(position, depth),例如(6, 4)為第4層從左到右第6個元素。該層滿元素個數為2 ** (depth - 1) = 8個
步數 = depth - 1 = 3 步
1. 因為6 > (8 / 2),所以從root開始找該元素時第一步是走root.right
2. 再用6 - (8 / 2) = 2, 因為 2 <= ((8 / 2) / 2),所以這步是走左邊left,root.right.left
3. 上一步得出左邊後,2就不用減((8 / 2) / 2), 因為2 > (((8 / 2) / 2) / 2),所以走右邊right
4. 最後路線為:root.right.left.right總共走三步就到達該node準確位置
5. 神祕碼就為 '101' , '1'為right, '0'為left. 遍歷找node或node.data時會用到神祕碼
"""
position = index + 1
# times為步數
times = depth - 1
# nums為該層滿元素的個數(depth為2時,該層最多2個node,第三層最多4個node)
nums = 2 ** (depth - 1)
i = 1
code = ''
while i <= times:
if position <= nums / 2:
magic = '0'
nums = nums / 2
else:
magic = '1'
position = position - (nums / 2)
nums = nums / 2
code += magic
i += 1
return code
我們先構建這樣的樹結構,看看輸出:
if __name__ == '__main__':
node_a = Node(data=111)
node_b = Node(data=222)
node_c = Node(data=333)
node_d = Node(data=444)
node_e = Node(data=555)
node_f = Node(data=666)
# 設定樹關係
tree = Tree(node_a)
node_a.left = node_b
node_b.left = node_d
node_a.right = node_c
node_c.left = node_e
node_e.right = node_f
tree.update_list()
print(tree.__class__.list_with_data)
# 輸出為: [[[None, None, 444], None, 222], [[None, [None, None, 666], 555], None, 333], 111]
此輸出list描述的圖,畫出來後就是上述的圖。
可以這樣去標記列表:
下面來增加幾個節點來看看輸出:
# append節點
add_1 = Node(data='add_1')
add_2 = Node(data='add_2')
add_3 = Node(data='add_3')
add_4 = Node(data='add_4')
add_5 = Node(data='add_5')
add_6 = Node(data='add_6')
add_7 = Node(data='add_7')
add_8 = Node(data='add_8')
add_9 = Node(data='add_9')
tree.append(add_1)
tree.append(add_2)
tree.append(add_3)
tree.append(add_4)
tree.append(add_5)
tree.append(add_6)
tree.append(add_7)
tree.append(add_8)
tree.append(add_9)
print(tree.__class__.list_with_data)
# 輸出為:
[[[[None, None, 'add_3'], [None, None, 'add_4'], 444], [[None, None, 'add_5'], [None, None, 'add_6'], 'add_1'], 222], [[[None, None, 'add_7'], [None, None, 666], 555], [[None, None, 'add_8'], [None, None, 'add_9'], 'add_2'], 333], 111]
此結果所描繪的樹結構就是上圖所示的樹結構。
相關文章
- 遍歷二叉樹-------遞迴&非遞迴二叉樹遞迴
- 遞迴函式-樹形列表遞迴函式
- 二叉樹遞迴練習二叉樹遞迴
- 二叉樹的遞迴套路二叉樹遞迴
- 【C++】翻轉二叉樹(遞迴、非遞迴)C++二叉樹遞迴
- python實現二叉樹及其七種遍歷方式(遞迴+非遞迴)Python二叉樹遞迴
- 二叉樹非遞迴遍歷二叉樹遞迴
- 平衡二叉樹二叉樹
- 二叉樹的四種遍歷(遞迴與非遞迴)二叉樹遞迴
- 【資料結構】二叉樹遍歷(遞迴+非遞迴)資料結構二叉樹遞迴
- 什麼是遍歷二叉樹,JavaScript實現二叉樹的遍歷(遞迴,非遞迴)二叉樹JavaScript遞迴
- python實現非平衡二叉樹Python二叉樹
- 樹(2)--二叉樹的遍歷(非遞迴)+線索二叉樹二叉樹遞迴
- 排序二叉樹和平衡二叉樹排序二叉樹
- 平衡二叉樹(AVL)二叉樹
- 平衡二叉樹AVL二叉樹
- 樹3-二叉樹非遞迴遍歷(棧)二叉樹遞迴
- 遍歷二叉樹的遞迴與非遞迴程式碼實現二叉樹遞迴
- 二叉樹建立及遍歷演算法(遞迴及非遞迴)二叉樹演算法遞迴
- [Python手撕]判斷平衡二叉樹Python二叉樹
- 非遞迴先序遍歷二叉樹遞迴二叉樹
- 【刷題】二叉樹非遞迴遍歷二叉樹遞迴
- 二叉樹 遞迴 洛谷P1364二叉樹遞迴
- 手擼二叉樹——AVL平衡二叉樹二叉樹
- 平衡二叉樹,B樹,B+樹二叉樹
- 二叉樹建立後,如何使用遞迴和棧遍歷二叉樹?二叉樹遞迴
- 刷題系列 - Python用遞迴實現求二叉樹深度Python遞迴二叉樹
- 二叉樹的前中後序遍歷(遞迴和非遞迴版本)二叉樹遞迴
- 二叉樹——後序遍歷的遞迴與非遞迴演算法二叉樹遞迴演算法
- [java] 二叉樹的後序遍歷(遞迴與非遞迴實現)Java二叉樹遞迴
- 【筆記】平衡二叉樹筆記二叉樹
- 平衡二叉樹(AVL樹)和 二叉排序樹轉化為平衡二叉樹 及C語言實現二叉樹排序C語言
- 遍歷二叉樹的迭代和遞迴方法二叉樹遞迴
- 二叉樹的非遞迴遍歷寫法二叉樹遞迴
- 資料結構之二叉樹遞迴操作資料結構二叉樹遞迴
- Day14 | 二叉樹遞迴遍歷二叉樹遞迴
- 平衡二叉樹(AVL樹),原來如此!!!二叉樹
- 十三、Mysql之平衡二叉樹(AVL樹)MySql二叉樹