您的位置:首页 > 编程语言 > Python开发

[从头学数学] 第243节 关于平衡二叉树的Python实现

2016-07-23 16:41 681 查看
剧情提要:

阿伟看到了一本比较有趣的书,是关于《计算几何》的,2008年由北清派出版。很好奇

它里面讲了些什么,就来看看啦。

正剧开始:

星历2016年07月23日 16:30:59, 银河系厄尔斯星球中华帝国江南行省。

[工程师阿伟]正在和[机器小伟]一起研究[计算几何]]。



关于平衡二叉树ALV,一直没有找到Python版本,当然C++和Java版本有很多。

于是想自己实现一个。

首先研究了下二叉查找树:

<span style="font-size:18px;">#用列表模拟平衡二叉树
class BBT():
#对于按<法则排序好的列表,查看其中任意元素的左右叶子,返回序号
#二叉查找树,会有退化现象
def childindex(self, total, cur, mode = 'L'):
#total: 列表总元素数,位序取值范围 0 ~ total-1
#cur: 当前元素在列表中的位序

start = 0;
end = total-1;

if (cur == start or cur == end):
return [cur, -1, -1, math.ceil(math.log(total)/math.log(2))-1];

midArray = [];

mid = (start + end+1)//2;
left = (start + mid+1)//2;
right = (mid + end+1)//2;
level = 0;

midArray.append(mid);

while (mid != cur and level < 10):
if (mid < cur):
start = mid;
mid_ = (end + mid+1)//2;
right = (end + mid_+1)//2;
left = (mid + mid_+1)//2;
mid = mid_;
elif (mid > cur):
end = mid;
mid_ = (start + mid+1)//2;
right = (mid+mid_+1)//2;
left = (start+mid_+1)//2;
mid = mid_;

midArray.append(mid);
level+=1;

if (left in midArray):
left = -1;

if (right in midArray):
right = -1;

return [cur, left, right, level];
</span>


据说这种树有退化的问题,只写了这一个函数,这个问题就暴露了。

结论就是这种树是没用的,也没有研究下去的价值了。

接着看ALV树。

<span style="font-size:18px;">###
# @usage   平衡二叉树的Python实现,C++/Java实现到处都有
# @author  mw
# @date    2016年07月23日  星期六  10:09:31
# @param
# @return
#
###

#AVL树
class ALVTreeNode():
def __init__(self, data, height, freq, left, right):
self.data = data;
self.height = height;
self.freq = freq;
self.left = left;
self.right = right;

#小于<法则
def less(x1, x2):
return x1 < x2;

class ALVTree():
def __init__(self):
self.root = None;
self.left = None;
self.right = None;

def setValue(self, root, left, right):
self.root = root;
self.left = left;
self.right = right;

def getValue(self):
return [self.root, self.left, self.right];

def info(self, node):
if (node == None):
info = 'None';
else:
if (node.left == None):
sL = 'None';
else:
sL = node.left.data;

if (node.right == None):
sR = 'None';
else:
sR = node.right.data;

info = [node.data, node.height, node.freq, sL, sR];
print(info);

def genNode(self, data, height, freq, left, right):
return ALVTreeNode(data, height, freq, left, right);

def height(self, node):
if (node == None):
return 0;
else:
lh = self.height(node.left);
rh = self.height(node.right);

node.height = max(lh, rh)+1;

return node.height;

#左左情况下的旋转
#输入的是高度最高的节点,也就是待处理的root
def rotateLL(self, k2):
k1 = k2.left;
k2.left = k1.right;
k1.right = k2;

k2.height = max(self.height(k2.left), self.height(k2.right))+1;
k1.height = max(self.height(k1.left), k2.height)+1;

return k1;

#右右情况下的旋转
#输入的是高度最高的节点,也就是待处理的root
def rotateRR(self, k2):
k1 = k2.right;
k2.right = k1.left;
k1.left = k2;

k2.height = max(self.height(k2.left), self.height(k2.right))+1;
k1.height = max(self.height(k1.right), k2.height)+1;

return k1;

