问题

Python中的二叉树查找算法模块

思路说明

二叉树查找算法,在开发实践中,会经常用到。按照惯例,对于这么一个常用的东西,Python一定会提供轮子的。是的,python就是这样,一定会让开发者省心,降低开发者的工作压力。 python中的二叉树模块内容:

  • BinaryTree:非平衡二叉树
  • AVLTree:平衡的AVL树
  • RBTree:平衡的红黑树

以上是用python写的,相面的模块是用c写的,并且可以做为Cython的包。

  • FastBinaryTree
  • FastAVLTree
  • FastRBTree

特别需要说明的是:树往往要比python内置的dict类慢一些,但是它中的所有数据都是按照某个关键词进行排序的,故在某些情况下是必须使用的。

安装和使用

安装方法

安装环境:

ubuntu12.04, python 2.7.6

安装方法

安装成功,ok!下面就看如何使用了。

应用

bintrees提供了丰富的API,涵盖了通常的多种应用。下面逐条说明其应用。

  • 引用

如果按照一般模块的思路,输入下面的命令引入上述模块

  1. 1. >>> import bintrees

错了,这是错的,出现如下警告:(×××不可用,用×××)

  1. 1. Warning: FastBinaryTree not available, using Python version BinaryTree.
  2. 2. Warning: FastAVLTree not available, using Python version AVLTree.
  3. 3. Warning: FastRBTree not available, using Python version RBTree.

正确的引入方式是:

  1. 1. >>> from bintrees import BinaryTree #只引入了BinartTree
  2. 2. >>> from bintrees import * #三个模块都引入了
  • 实例化

看例子:

  1. 1. >>> btree = BinaryTree()
  2. 2. >>> btree
  3. 3. BinaryTree({})
  4. 4. >>> type(btree)
  5. 5. <class 'bintrees.bintree.BinaryTree'>
  • 逐个增加键值对:.setitem(k,v) .复杂度O(log(n))(后续说明中,都会有复杂度标示,为了简单,直接标明:O(log(n)).)

看例子:

  1. 1. >>> btree.__setitem__("Tom","headmaster")
  2. 2. >>> btree
  3. 3. BinaryTree({'Tom': 'headmaster'})
  4. 4. >>> btree.__setitem__("blog","http://blog.csdn.net/qiwsir")
  5. 5. >>> btree
  6. 6. BinaryTree({'Tom': 'headmaster', 'blog': 'http://blog.csdn.net/qiwsir'})
  • 批量添加:.update(E) E是dict/iterable,将E批量更新入btree. O(E*log(n))

看例子:

  1. 1. >>> adict = [(2,"phone"),(5,"tea"),(9,"scree"),(7,"computer")]
  2. 2. >>> btree.update(adict)
  3. 3. >>> btree
  4. 4. BinaryTree({2: 'phone', 5: 'tea', 7: 'computer', 9: 'scree', 'Tom': 'headmaster', 'blog': 'http://blog.csdn.net/qiwsir'})
  • 查找某个key是否存在:.contains(k) 如果含有键k,则返回True,否则返回False. O(log(n))

看例子:

  1. 1. >>> btree
  2. 2. BinaryTree({2: 'phone', 5: 'tea', 7: 'computer', 9: 'scree', 'Tom': 'headmaster', 'blog': 'http://blog.csdn.net/qiwsir'})
  3. 3. >>> btree.__contains__(5)
  4. 4. True
  5. 5. >>> btree.__contains__("blog")
  6. 6. True
  7. 7. >>> btree.__contains__("qiwsir")
  8. 8. False
  9. 9. >>> btree.__contains__(1)
  10. 10. False
  • 根据key删除某个key-value:.delitem(key), O(log(n))

看例子:

  1. 1. >>> btree
  2. 2. BinaryTree({2: 'phone', 5: 'tea', 7: 'computer', 9: 'scree', 'Tom': 'headmaster', 'blog': 'http://blog.csdn.net/qiwsir'})
  3. 3. >>> btree.__delitem__(5) #删除key=5的key-value,即:5:'tea' 被删除.
  4. 4. >>> btree
  5. 5. BinaryTree({2: 'phone', 7: 'computer', 9: 'scree', 'Tom': 'headmaster', 'blog': 'http://blog.csdn.net/qiwsir'})
  • 根据key值得到该kye的value:.getitem(key)

