数据结构课程:树和堆

二叉树基础:

  • 树的定义:树(英语:Tree)是一种无向图(undirected graph),其中任意两个顶点间存在唯一一条路径。或者说,只要没有回路的连通图就是树。
  • 二叉树(英语:Binary tree)是每个节点最多只有两个分支(不存在分支度大于2的节点)的树结构。通常分支被称作“左子树”和“右子树”。二叉树的分支具有左右次序,不能颠倒。
  • 完全二叉树:叶节点只能出现在最下层和次下层,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树。
  • 平衡二叉树:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
  • 树的应用
        快速数据检索:①STL的红黑树;②数据库的B+树;
        文档结构组织:DOM
        人工智能:决策树
        游戏:通过构造空间树实现快速碰撞检测(https://www.zhihu.com/question/25111128)
        区块链的默克尔树

常用算法:   

  •  递归:树的深度优先遍历(以前序遍历为例)

    模拟遍历如下二叉树:

  • 队列:树的广度优先遍历(分层遍历):

leetcode例题

94.题目:给定一个二叉树,返回它的中序 遍历。

示例:

输入: [1,null,2,3]
   1
    \
     2
    /
   3

输出: [1,3,2]

解法

扫描二维码关注公众号,回复: 10615560 查看本文章

一、递归法:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def __init__(self):
        self.ret=[]
        
    def inorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        if root is not None:
            self.inorderTraversal(root.left)
            self.ret.append(root.val)
            self.inorderTraversal(root.right)
        return self.ret

二、非递归:

def loopVersion(self, root):    # 非递归版本
        ret, stack = [], []
        #如果root不为空或者堆栈有元素:
        while root or stack:
            #1.root不为空,root压入堆栈
            while root:
                stack.append(root)
                #2.root=root.left
                root = root.left
                #3.回到1
            #4.如果堆栈有元素
            if stack:
                #5.弹出元素,加入返回队列
                root = stack.pop()
                ret.append(root.val)
                #6.root=root.left继续while循环
                root = root.right
        return ret

106.题目:根据一棵树的中序遍历与后序遍历构造二叉树。

注意:
你可以假设树中没有重复的元素。

例如,给出

中序遍历 inorder = [9,3,15,20,7]
后序遍历 postorder = [9,15,7,20,3]

返回如下的二叉树:

    3
   / \
  9  20
    /  \
   15   7

解法

class Solution:
    """
    @param inorder : A list of integers that inorder traversal of a tree
    @param postorder : A list of integers that postorder traversal of a tree
    @return : Root of a tree
    """
    def buildTree(self, inorder, postorder):
        # write your code here
        return self._buildTree(inorder, 0, len(inorder), postorder, 0, len(postorder))

    def _buildTree(self, inorder, in_start, in_end, postorder, post_start, post_end):
        if in_start >= in_end:
            return None
        i = in_start
        while i < in_end:
            if inorder[i] == postorder[post_end -1]:    # 找到根节点
                break
            i += 1
        root = TreeNode(inorder[i])
        left_len = i - in_start # 左子树元素数量
        root.left = self._buildTree(inorder, in_start, i, postorder, post_start, post_start + left_len)
        root.right = self._buildTree(inorder, i + 1, in_end, postorder, post_start + left_len, post_end - 1)

226. 翻转二叉树

示例:

输入:

     4
   /   \
  2     7
 / \   / \
1   3 6   9

输出:

     4
   /   \
  7     2
 / \   / \
9   6 3   1

解法:递归法与中序遍历相似

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def invertTree(self, root):
        """
        :type root: TreeNode
        :rtype: TreeNode
        """
        if root is not None:
            root.left,root.right = root.right,root.left
            self.invertTree(root.left)
            self.invertTree(root.right)
        return root

堆的基础知识:

  • 堆的定义(from Wiki):堆的实现通过构造二叉堆(binary heap),实为二叉树的一种;由于其应用的普遍性,当不加限定时,均指该数据结构的这种实现。这种数据结构具有以下性质:
    ①任意节点小于(或大于)它的所有后裔,最小元或最大元)在堆的根上(堆序性)。
    ②堆总是一棵完全树。即除了最底层,其他层的节点都被元素填满,且最底层尽可能地从左到右填入。
  • 建堆的过程:

  • 建堆的复杂度分析:
    N个节点的堆高度最大为h=logN,最下面一层非叶子节点最多调整1次,倒数第2层最多2次,…依此类推,根节点最多需要h次。
    ②最下面一层子节点共有2^(h-1)个,倒数第2层有2^(h-2)个,…依此类推,根节点有2^(h-h)个1个。
    ③所以总的时间复杂度为1^(h-1) + 2*2^(h-2) + (h-1)*2 + h,得到结果为N*2 –2 –log(N),所以时间复杂度O(n)。
  • 堆的应用

