Python采用平衡二叉树实现一个字典类Dict | 附源码+视频

Posted 清华计算机学堂

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python采用平衡二叉树实现一个字典类Dict | 附源码+视频相关的知识,希望对你有一定的参考价值。









本篇我们将采用平衡二叉树实现一个字典类Dict,实现元素的插入、删除、关键字in操作、按关键字取值、按关键字赋值和按关键字递增输出所有元素的算法。

01

案例讲解

利用《数据结构教程(Python语言描述)》介绍的AVL原理设计AVL树类AVLTree,用AVL.py文件存放,其中的代码如下:
class AVLNode:                                #AVL树结点类
  def __init__(self,k,d):                       #构造方法,新建结点均为叶子,高度为1
    self.key
=k                              #关键字k
    self.data=d                             #关键字对应的值d
    self.lchild=None                        #左指针
    self.rchild=None                        #右指针
    self.ht=1                               #当前结点的子树高度

class AVLTree:                                #AVL树类
  def __init__(self):
    self.r
=None                             #根结点

  def getht(self,p):                          #返回结点p的子树高度
    if p==None: return 0                #空树高度为0
    return p.ht

  def right_rotate(self,a):                     #以结点a为根做右旋转
    b=a.lchild
    a.lchild=b.rchild
    b.rchild=a
     a.ht=max(self.getht(a.rchild),self.getht(a.lchild))+1
    b.ht=max(self.getht(b.rchild),self.getht(b.lchild))+1
     return b

  def left_rotate(self,a):                      #以结点a为根做左旋转
    b=a.rchild
    a.rchild=b.lchild
     b.lchild=a
     a.ht=max(self.getht(a.rchild),self.getht(a.lchild))+1
    b.ht=max(self.getht(b.rchild),self.getht(b.lchild))+1
     return b

  def LL(self,a):                             #LL型调整
      return self.right_rotate(a)

  def RR(self,a):                             #RR型调整
    return self.left_rotate(a)

  def LR(self,a):                             #LR型调整
    b=a.lchild
    a.lchild=self.left_rotate(b)              #结点b左旋
    return self.right_rotate(a)               #结点a右旋

  def RL(self,a):                             #RL型调整
    b=a.rchild
    a.rchild=self.right_rotate(b)             #结点b右旋
     return self.left_rotate(a)                #结点a左旋

  def insert(self,k,d):                         #插入(k,d)结点
    self.r=self._insert(self.r,k,d)

  def _insert(self,p,k,d):                #被insert方法调用
      if p==None:                                #空树时创建根结点
      q=AVLNode(k,d)
      return q
    elif k==p.key:
      p.data=d                               #更新data
      return p
    elif k<p.key:                               #k<p.key的情况
      p.lchild=self._insert(p.lchild,k,d)         #将(k,d)插入到p的左子树中
      if self.getht(p.lchild)-self.getht(p.rchild)>=2:   #找到失衡结点p
        if k<p.lchild.key:                  #(k,d)是插入在p的左孩子的左子树中
          p=self.LL(p)                    #采用LL型调整
        else:                               #(k,d)是插入在p的左孩子的右子树中
          p=self.LR(p)                    #采用LR型调整
    else:                                     #k>p.key的情况
      p.rchild=self._insert(p.rchild,k,d)         #将(k,d)插入到p的右子树中
      if self.getht(p.rchild)-self.getht(p.lchild)>=2:   #找到失衡结点p
        if k>p.rchild.key:                   #(k,d)是插入在p的右孩子的右子树中
          p=self.RR(p)                   #采用RR型调整
        else:                             #(k,d)是插入在p的右孩子的左子树中
          p=self.RL(p)                   #采用RL型调整
    p.ht=max(self.getht(p.lchild),self.getht(p.rchild))+1  #更新结点p的高度
    return p

  def delete(self,k):                             #删除关键字为k的结点
    self.r=self._delete(self.r,k)

  def _delete(self,p,k):                  #被delete调用删除k结点
    if p==None: return p
    if p.key==k:                              #找到关键字为k的结点p
      if p.lchild==None:                    #结点p只有右子树的情况
        return p.rchild                     #直接用右孩子替代结点p
      elif p.rchild==None:                  #结点p只有左子树的情况
        return p.lchild                     #直接用左孩子替代结点p
      else:                                 #结点p同时有左右子树的情况
        if self.getht(p.lchild)>self.getht(p.rchild):   #结点p的左子树较高
          q=p.lchild
          while(q.rchild!=None):          #在结点p的左子树中查找最大结点q
            q=q.rchild
          p=self._delete(p,q.key)         #删除结点q
           p.key=q.key                   #用q结点值替代p结点值
          p.data=q.data
          return p
        else:                             #结点p的右子树较高
          q=p.rchild
          while q.lchild!=None:           #在结点p的右子树中查找最小结点q
            q=q.lchild
          p=self._delete(p,q.key)         #删除结点q
          p.key=q.key                   #用q结点值替代p结点值
          p.data=q.data
          return p
    elif k<p.key:                             #k<p.key的情况
      p.lchild=self._delete(p.lchild,k)        #在左子树中删除关键字k的结点
      if self.getht(p.rchild)-self.getht(p.lchild)>=2:   #找到失衡结点p
        if self.getht(p.rchild.lchild)>self.getht(p.rchild.rchild):
          p=self.RL(p)                    #结点p右孩子的左子树较高,做RL型调整
        else:
          p=self.RR(p)                    #结点p右孩子的右子树较高,做RR型调整
    elif k>p.key:                             #k>p.key的情况
      p.rchild=self._delete(p.rchild,k)         #在右子树中删除关键字k的结点
      if self.getht(p.lchild)-self.getht(p.rchild)>=2:  #找到失衡结点p
        if self.getht(p.lchild.rchild)>self.getht(p.lchild.lchild):
          p=self.LR(p)                   #结点p左孩子的右子树较高,做LR型调整
        else:
          p=self.LL(p)                   #结点p左孩子的左子树较高,做LL型调整
    p.ht=max(self.getht(p.lchild),self.getht(p.rchild))+1  #更新结点p的高度
    return p

  def search(self,k):                  #在AVL树中查找关键字为k的结点
    return self._search(self.r,k)            #r为AVL树的根结点

  def _search(self,p,k):                          #被search方法调用
      if p==None: return None              #空树返回None
      if p.key==k: return p.data                  #找到后返回p.data
       if k<p.key:
         return self._search(p.lchild,k)            #在左子树中递归查找
      else:
        return self._search(p.rchild,k)            #在右子树中递归查找

  def inorder(self):                              #中序遍历所有结点
      global res
       res=[]
       self._inorder(self.r)
       return res

  def _inorder(self,p):                           #被inorder方法调用
      global res
       if p!=None:
        self._inorder(p.lchild)
          res.append([p.key,p.data])
          self._inorder(p.rchild)

  def DispAVL(self):                  #输出AVL树的括号表示串
        self._DispAVL(self.r)

  def _DispAVL(self,p):                       #被DispAVL方法调用
      if p!=None:
        print(p.key,end='')                   #输出根结点值
          if p.lchild!=None or p.rchild!=None:
             print("(",end='')                 #有孩子结点时才输出“(”
             self._DispAVL(p.lchild)            #递归处理左子树
            if p.rchild!=None:
               print(",",end='')               #有右孩子结点时才输出“,”
              self._DispAVL(p.rchild)             #递归处理右子树
              print(")",end='')                 #有孩子结点时才输出“)”