看例子:

  1. 1. >>> btree
  2. 2. BinaryTree({2: 'phone', 7: 'computer', 9: 'scree', 'Tom': 'headmaster', 'blog': 'http://blog.csdn.net/qiwsir'})
  3. 3. >>> btree.__getitem__("blog")
  4. 4. 'http://blog.csdn.net/qiwsir'
  5. 5. >>> btree.__getitem__(7)
  6. 6. 'computer'
  7. 7. >>> btree._getitem__(5) #在btree中没有key=5,于是报错。
  8. 8. Traceback (most recent call last):
  9. 9. File "<stdin>", line 1, in <module>
  10. 10. AttributeError: 'BinaryTree' object has no attribute '_getitem__'
  • 迭代器:.iter()

看例子:

  1. 1. >>> btree
  2. 2. BinaryTree({2: 'phone', 7: 'computer', 9: 'scree', 'Tom': 'headmaster', 'blog': 'http://blog.csdn.net/qiwsir'})
  3. 3. >>> aiter = btree.__iter__()
  4. 4. >>> aiter
  5. 5. <generator object <genexpr> at 0xb7416dec>
  6. 6. >>> aiter.next() #注意:next()一个之后,该值从list中删除
  7. 7. 2
  8. 8. >>> aiter.next()
  9. 9. 7
  10. 10. >>> list(aiter)
  11. 11. [9, 'Tom', 'blog']
  12. 12. >>> list(aiter) #结果是空
  13. 13. []
  14. 14. >>> bool(aiter) #but,is True
  15. 15. True
  • 数的数据长度:.len(),返回btree的长度。O(1)

看例子:

  1. 1. >>> btree
  2. 2. BinaryTree({2: 'phone', 7: 'computer', 9: 'scree', 'Tom': 'headmaster', 'blog': 'http://blog.csdn.net/qiwsir'})
  3. 3. >>> btree.__len__()
  4. 4. 5
  • 找出key最大的k-v对:.max(),按照key排列,返回key最大的键值对。
  • 找出key最小的键值对:.min()

看例子:

  1. 1. >>> btree
  2. 2. BinaryTree({2: 'phone', 7: 'computer', 9: 'scree'})
  3. 3. >>> btree.__max__()
  4. 4. (9, 'scree')
  5. 5. >>> btree.__min__()
  6. 6. (2, 'phone')
  • 两棵树的关系运算

看例子:

  1. 1. >>> other = [(3,'http://blog.csdn.net/qiwsir'),(7,'qiwsir')]
  2. 2. >>> bother = BinaryTree() #再建一个树
  3. 3. >>> bother.update(other) #加入数据
  4. 4. 5. >>> bother
  5. 6. BinaryTree({3: 'http://blog.csdn.net/qiwsir', 7: 'qiwsir'})
  6. 7. >>> btree
  7. 8. BinaryTree({2: 'phone', 7: 'computer', 9: 'scree'})
  8. 9. 10. >>> btree.__and__(bother) #重叠部分部分
  9. 11. BinaryTree({7: 'computer'})
  10. 12. 13. >>> btree.__or__(bother) #全部
  11. 14. BinaryTree({2: 'phone', 3: 'http://blog.csdn.net/qiwsir', 7: 'computer', 9: 'scree'})
  12. 15. 16. >>> btree.__sub__(bother) #btree不与bother重叠的部分
  13. 17. BinaryTree({2: 'phone', 9: 'scree'})
  14. 18. 19. >>> btree.__xor__(bother) #两者非重叠部分
  15. 20. BinaryTree({2: 'phone', 3: 'http://blog.csdn.net/qiwsir', 9: 'scree'})
  • 输出字符串模样,注意仅仅是输出的模样罢了:.repr()

看例子:

  1. 1. >>> btree
  2. 2. BinaryTree({2: 'phone', 7: 'computer', 9: 'scree'})
  3. 3. >>> btree.__repr__()
  4. 4. "BinaryTree({2: 'phone', 7: 'computer', 9: 'scree'})"
  • 清空树中的所有数据:.clear(),O(log(n))

看例子:

  1. 1. >>> bother
  2. 2. BinaryTree({3: 'http://blog.csdn.net/qiwsir', 7: 'qiwsir'})
  3. 3. >>> bother.clear()
  4. 4. >>> bother
  5. 5. BinaryTree({})
  6. 6. >>> bool(bother)
  7. 7. False
  • 浅拷贝:.copy(),官方文档上说是浅拷贝,但是我做了操作实现,是下面所示,还不是很理解其“浅”的含义。O(n*log(n))

