二叉搜索树

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

类(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. Linux下修改MySQL数据表中字段属性

    一.修改某个表的字段类型及指定为空或非空 alter table 表名称 change 字段名称 字段名称 字段类型 [是否允许非空]; alter table 表名称 modify 字段名称 字段类 ...

  2. python批量修改linux主机密码

    +++++++++++++++++++++++++++++++++++++++++++标题:python批量修改Linux服务器密码时间:2019年2月24日内容:基于python实现批量修改linu ...

  3. 更改电脑名称后, Cnario无法播放画面和声音, 开机后停留在桌面, Cnario Player软件界面的停止按钮为蓝色可选状态

    症状描述 Cnario Player正常工作期间, 更改了电脑的Windows系统计算机名称(不是登录Windows的用户名), 重启后, 新计算机名生效. 此时Cnario自动启动, 但没有进入播放 ...

  4. win10设置操作备忘

    添加密码, 更改密码: Win键-->左侧用户图标-->更改帐户设置-->登陆选项-->添加密码 | 更改密码

  5. wepy项目创建

    全局安装wepy npm install wepy-cli -g 创建项目 wepy init standard mywepy 安装依赖 npm install 实时编译 wepy build --w ...

  6. Python量化交易

    资料整理: 1.python量化的一个github 代码 2.原理 + python基础 讲解 3.目前发现不错的两个量化交易 学习平台: 聚宽和优矿在量化交易都是在15年线上布局的,聚宽是15年的新 ...

  7. fiddler软件测试——Fiddler抓取https设置详解(图文)(摘抄)

    随笔- 8  文章- 0  评论- 0 fiddler软件测试——Fiddler抓取https设置详解(图文)   强烈推荐(原创亲测)!!!Fiddler抓取https设置详解(图文)转 本文主要说 ...

  8. wrk编译报错gcc: Command not found

    报错信息如下: 问题原因:没有安装gcc 解决办法: yum -y install gcc+ gcc-c++ 若需升级gcc,则采用如下命令: yum -y update gcc

  9. 第六十三天 js基础

    一.JS三个组成部分 ES:ECMAScript语法 DOM:document对象模型=>通过js代码与页面文档(出现在body中的所有可视化标签)进行交互 BOM:borwser对象模型=&g ...

  10. [NOIp2016] 换教室

    题目类型:期望\(DP\) 传送门:>Here< 题意:现有\(N\)个时间段,每个时间段上一节课.如果不申请换教室,那么时间段\(i\)必须去教室\(c[i]\)上课,如果申请换课成功, ...