二叉搜索树

定义:如果一颗二叉树的每个节点对应一个关键码值,且关键码值的组织是有顺序的,例如左子节点值小于父节点值,父节点值小于右子节点值,则这棵二叉树是一棵二叉搜索树。

类(TreeNode):定义二叉搜索树各个节点

在该类中,分别存放节点本身的值,以及其左子节点,右子节点,父节点的值。

  1. class TreeNode(object):
  2. def __init__(self,val):
  3. self.value = val #存值
  4. self.left = None #存本节点的左子节点
  5. self.right = None #存本节点的右子节点
  6. self.father = None #存本节点的父节点

  

类(BST):定义二叉搜索树的各种功能方法

此类用于存放定义二叉树的插入,删除,搜索等方法。

  1. class BST(object):
  2. def __init__(self,nodeList):
  3. self.root = None
  4. for node in nodeList:
  5. self.bfs_insert(node)

注:self.bfs_insert(node)中的bfs_insert方法在后面实现。放在构造函数中的目的是将一个列表生成一个二叉搜索树列表。

方法(bfs_insert):实现插入功能

第一步:将根节点(self.root)设置成当前位置节点(cur),即从根节点开始遍历。根节点的父节点(father)初始设置为None。

  1. def bfs_insert(self,node):
  2. cur = self.root #设置当前节点为根节点
  3. father = None #设置根节点的父节点为None

  

第二步:查找可以插入的位置

1. 当前位置节点(cur)的值与待插入节点(node)的值相等,返回-1(代表无法进行插入操作)。并将父节点(father)值修改为当前位置节点(cur),代表该节点已经遍历完成。

  1. if cur.value == node.value:
  2. return -1
  3. father = cur

  

2.当前位置节点(cur)的值大于待插入节点(node)的值时,表示待插入节点(node)需继续在当前位置节点的左子树中继续查找。故把当前位置节点(cur)的左节点赋值给当前位置节点(cur),作为下一个要访问的节点对象。

  1. if node.value < cur.value:
  2. cur = cur.left

  

3.当前位置节点(cur)的值小于待插入节点(node)的值时,表示待插入节点(node)需继续在当前位置节点的右子树中继续查找。故把当前位置节点(cur)的右节点赋值给当前位置节点(cur),作为下一个要访问的节点对象。

  1. if node.value > cur.value:
  2. cur = cur.right

  

第三步:找到插入位置后,将其设置为待插入值(node)的父节点

  1. node.father = father

  

第四步:插入操作

1.父节点的值为空(即要插入的是个空二叉树),将待插入节点(node)赋值给根节点(root)。

  1. if father == None:
  2. self.root = node

  

2.待插入节点(node)的值小于父节点(father)的值,将其放到父节点的左子节点

  1. if node.value <father.value:
  2. father.left = node

 

3.待插入节点(node)的值大于父节点(father)的值,将其放到父节点的右子节点

  1. if node.value >father.value:
  2. father.right = node

插入功能代码汇总:

  1. def insert(self,node):
  2. father = None
  3. cur = self.root
  4.  
  5. while cur != None:
  6. if cur.value == node.value:
  7. return -1
  8. father = cur
  9. if node.value < cur.value:
  10. cur = cur.left
  11. else:
  12. cur = cur.right
  13. node.father = father
  14. if father == None:
  15. self.root = node
  16. elif node.value < father.value:
  17. father.left = node
  18. else:
  19. father.right = node

  

方法(bfs):生成二叉搜索树列表

利用队列先进先出的特性,将一个二叉搜索树存放到列表中。

  1. def bfs(self):
  2. if self.root == None:
  3. return None
  4. retList = []
  5. q = queue.Queue()
  6. q.put(self.root)
  7. while q.empty() is not True:
  8. node = q.get()
  9. retList.append(node.value)
  10. if node.left != None:
  11. q.put(node.left)
  12. if node.right != None:
  13. q.put(node.right)
  14. return retList

示例:针对如下二叉搜索树,遍历存放到一个列表过程

ps:蓝色:二叉树列表 retList    橙色:队列 q

方法(bfs_search):实现查找功能

第一步:将根节点(self.root)设置成当前位置节点(cur),即从根节点开始遍历。

  1. def search(self,value):
  2. cur = self.root

如果cur值不为None,执行第二步。否则执行第三步