看例子:

  1. 1. >>> btree
  2. 2. BinaryTree({2: 'phone', 7: 'computer', 9: 'scree'})
  3. 3. >>> ctree = btree.copy()
  4. 4. >>> ctree
  5. 5. BinaryTree({2: 'phone', 7: 'computer', 9: 'scree'})
  6. 6. 7. >>> btree.__setitem__("github","qiwsir") #增加btree的数据
  7. 8. >>> btree
  8. 9. BinaryTree({2: 'phone', 7: 'computer', 9: 'scree', 'github': 'qiwsir'})
  9. 10. >>> ctree
  10. 11. BinaryTree({2: 'phone', 7: 'computer', 9: 'scree'}) #这是不是在说明属于深拷贝呢?
  11. 12. 13. >>> ctree.__delitem__(7) #删除ctree的一个数据
  12. 14. >>> ctree
  13. 15. BinaryTree({2: 'phone', 9: 'scree'})
  14. 16. >>> btree
  15. 17. BinaryTree({2: 'phone', 7: 'computer', 9: 'scree', 'github': 'qiwsir'})
  • 移除树中的一个数据:.discard(key),这个功能与.delitem(key)类似.两者都不反悔值。O(log(n))

看例子:

  1. 1. >>> ctree
  2. 2. BinaryTree({2: 'phone', 9: 'scree'})
  3. 3. >>> ctree.discard(2) #删除后,不返回值,或者返回None
  4. 4. >>> ctree
  5. 5. BinaryTree({9: 'scree'})
  6. 6. >>> ctree.discard(2) #如果删除的key不存在,也返回None
  7. 7. >>> ctree.discard(3)
  8. 8. >>> ctree.__delitem__(3) #但是,.__delitem__(key)则不同,如果key不存在,会报错。
  9. 9. Traceback (most recent call last):
  10. 10. File "<stdin>", line 1, in <module>
  11. 11. File "/usr/local/lib/python2.7/site-packages/bintrees/abctree.py", line 264, in __delitem__
  12. 12. self.remove(key)
  13. 13. File "/usr/local/lib/python2.7/site-packages/bintrees/bintree.py", line 124, in remove
  14. 14. raise KeyError(str(key))
  15. 15. KeyError: '3'
  • 根据key查找,并返回或返回备用值:.get(key[,d])。如果key在树中存在,则返回value,否则如果有d,则返回d值。O(log(n))

看例子:

  1. 1. >>> btree
  2. 2. BinaryTree({2: 'phone', 7: 'computer', 9: 'scree', 'github': 'qiwsir'})
  3. 3. >>> btree.get(2,"algorithm")
  4. 4. 'phone'
  5. 5. >>> btree.get("python","algorithm") #没有key='python'的值,返回'algorithm'
  6. 6. 'algorithm'
  7. 7. >>> btree.get("python") #如果不指定第二个参数,若查不到,则返回None
  8. 8. >>>
  • 判断树是否为空:is_empty().根据树数据的长度,如果数据长度为0,则为空。O(1)

看例子:

  1. 1. >>> ctree
  2. 2. BinaryTree({9: 'scree'})
  3. 3. >>> ctree.clear() #清空数据
  4. 4. >>> ctree
  5. 5. BinaryTree({})
  6. 6. >>> ctree.is_empty()
  7. 7. True
  8. 8. >>> btree
  9. 9. BinaryTree({2: 'phone', 7: 'computer', 9: 'scree', 'github': 'qiwsir'})
  10. 10. >>> btree.is_empty()
  11. 11. False
  • 根据key、value循环从树中取值:

