打牢地基-二叉樹、BST

章節

  • tree結構簡介
  • 二叉樹詳解
  • 二分搜索樹 – Binary Search Tree

1 tree結構簡介

tree-簡介

  1. tree 是非線性數據結構
  2. tree 是高效的

tree-高效性

2 二叉樹詳解

重新認識下tree

1. 和鏈表一樣,動態的數據結構  class Node {      E e;   Node left;   Node right;  }  2. 二叉樹具有唯一根節點  3. 二叉樹中每個節點最多有兩個孩子 - 左孩子 or 右孩子  4. 1個孩子都沒有的節點叫葉子節點  5. 二叉樹每個節點最多有一個父節點  6. 根節點沒有父節點  7. 二叉樹具有比鏈表更明顯的遞歸屬性   

二叉樹的天然遞歸屬性

一個節點有n個分叉- n叉樹

滿二叉樹

定義: 除了葉子節點,每個節點都有兩個孩子節點

二叉樹不一定是滿二叉樹

3 二分搜索樹 – Binary Search Tree

1. 二分搜索樹是二叉樹    2. 二分搜索樹每個節點的值:     大於其左子樹所有節點的值     小於其右子樹所有節點的值     左子樹(all node val) < cur node val < 右子樹(all node val)    3. 每一棵子樹也是二分搜索樹   

二分搜索樹-BTS 加速查詢過程的原因,假如根節點val = 28, 現在在查找 30 這個元素,因為BTS的存儲特性,只需要查找右子樹部分就可以了,大大提高了查詢的速度 有個細節,需要保證node的val 是可比較的,這是有局限性的

3.1 定義樹中節點-struct

class Node:     def __init__(self, e=None, left=None, right=None):            self.e = e            self.left = left            self.right = right   

節點結構體中 包含數據域 e, 左子樹引用 left, 右子樹引用right

3.2 定義BTS

class BST:     def __init__(self, root: Node = None):     """            根節點            :param root:            """            self._root = root            self._size = 0   

一棵樹包包含一個根節點root,以及node的個數 size

3.3 add(e)-遞歸新增一個節點數據

 def add(self, e):            self._root = self._add_element(self._root, e)           def _add_element(self, root, e):     """            遞歸構建二分搜索樹            :param root:            :param e:            :return:            """     if root is None:                self._size += 1     """                返回的是子樹根節點                """     return Node(e)     elif e < root.e:                root.left = self._add_element(root.left, e)     elif e > root.e:                root.right = self._add_element(root.right, e)     return root   

3.4 contains- 遞歸查詢樹中是否包含某個數據

 def contains(self, e):     return self._contains(self._root, e)     def _contains(self, _root, e):     if self._root is None:    return False     if self._root.e == e:     return True       if e < self._root.e:     return self._contains(self._root.left, e)     if e > self._root.e:     return self._contains(self._root.right, e)   

3.5 二分搜索樹的遍歷

3.5.1 前序遍歷 – 遞歸

def pre_order(self):     """            前序遍歷            :return:            """            self._pre_order(self._root)           def _pre_order(self, node):     if node is None:     return           print(node.e)                  self._pre_order(node.left)            self._pre_order(node.right)   

3.5.2 中序遍歷-遞歸

 def in_order(self):     """            中序遍歷,即是二分搜索樹從小到達排序的數據            :return:            """            self._in_order(self._root)           def _in_order(self, node):     if node is None:     return                  self._in_order(node.left)     print(node.e)            self._in_order(node.right)   

3.5.3 後序遍歷 post_order – 遞歸

 def post_order(self):     """            後續遍歷            :return:            """            self._post_order(self._root)           def _post_order(self, node):     if node is None:     return            self._post_order(node.left)            self._post_order(node.right)     print(node.e)   

3.5.4 前序遍歷 – 非遞歸算法(棧的應用)- DFS 深度優先遍歷

LinkedListStack-使用先前實現的鏈表棧

 def pre_order_nr(self):     """            前序遍歷-非遞歸,使用棧            :return:            """            stack = LinkedListStack()            stack.push(self._root)     while stack.is_empty() is False:                cur = stack.pop()     print(cur.e)     if cur.right is not None:                    stack.push(cur.right)     if cur.left is not None:                    stack.push(cur.left)   

3.5.5 二分搜索樹的層序遍歷-(隊列的應用) BFS (Breadth First Search)

LinkedListQueue-使用先前實現的鏈表隊列實現層序遍歷

 def level_order(self):     """            隊列實現中序遍歷 - 先進先出            :return:            """            queue = LinkedListQueue()            queue.enqueue(self._root)     while queue.is_empty() is False:                cur = queue.dequeue()     print(cur.e.e)     if cur.e.left is not None:                    queue.enqueue(cur.e.left)     if cur.e.right is not None:                    queue.enqueue(cur.e.right)   

編程的過程中會發現其實每一個節點都會被訪問3次。