数据结构与算法:二叉树+堆
Posted deeplearning-man
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构与算法:二叉树+堆相关的知识,希望对你有一定的参考价值。
【二叉树】
1. 实现一个二叉查找树,并且支持插入、删除、查找操作
class Node: def __init__(self, data): self.data = data self.lchild = None self.rchild = None class BST: def __init__(self, node_list): self.root = Node(node_list[0]) for data in node_list[1:]: self.insert(data) # 查找 def search(self, node, parent, data): if node is None: return False, node, parent if node.data == data: return True, node, parent if node.data > data: return self.search(node.lchild, node, data) else: return self.search(node.rchild, node, data) # 插入 def insert(self, data): flag, n, p = self.search(self.root, self.root, data) if not flag: new_node = Node(data) if data > p.data: p.rchild = new_node else: p.lchild = new_node # 删除 def delete(self, root, data): flag, n, p = self.search(root, root, data) if flag is False: print "无该关键字,删除失败" else: if n.lchild is None: if n == p.lchild: p.lchild = n.rchild else: p.rchild = n.rchild del p elif n.rchild is None: if n == p.lchild: p.lchild = n.lchild else: p.rchild = n.lchild del p else: # 左右子树均不为空 pre = n.rchild if pre.lchild is None: n.data = pre.data n.rchild = pre.rchild del pre else: next = pre.lchild while next.lchild is not None: pre = next next = next.lchild n.data = next.data pre.lchild = next.rchild del p
2. 实现查找二叉查找树中某个节点的后继、前驱节点
class Solution: def GetNext(self, pNode): # write code here dummy = pNode #找到根节点 while dummy.next: dummy = dummy.next #中序遍历 ls = self.inorderTraversal(dummy) #找pNode所在索引的下一个 if ls.index(pNode) != (len(ls)-1): return ls[ls.index(pNode)+1] else: return None def GetBefore(self, pNode): # write code here dummy = pNode #找到根节点 while dummy.next: dummy = dummy.next #中序遍历 ls = self.inorderTraversal(dummy) #找pNode所在索引的下一个 if ls.index(pNode) != 0: return ls[ls.index(pNode)-1] else: return None def inorderTraversal(self, root): if root==None: return [] return self.inorderTraversal(root.left)+[root]+self.inorderTraversal(root.right)
3. 实现二叉树前、中、后序以及按层遍历
class Solution: def preorderTraversal(self, root: TreeNode) -> List[int]: if root==None: return [] return [root.val]+self.preorderTraversal(root.left)+self.preorderTraversal(root.right) def inorderTraversal(self, root: TreeNode) -> List[int]: if root==None: return [] return self.inorderTraversal(root.left)+[root.val]+self.inorderTraversal(root.right) def postorderTraversal(self, root: TreeNode) -> List[int]: if root==None: return [] return self.postorderTraversal(root.left)+self.postorderTraversal(root.right)+[root.val] def levelOrder(self, root: TreeNode) -> List[List[int]]: if not root: return [] result = [] queue = collections.deque() queue.append(root) while queue: level_size = len(queue) current_level = [] for _ in range(level_size): node = queue.popleft() current_level.append(node.val) if node.left: queue.append(node.left) if node.right: queue.append(node.right) result.append(current_level) return result
练习:
1. 翻转二叉树 https://leetcode-cn.com/problems/invert-binary-tree/
思路:递归
class Solution: def invertTree(self, root: TreeNode) -> TreeNode: if root == None: return None root.left, root.right = root.right, root.left self.invertTree(root.left) self.invertTree(root.right) return root
2. 二叉树的最大深度 https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/
思路:1. 深度优先搜索 2. 广度优先搜索
class Solution: def maxDepth(self, root: TreeNode) -> int: if root is None: return 0 ‘‘‘ #深度优先搜索+分治 return max(self.maxDepth(root.left), self.maxDepth(root.right))+1 ‘‘‘ ‘‘‘ #深度优先搜索+栈 self.ans = 0 self._dfs(root, 0) return self.ans def _dfs(self, node, level): if not node: return if self.ans < level + 1: self.ans = level + 1 self._dfs(node.left, level + 1) self._dfs(node.right, level + 1) ‘‘‘ #广度优先搜索+双端队列deque queue = collections.deque() queue.append(root) ans = 0 while queue: ans += 1 for _ in range(len(queue)): node = queue.popleft() if node.left: queue.append(node.left) if node.right: queue.append(node.right) return ans
3. 验证二叉查找树 [作为可选] https://leetcode-cn.com/problems/validate-binary-search-tree/
思路:递归
class Solution: def isValidBST(self, root: TreeNode) -> bool: #max(leftnode)<root #min(rightnode)>root return self.valid(root, float(‘-inf‘), float(‘inf‘)) def valid(self, root, min, max): if not root: return True if root.val >= max or root.val <= min: return False return self.valid(root.left, min, root.val) and self.valid(root.right, root.val, max)
【堆】
1. 实现一个小顶堆、大顶堆、优先级队列
class ZHeap: def __init__(self, item=[]): # 初始化。item为数组 self.items = item self.heapsize = len(self.items) def LEFT(self, i): return 2 * i + 1 def RIGHT(self, i): return 2 * i + 2 def PARENT(self, i): return (i - 1) / 2 def MIN_HEAPIFY(self, i): # 最小堆化:使以i为根的子树成为最小堆 l = self.LEFT(i) r = self.RIGHT(i) if l < self.heapsize and self.items[l] < self.items[i]: smallest = l else: smallest = i if r < self.heapsize and self.items[r] < self.items[smallest]: smallest = r if smallest != i: self.items[i], self.items[smallest] = self.items[smallest], self.items[i] self.MIN_HEAPIFY(smallest) def INSERT(self, val): # 插入一个值val,并且调整使满足堆结构 self.items.append(val) idx = len(self.items) - 1 parIdx = self.PARENT(idx) while parIdx >= 0: if self.items[parIdx] > self.items[idx]: self.items[parIdx], self.items[idx] = self.items[idx], self.items[parIdx] idx = parIdx parIdx = self.PARENT(parIdx) else: break self.heapsize += 1 def DELETE(self): last = len(self.items) - 1 if last < 0: # 堆为空 return None # else: self.items[0], self.items[last] = self.items[last], self.items[0] val = self.items.pop() self.heapsize -= 1 self.MIN_HEAPIFY(0) return val def BUILD_MIN_HEAP(self): # 建立最小堆, O(nlog(n)) i = self.PARENT(len(self.items) - 1) while i >= 0: self.MIN_HEAPIFY(i) i -= 1 def SHOW(self): print self.items class ZPriorityQ(ZHeap): def __init__(self, item=[]): ZHeap.__init__(self, item) def enQ(self, val): ZHeap.INSERT(self, val) def deQ(self): val = ZHeap.DELETE(self) return val class MaxHeap: def __init__(self, data): data.insert(0, None) self.heap = data self.heapSize = 0 for i in range(1,len(self.heap)): self.heapSize += 1 self.__bubble(i) def __sink(self, pos): left, right = 2*pos, 2*pos+1 next = pos if left <= self.heapSize and self.compare(self.heap[left], self.heap[next]) > 0: next = left if right <= self.heapSize and self.compare(self.heap[right], self.heap[next]) > 0: next = right if next == pos: return self.__exchange(pos, next) return self.__sink(next) def __bubble(self, pos): # build if pos <= 1: return ppos = pos/2 if self.compare(self.heap[pos], self.heap[ppos]) > 0: self.__exchange(pos, ppos) return self.__bubble(ppos) def compare(self, a, b): return a - b def __exchange(self, i, j): temp = self.heap[i] self.heap[i] = self.heap[j] self.heap[j] = temp def sort(self): while self.heapSize > 1: self.__exchange(1, self.heapSize) self.heapSize -= 1 self.__sink(1) self.heap.remove(None) return self.heap
2. 实现堆排序
def sift_down(arr, start, end): root = start while True: # 从root开始对最大堆调整 child = 2 * root + 1 if child > end: break # 找出两个child中交大的一个 if child + 1 <= end and arr[child] < arr[child + 1]: child += 1 if arr[root] < arr[child]: # 最大堆小于较大的child, 交换顺序 arr[root], arr[child] = arr[child], arr[root] # 正在调整的节点设置为root root = child else: # 无需调整的时候, 退出 break def heap_sort(arr): # 从最后一个有子节点的孩子还是调整最大堆 first = len(arr) // 2 - 1 for start in range(first, -1, -1): sift_down(arr, start, len(arr) - 1) # 将最大的放到堆的最后一个, 堆-1, 继续调整排序 for end in range(len(arr) -1, 0, -1): arr[0], arr[end] = arr[end], arr[0] sift_down(arr, 0, end - 1)
3. 利用优先级队列合并 K 个有序数组
class Solution: def mergeKLists(self, lists): """ :type lists: List[ListNode] :rtype: ListNode """ heap = [] for ln in lists: if ln: heap.append((ln.val, ln)) dummy = ListNode(0) cur = dummy heapq.heapify(heap) while heap: valu, ln_index = heapq.heappop(heap) cur.next = ln_index cur = cur.next if ln_index.next: heapq.heappush(heap, (ln_index.next.val, ln_index.next)) return dummy.next
4. 求一组动态数据集合的最大 Top K
def findKthLargest(self, nums, k): import heapq return heapq.nlargest(k, nums)[-1]
练习:
路径总和 https://leetcode-cn.com/problems/path-sum/
思路:递归
class Solution: def hasPathSum(self, root: TreeNode, sum: int) -> bool: if root is None: return False if root.val == sum and root.left is None and root.right is None: return True else: return self.hasPathSum(root.right, sum-root.val) or self.hasPathSum(root.left, sum-root.val)
以上是关于数据结构与算法:二叉树+堆的主要内容,如果未能解决你的问题,请参考以下文章