.items([reverse])—按照(key,value)结构取值;
.keys([reverse])—key
.values([reverse])—value. O(n)
.iter_items(s,e[,reverse]—s,e是key的范围,也就是生成在某个范围内的key的迭代器 O(n) 看例子:

  1. 1. >>> btree
  2. 2. BinaryTree({2: 'phone', 7: 'computer', 9: 'scree', 'github': 'qiwsir'})
  3. 3. >>> for (k,v) in btree.items():
  4. 4. ... print k,v
  5. 5. ...
  6. 6. 2 phone
  7. 7. 7 computer
  8. 8. 9 scree
  9. 9. github qiwsir
  10. 10. >>> for k in btree.keys():
  11. 11. ... print k
  12. 12. ...
  13. 13. 2
  14. 14. 7
  15. 15. 9
  16. 16. github
  17. 17. >>> for v in btree.values():
  18. 18. ... print v
  19. 19. ...
  20. 20. phone
  21. 21. computer
  22. 22. scree
  23. 23. qiwsir
  24. 24. >>> for (k,v) in btree.items(reverse=True): #反序
  25. 25. ... print k,v
  26. 26. ...
  27. 27. github qiwsir
  28. 28. 9 scree
  29. 29. 7 computer
  30. 30. 2 phone
  31. 31. 32. >>> btree
  32. 33. BinaryTree({2: 'phone', 5: None, 7: 'computer', 8: 'eight', 9: 'scree', 'github': 'qiwsir'})
  33. 34. >>> for (k,v) in btree.iter_items(6,9): #要求迭代6<=key<9的键值对数据
  34. 35. ... print k,v
  35. 36. ...
  36. 37. 7 computer
  37. 38. 8 eight
  38. 39. >>>
  • 删除数据并返回该值:

.pop(key[,d]), 根据key删除树的数据,并返回该value,但是如果没有,并也指定了备选返回的d,则返回d,如果没有d,则报错;
.pop_item(),在树中随机选择(key,value)删除,并返回。 看例子:

  1. 1. >>> ctree = btree.copy()
  2. 2. >>> ctree
  3. 3. BinaryTree({2: 'phone', 7: 'computer', 9: 'scree', 'github': 'qiwsir'})
  4. 4. 5. >>> ctree.pop(2) #删除key=2的数据,返回其value
  5. 6. 'phone'
  6. 7. >>> ctree.pop(2) #删除一个不存在的key,报错
  7. 8. Traceback (most recent call last):
  8. 9. File "<stdin>", line 1, in <module>
  9. 10. File "/usr/local/lib/python2.7/site-packages/bintrees/abctree.py", line 350, in pop
  10. 11. value = self.get_value(key)
  11. 12. File "/usr/local/lib/python2.7/site-packages/bintrees/abctree.py", line 557, in get_value
  12. 13. raise KeyError(str(key))
  13. 14. KeyError: '2'
  14. 15. 16. >>> ctree.pop_item() #随机返回一个(key,value),并已删除之
  15. 17. (7, 'computer')
  16. 18. >>> ctree
  17. 19. BinaryTree({9: 'scree', 'github': 'qiwsir'})
  18. 20. 21. >>> ctree.pop(7,"sing") #如果没有,可以返回指定值
  19. 22. 'sing'
  • 查找数据,并返回value:.set_default(key[,d]),在树的数据中查找key,如果存在,则返回该value。如果不存在,当指定了d,则将该(key,d)添加到树内;当不指定d的时候,添加(key,None). O(log(n))

看例子:

  1. 1. >>> btree
  2. 2. BinaryTree({2: 'phone', 7: 'computer', 9: 'scree', 'github': 'qiwsir'})
  3. 3. >>> btree.set_default(7) #存在则返回
  4. 4. 'computer'
  5. 5. 6. >>> btree.set_default(8,"eight") #不存在,则返回后备指定值,并加入到树
  6. 7. 'eight'
  7. 8. >>> btree
  8. 9. BinaryTree({2: 'phone', 7: 'computer', 8: 'eight', 9: 'scree', 'github': 'qiwsir'})
  9. 10. 11. >>> btree.set_default(5) #如果不指定值,则会加入None
  10. 12. >>> btree
  11. 13. BinaryTree({2: 'phone', 5: None, 7: 'computer', 8: 'eight', 9: 'scree', 'github': 'qiwsir'})
  12. 14. 15. >>> btree.get(2) #注意,.get(key)与.set_default(key[,d])的区别
  13. 16. 'phone'
  14. 17. >>> btree.get(3,"mobile") #不存在的 key,返回但不增加到树
  15. 18. 'mobile'
  16. 19. >>> btree
  17. 20. BinaryTree({2: 'phone', 7: 'computer', 8: 'eight', 9: 'scree', 'github': 'qiwsir'})
  • 根据key删除值

.remove(key),删除(key,value)
.remove_items(keys),keys是一个key组成的list,逐个删除树中的对应数据 看例子:

  1. 1. >>> ctree
  2. 2. BinaryTree({2: 'phone', 5: None, 7: 'computer', 8: 'eight', 9: 'scree', 'github': 'qiwsir'})
  3. 3. >>> ctree.remove_items([5,6]) #key=6,不存在,报错
  4. 4. Traceback (most recent call last):
  5. 5. File "<stdin>", line 1, in <module>
  6. 6. File "/usr/local/lib/python2.7/site-packages/bintrees/abctree.py", line 271, in remove_items
  7. 7. self.remove(key)
  8. 8. File "/usr/local/lib/python2.7/site-packages/bintrees/bintree.py", line 124, in remove
  9. 9. raise KeyError(str(key))
  10. 10. KeyError: '6'
  11. 11. 12. >>> ctree
  12. 13. BinaryTree({2: 'phone', 7: 'computer', 8: 'eight', 9: 'scree', 'github': 'qiwsir'})
  13. 14. >>> ctree.remove_items([2,7,'github']) #按照 列表中顺序逐个删除
  14. 15. >>> ctree
  15. 16. BinaryTree({8: 'eight', 9: 'scree'})

以上只是入门的基本方法啦,还有更多内容,请移到文章开头的官方网站。


整理人:豆包AI助手