#左右情况的旋转
#输入的是高度最高的节点,也就是待处理的root
def rotateLR(self, k3):
k1 = self.rotateRR(k3.left);
k3.left = k1;
k2 = self.rotateLL(k3);

return k2;

#右左情况的旋转
#输入的是高度最高的节点,也就是待处理的root
def rotateRL(self, k3):
k1 = self.rotateLL(k3.right);
k3.right = k1;
k2 = self.rotateRR(k3);

return k2;

#平衡值
def balanceFlag(self, node):
return self.height(node.left)-self.height(node.right);

#左平衡
def LBalance(self, root):
p = root;
c = p.left;
rc = c.right;

cbf = self.balanceFlag(c);

if (cbf == 1):
root = self.rotateLL(root);
elif (cbf == -1):
root = self.rotateLR(root);

return root;

#右平衡
def RBalance(self, root):
p = root;
c = p.right;
lc = c.left;

cbf = self.balanceFlag(c);

if (cbf == -1):
root = self.rotateRR(root);
elif (cbf == 1):
root = self.rotateRL(root);

return root;

</span>


左旋,右旋,左平衡,右平衡都没有问题。



然后到插入就卡壳了,怎么都调不出结果来。

下面这是废码,留着看看吧:

<span style="font-size:18px;">    #插入
def insert_x(self, node, data):
if (node == None):
node = self.genNode(data, 1, 0, None, None);
return node;
else:
if (less(data, node.data)):
if (node.left == None):
node.left =  self.genNode(data, 1, 0, None, None);

self.height(node);

if (2 == self.height(node.left) - self.height(node.right)):
if less(data, node.left.data):
self.rotateLL(node);
else:
self.rotateLR(node);

return node;
else:
return self.insert(node.left, data);

elif (less(node.data, data)):
if (node.right == None):
node.right =  self.genNode(data, 1, 0, None, None);

self.height(node);

if (2 == self.height(node.right) - self.height(node.left)):
if less(node.right.data, data):
self.rotateRR(node);
else:
self.rotateRL(node);

return node;
else:
return self.insert(node.right, data);

else:
#如果相等,就把频率加1
node.freq+=1;

#插入
def insert(self, root, data, tall = 1):
if (root == None):
tall = 1;
root = self.genNode(data, 1, 0, None, None);
self.setValue(root, root.left, root.right);

return 1;
elif (root.data == data):
#如果相等,就把频率加1
root.freq+=1;
self.setValue(root, root.left, root.right);
return 0;
elif (less(data, root.data)):
if (root.left == None):
self.setValue(root, self.genNode(data, 1, 0, None, None), root.right);
return 1;
else:
self.insert(root.left, data, tall):

if (tall):
root = self.root;
rbf = self.balanceFlag(root);

if (rbf == 1):
root = LBalance(root);
tall = 0;
elif (rbf == 0):
tall = 1;
elif (rbf == -1):
tall = 0;

self.root = root;
return 0;

elif (less(root.data, data)):
if (self.insert(root.right, data, tall)):
return 1;
if (tall):
rbf = self.balanceFlag(root);

if (rbf == -1):
root = RBalance(root);
tall = 0;
elif (rbf == 0):
tall = 1;
elif (rbf == 1):
tall = 0;
self.root = root;
return 0;

if __name__ == '__main__':
alv = ALVTree();

alv.insert(None, 0);
root = alv.root;

alv.info(root);

for i in range(3):
alv.insert(root, i);
root = alv.root;
alv.info(root);</span>




阿伟最后终于发现了问题所在,在C++中可以用*号给每个节点作为存储地址,

在Java里面也可以用&,虽然效果差了点,但在Python里面,啥都没有。

插入函数中需要不断地new出新地址来存储节点,但这确实是做不到的。

当然,只要解决了每个节点的存储空间问题,用Python也是可以实现这个ALV树的。

用链表来存也不是不可以,但那样效率肯定会非常差。

那是不是可以这么说: Python可以和数据结构说拜拜了呢。

本节到此结束,欲知后事如何,请看下回分解。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: