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

剧情提要:
阿伟看到了一本比较有趣的书,是关于《计算几何》的,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可以和数据结构说拜拜了呢。


本节到此结束,欲知后事如何,请看下回分解。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值