第二步:对比要查找的值(value)与当前位置节点(cur)的值的大小

1. 如果当前位置节点(cur)的值等于要查找的值(value),返回当前位置节点(cur)。

  1. if cur.value == value:
  2. return cur

2. 如果当前位置节点(cur)的值小于要查找的值(value),返回当前位置节点(cur)。

  1. if cur.value < value:
  2. cur = cur.right

3. 如果当前位置节点(cur)的值小于要查找的值(value),返回当前位置节点(cur)。

  1. if cur.value > value:
  2. cur = cur.left

第三步:如果cur的值为None,返回空。即查找的二叉搜索树为空树。

  1. return None

查找功能代码汇总:

  1. def search(self,value):
  2. cur = self.root
  3. while cur != None:
  4. if cur.value == value:
  5. return cur
  6. elif cur.value < value:
  7. cur = cur.right
  8. else:
  9. cur = cur.left
  10. return None

  

方法(bfs_delete):实现删除功能

第一步:将待删除节点(node)的父节点赋值给father变量。

  1. def delete(self,node):
  2. father = node.father

  

第二步:判断待删除节点(node)的左子树是否为空

1. 待删除节点(node)的左子树为空

  1. if node.left == None:

a)     待删除节点(node)为根节点

将待删除节点(node)的右子节点置为新的根节点(root),且其如果为非空,将其父节点(node.right.father)赋值为空。

  1. if father == None:
  2. self.root = node.right
  3. if node.right != None:
  4. node.right.father = None

b)     待删除节点(node)为其父节点的左子节点

待删除节点(node)的右子节点(node.right)取代其原来的位置,成为其父节点新的左子节点(father.left)。且其右子节点(node.right)不为空,将待删除节点(node)的父节点赋值给它的父节点(node.right.father)

  1. if father.left == node:
  2. father.left = node.right
  3. if node.right != None:
  4. node.right.father = father

 

c)     待删除节点(node)为其父节点的右子节点

待删除节点(node)的右子节点(node.right)取代其原来的位置,成为其父节点新的右子节点(father.right)。且其右子节点(node.right)不为空,将待删除节点(node)的父节点赋值给它的父节点(node.right.father)

  1. if father.right == node:
  2. father.right = node.right
  3. if node.right != None:
  4. node.right.father = father

2. 待删除节点(node)的左子树不为空

第一步:将待删除节点(node)的右子树挂到其左子树最后一层的右子节点下

a)     将待删除节点的左子节点(node.left)存到临时变量tmpNode中

  1. tmpNode = node.left

b)     递归找到node.left的最后一层右子节点

  1. while tmpNode.right != None:
  2. tmpNode = tmpNode.right

c)     将待删节点的右子树(node.right)挂到node.left的最后一层右子节点下

  1. tmpNode.right = node.right

d)     将node.right的父节点设置为待删节点左子树中的最后一层的右子节点

  1. if node.right != None:
  2. node.right.father = tmpNode

 

第二步:开始删除node

1.待删除节点为根节点

将待删除节点的左子节点(node.left)设置为根节点(self.root),并将其父节点设置为空。

  1. if father == None:
  2. self.root = node.left
  3. node.left.father = None

  

2.待删除节点为根节点的左子节点

待删除节点的左子节点(node.left)取代待删节点的位置,并将其父节点设置为待删除节点的父节点。

  1. if father.left == node:
  2. father.left = node.left
  3. node.left.father = father

3. 待删除节点为根节点的右子节点

待删除节点的左子节点(node.left)取代待删节点的位置,并将其父节点设置为待删除节点的父节点

  1. if father.right == node:
  2. father.right = node.left
  3. node.left.father = father

删除功能代码汇总:

  1. def delete(self,node):
  2. father = node.father
  3. if node.left == None:
  4. if father == None:
  5. self.root = node.right
  6. if node.right != None:
  7. node.right.father = None
  8. elif father.left == node:
  9. father.left = node.right
  10. if node.right != None:
  11. node.right.father = father
  12. else:
  13. father.right = node.right
  14. if node.right != None:
  15. node.right.father = father
  16. return 'delete successfully'
  17. tmpNode = node.left
  18. while tmpNode.right != None:
  19. tmpNode = tmpNode.right
  20.  
  21. tmpNode.right = node.right
  22. if node.right != None:
  23. node.right.father = tmpNode
  24.  
  25. if father == None:
  26. self.root = node.left
  27. node.left.father = None
  28. elif father.left == node:
  29. father.left = node.left
  30. node.left.father = father
  31. else:
  32. father.right = node.left
  33. node.left.father = father
  34. node = None
  35. return 'delete successfully'

 

