数据结构与算法:二叉树+堆

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)

 

以上是关于数据结构与算法:二叉树+堆的主要内容,如果未能解决你的问题,请参考以下文章

数据结构与算法:树 堆排序

数据结构与算法:二叉树+堆

数据结构----二叉树(未写完)

初阶数据结构完全二叉树实现堆排序

初阶数据结构完全二叉树实现堆排序

初阶数据结构完全二叉树实现堆排序