在设计字典类Dict时,包含avl属性用来存放字典的所有元素,它是AVLTree类对象,字典类的相关方法通过操作avl来实现。对应的Dict类如下:

from AVL import AVLTree
class Dict:
  def __init__(self):                         #构造方法
      self.avl
=AVLTree()                #对应AVLTree对象avl

  def insert(self,k,d):                       #插入(k,d)
      self.avl.insert(k,d)

  def delete(self,k):                         #删除关键字为k的元素
      self.avl.delete(k)

  def inorder(self):                        #按关键字递增输出所有元素
      return self.avl.inorder()

  def __contains__(self,k):                   #in运算符重载
      if self.avl.search(k)!=None:
        return True
      else:
        return False

  def __getitem__(self,k):                  #按关键字取值
      return self.avl.search(k)

  def __setitem__(self,k,d):                  #按关键字赋值
      self.avl.insert(k,d)

如,以下程序利用字典类Dict统计一个整数序列中每个整数出现的次数,其中每个元素为[k,d],k为整数,d为该关键字出现的次数:

#主程序
if __name__ == '__main__':
  a=[1,2,5,4,1,2,5]
   print("(1)建立dic")
   dic=Dict()                      #定义Dict对象dic
   for i in range(len(a)):
      if a[i] in dic:                         #若a[i]已存在,次数增1
        dic[a[i]]+=1
       else:                                 #若a[i]不存在,次数置为1
        dic[a[i]]=1
  print("(2)输出所有的元素:",dic.inorder())
   k=2
   print("(3)删除关键字%d" %(k))
   dic.delete(2)
   print("(4)删除后所有元素:",dic.inorder())

上述程序的执行结果如下:

(1)建立dic

(2)输出所有的元素: [[1, 2], [2, 2], [4, 1], [5, 2]]

(3)删除关键字2

(4)删除后所有元素: [[1, 2], [4, 1], [5, 2]]

02

视频讲解

视频教程如下:

Python采用平衡二叉树实现一个字典类Dict | 附源码+视频

03

源代码下载

04

参考书籍

《数据结构教程(Python语言描述)》

ISBN:978-7-302-56028-9

李春葆 等 编著

定价:69.8元

Python采用平衡二叉树实现一个字典类Dict | 附源码+视频

Python采用平衡二叉树实现一个字典类Dict | 附源码+视频

扫码,优惠购书

05

精彩文章回顾




以上是关于Python采用平衡二叉树实现一个字典类Dict | 附源码+视频的主要内容,如果未能解决你的问题,请参考以下文章

Python的标准库中是不是有平衡二叉树的模块?

为啥 Haskell Maps 实现为平衡二叉树而不是传统的哈希表?

二叉树的深度平衡是啥意思?

C# AVL树(平衡二叉树)的实现

C# AVL树(平衡二叉树)的实现

一棵树,怎么就平衡了(图解AVL+实现)