综上,二叉搜索树代码

  1. # encoding=utf-8
  2. import queue
  3.  
  4. class TreeNode(object):
  5. def __init__(self,val):
  6. self.value = val
  7. self.left = None
  8. self.right = None
  9. self.father = None
  10.  
  11. class BST(object):
  12. def __init__(self,nodeList):
  13. self.root = None
  14. for node in nodeList:
  15. self.bfs_insert(node)
  16.  
  17. def bfs_insert(self,node):
  18. father = None
  19. cur = self.root
  20.  
  21. while cur != None:
  22. if cur.value == node.value:
  23. return -1
  24. father = cur
  25. if node.value < cur.value:
  26. cur = cur.left
  27. else:
  28. cur = cur.right
  29. node.father = father
  30. if father == None:
  31. self.root = node
  32. elif node.value < father.value:
  33. father.left = node
  34. else:
  35. father.right = node
  36.  
  37. def bfs(self):
  38. if self.root == None:
  39. return None
  40. retList = []
  41. q = queue.Queue()
  42. q.put(self.root)
  43. while q.empty() is not True:
  44. node = q.get()
  45. retList.append(node.value)
  46. if node.left != None:
  47. q.put(node.left)
  48. if node.right != None:
  49. q.put(node.right)
  50. return retList
  51.  
  52. def bfs_search(self,value):
  53. cur = self.root
  54. while cur != None:
  55. if cur.value == value:
  56. return cur
  57. elif cur.value < value:
  58. cur = cur.right
  59. else:
  60. cur = cur.left
  61. return None
  62.  
  63. def bfs_delete(self,node):
  64. father = node.father
  65. if node.left == None:
  66. if father == None:
  67. self.root = node.right
  68. if node.right != None:
  69. node.right.father = None
  70. elif father.left == node:
  71. father.left = node.right
  72. if node.right != None:
  73. node.right.father = father
  74. else:
  75. father.right = node.right
  76. if node.right != None:
  77. node.right.father = father
  78. return 'delete successfully'
  79. tmpNode = node.left
  80. while tmpNode.right != None:
  81. tmpNode = tmpNode.right
  82.  
  83. tmpNode.right = node.right
  84. if node.right != None:
  85. node.right.father = tmpNode
  86.  
  87. if father == None:
  88. self.root = node.left
  89. node.left.father = None
  90. elif father.left == node:
  91. father.left = node.left
  92. node.left.father = father
  93. else:
  94. father.right = node.left
  95. node.left.father = father
  96. node = None
  97. return 'delete successfully'
  98.  
  99. if __name__ == '__main__':
  100. varList = [24,34,5,4,8,23,45,35,28,6,29]
  101. nodeList = [TreeNode(var) for var in varList]
  102. bst = BST(nodeList)
  103. print (bst.bfs())
  104. node = bst.bfs_search(34)
  105. bst.bfs_delete(node)
  106. print (bst.bfs())

  