leetcode例题

题目:堆化

给出一个整数数组,堆化操作就是把它变成一个最小堆数组。

对于堆数组A,A[0]是堆的根,并对于每个A[i],A [i * 2 + 1]是A[i]的左儿子并且A[i * 2 + 2]是A[i]的右儿子。

您在真实的面试中是否遇到过这个题?  是

题目纠错

说明

什么是堆?

  • 堆是一种数据结构,它通常有三种方法:push, pop 和 top。其中,“push”添加新的元素进入堆,“pop”删除堆中最小/最大元素,“top”返回堆中最小/最大元素。

什么是堆化?

  • 把一个无序整数数组变成一个堆数组。如果是最小堆,每个元素A[i],我们将得到A[i * 2 + 1] >= A[i]和A[i * 2 + 2] >= A[i]

如果有很多种堆化的结果?

  • 返回其中任何一个。

样例

给出 [3,2,1,4,5],返回[1,2,3,4,5] 或者任何一个合法的堆数组

挑战

O(n)的时间复杂度完成堆化

解法

class Solution:
    """
    @param: A: Given an integer array
    @return: nothing
    """
    def heapify(self, A):
        # write your code here
        for i in range(int((len(A)-1)/2),-1,-1):
            while i < len(A):
                left,right = i*2+1,i*2+2
                min_pos = i
                if (left<len(A)) and (A[left]<A[min_pos]):
                    min_pos=left
                if (right<len(A)) and (A[right]<A[min_pos]):
                    min_pos=right
                if min_pos!=i:
                    A[i],A[min_pos]=A[min_pos],A[i]
                    i = min_pos
                else:
                    break

23. 合并K个排序链表

合并 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。

示例:

输入:
[
  1->4->5,
  1->3->4,
  2->6
]
输出: 1->1->2->3->4->4->5->6

解法:这是别人写的一个解法,我自己没做出来

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def mergeKLists(self, lists):
        """
        :type lists: List[ListNode]
        :rtype: ListNode
        """
        k=len(lists)
        if k==0:
            return []
        if k==1:
            return lists[0]
        combine_list=lists[0]
        aim_list=ListNode(0)
        for i in range(1,k):
            pointer_aim_list=aim_list
            list_1=combine_list
            #list_2=lists[i]
            pointer_list_2=lists[i]
            pointer_list_1=list_1
            while pointer_list_1!=None or pointer_list_2!=None:
                if pointer_list_1==None:
                    pointer_aim_list.next=pointer_list_2
                    break
                if pointer_list_2==None:
                    pointer_aim_list.next=pointer_list_1
                    break
                if pointer_list_1.val<=pointer_list_2.val:
                    pointer_aim_list.next=pointer_list_1
                    pointer_list_1=pointer_list_1.next
                    pointer_aim_list=pointer_aim_list.next
                else:
                    pointer_aim_list.next=pointer_list_2
                    pointer_list_2=pointer_list_2.next
                    pointer_aim_list=pointer_aim_list.next
            combine_list=aim_list.next        
            #aim_list=aim_list.next
                    
        return aim_list.next

这是另一种,速度更快

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def less(self, a, b):
        if a.val < b.val:
            return a
        else:
            return b

    def mergeTwoLists(self, l1, l2):

        l3 = ListNode(0)
        rl3 = l3

        while l1 or l2:

            if not l1 or not l2:
                l3.next = l1 if l1 else l2
                break

            l3.next = self.less(l1, l2)
            if l3.next == l1:
                l1 = l1.next
            else:
                l2 = l2.next

            l3 = l3.next

        return rl3.next

    def mergeKLists(self, lists):

        half = int(len(lists)/2)
        left = lists[0:half]
        right = lists[half:]

        if 0 <= len(left) <= 1 and 0 <= len(right) <= 1:
            return self.mergeTwoLists(left[0] if left else [], right[0] if right else [])

        return self.mergeTwoLists(self.mergeKLists(left), self.mergeKLists(right))

To be continue......

发布了67 篇原创文章 · 获赞 16 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/weixin_42446330/article/details/85703287