【算法】【python实现】二叉搜索树插入、删除、查找的更多相关文章

  1. Java与算法之(13) - 二叉搜索树

    查找是指在一批记录中找出满足指定条件的某一记录的过程,例如在数组{ 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 }中查找数字15,实现代码很简单 ...

  2. 看动画学算法之:平衡二叉搜索树AVL Tree

    目录 简介 AVL的特性 AVL的构建 AVL的搜索 AVL的插入 AVL的删除 简介 平衡二叉搜索树是一种特殊的二叉搜索树.为什么会有平衡二叉搜索树呢? 考虑一下二叉搜索树的特殊情况,如果一个二叉搜 ...

  3. 在二叉搜索树(BST)中查找第K个大的结点之非递归实现

    一个被广泛使用的面试题: 给定一个二叉搜索树,请找出其中的第K个大的结点. PS:我第一次在面试的时候被问到这个问题而且让我直接在白纸上写的时候,直接蒙圈了,因为没有刷题准备,所以就会有伤害.(面完的 ...

  4. 二叉搜索树(BST)的插入和删除递归实现

    思路 二叉搜索树的插入 TreeNode InsertRec(rootNode, key) = if rootNode == NULL, return new Node(key) if key > ...

  5. [数据结构]——二叉树(Binary Tree)、二叉搜索树(Binary Search Tree)及其衍生算法

    二叉树(Binary Tree)是最简单的树形数据结构,然而却十分精妙.其衍生出各种算法,以致于占据了数据结构的半壁江山.STL中大名顶顶的关联容器--集合(set).映射(map)便是使用二叉树实现 ...

  6. 二叉搜索树(BST)---python实现

    github:代码实现 本文算法均使用python3实现 1. 二叉搜索树定义   二叉搜索树(Binary Search Tree),又名二叉排序树(Binary Sort Tree).   二叉搜 ...

  7. LeetCode-450 二叉搜索树删除一个节点

    二叉搜索树 建树 删除节点,三种情况,递归处理.左右子树都存在,两种方法,一种找到左子树最大节点,赋值后递归删除.找右子树最小同理 class Solution { public: TreeNode* ...

  8. 二叉搜索树(Binary Search Tree)--C语言描述(转)

    图解二叉搜索树概念 二叉树呢,其实就是链表的一个二维形式,而二叉搜索树,就是一种特殊的二叉树,这种二叉树有个特点:对任意节点而言,左孩子(当然了,存在的话)的值总是小于本身,而右孩子(存在的话)的值总 ...

  9. 数据结构学习笔记_树(二叉搜索树,B-树,B+树,B*树)

    一.查找二叉树(二叉搜索树BST) 1.查找二叉树的性质 1).所有非叶子结点至多拥有两个儿子(Left和Right): 2).所有结点存储一个关键字: 3).非叶子结点的左指针指向小于其关键字的子树 ...

随机推荐

  1. C#中使用JavaScriptSerializer类实现序列化与反序列化

    1.添加引用 JavaScriptSerializer类的使用需要引用System.Web.Extensions.dll文件,根据路径:C:\Program Files (x86)\Reference ...

  2. Python——网络编程基础

    一.TCP/IP 是Internet的基础协议,分四层应用层(HTTP,SMTP),传输层(TCP/UDP),网络层(IP),接口层 二.常用默认端口号 80-TCP-HTTP 23-TCP-TELN ...

  3. Ubuntu 16.04安装MySQL(5.7.18)

    此篇为http://www.cnblogs.com/EasonJim/p/7139275.html的分支页. 安装MySQL前需要做如下了解: 1.MySQL各类型版本的区别,参考:http://ww ...

  4. Magento Meigee-Glam 主题的用法

    Start起点 Package Structure包装结构 License许可证 Installation安装 What's new Updated!更新了什么! Theme options主题选项 ...

  5. hive笔记

    cast cast(number as string),  可以将整数转成字符串 lpad  rpad lpad(target, 10, '0')   表示在target字符串前面补0,构成一个长度为 ...

  6. 【Sql Server】SQL SERVER 收缩日志

    事务日志记录着在相关数据库上的操作,同时还存储数据库恢复(recovery)的相关信息. 收缩日志的原因有很多种,有些是考虑空间不足,有些则是应用程序限制导致的. 下面介绍的是在简单模式下,进行收缩操 ...

  7. LFYZ-OJ ID: 1008 求A/B高精度值

    思路 小数点前的部分可以通过m/n直接计算得出 小数点后的20位可通过循环进行快速计算,计算方法如下: m%=n m*=10 小数点后第i位为m/n,回到第1步 第3步后,如果m%n为0,说明已经除净 ...

  8. java代码调用第三方接口

    一.利用httpclient来字符串参数(url是第三方接口,不带参数,如:http://192.168.16.200:8081/faceInfo/list,param是url后面所要带的参数) pu ...

  9. 15、解决14中csv用excel打开乱码的问题 open('zhihu.csv','w',newline='',encoding='utf-8-sig')

    解决14中csv用excel打开乱码的问题 ,其实就是在写csv的时候把 utf-8 改成 utf-8-sig open('zhihu.csv','w',newline='',encoding='ut ...

  10. 我的 Erdos 数是 4

    我的 Erdos 数是 4. 呵呵. 图书馆开通了一个月的 mathscinet 数据库查询. 本来想买个 pde 的最新进展, 结果不能查询, 就算了.