数据结构经典面试题-树

本系列针对面试中【经典】算法题进行分类和汇总,每篇包含两部分:基础知识和经典题目。

本文的主角是【树】。

本文结构:

  1. 面试前必须知道的[树]的基础知识。

  2. [树]的经典手写编程题。

基础知识

基础概念

img

基础性质

img

经典面试题

  • 二叉树以及二叉搜索树初始化
class Node():
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Tree():
    def __init__(self):
        self.root = None

    def rand_tree(self, x): #普通二叉树构建
        node = Node(x)
        if not self.root:
            self.root = node
            return
        temp = [self.root]
        while True:
            p = temp.pop(0)
            if not p.left:
                p.left = node 
                return
            elif not p.right:
                p.right = node 
                return 
            temp.append(p.left)
            temp.append(p.right)

    def sort_tree(self, x): #搜索二叉树构建
        node = Node(x)
        if not self.root:
            self.root = node
            return 
        p = self.root
        while True:
            if x<p.val:
                if not p.left:
                    p.left = node 
                    return 
                p = p.left
            elif x>=p.val:
                if not p.right:
                    p.right = node
                    return
                p = p.right
  • 层次遍历
def traverse(root):
    if not root:
        return
    temp = [root]
    res = []
    while temp:
        p = temp.pop(0)
        res.append(p.val)
        if p.left:
            temp.append(p.left)
        if p.right:
            temp.append(p.right)
    return res
  • 前序遍历
#递归版
def preoder_recursion(root):
    if not root:
        return []
    left = preoder_recursion(root.left)
    res = [root.val]
    right = preoder_recursion(root.right)
    return res+left+right

#非递归版
def preorder(root):
    if not root:
        return
    res = []
    temp = [root]
    while temp:
        while temp[-1]:
            res.append(temp[-1].val)
            temp.append(temp[-1].left)
        temp.pop()
        if temp:
            p = temp.pop()
            temp.append(p.right)
    return res
  • 中序遍历
#递归版
def inorder_recursion(root):
    if not root:
        return []
    left = inorder_recursion(root.left)
    res = [root.val]
    right = inorder_recursion(root.right)
    return left+res+right   

#非递归
def inorder(root):
    if not root:
        return 
    res = []
    temp = [root]
    while temp:
        while temp[-1]:
            temp.append(temp[-1].left)
        temp.pop()
        if temp:
            p = temp.pop()
            res.append(p.val)
            temp.append(p.right)
    return res 
  • 后续遍历
#递归版
def postorder_recursion(root):
    if not root:
        return []
    left = postorder_recursion(root.left)
    res = [root.val]
    right = postorder_recursion(root.right)
    return left+right+res 

#非递归版
def postorder(root):
    if not root:
        return
    res = []
    temp = [root]
    while temp:
        while temp[-1]:
            p = temp[-1]
            if p.right:
                temp.append(None)  #用None作为分隔
                temp.append(p.right)
            else:
                temp.append(p.right)
            temp.append(p.left)
        temp.pop()
        if temp:
            if not temp[-1]:
                temp.pop()
                res.append(temp.pop().val)
            else:
                res.append(temp.pop().val)
    return res
  • 重建二叉树

pre = [3,0,1,2,6,5,4,8,7,9]
mid = [0,1,2,3,4,5,6,7,8,9]
pos = [2,1,0,4,5,7,9,8,6,3]
要求不含重复数字,对于根据后序和前序遍历重建二叉树要求二叉树是搜索二叉树,不然结构不确定。

#根据前序和中序遍历
def reconstruct_1(pre, mid):
    if len(pre)==0:
        return None
    elif len(pre)==1:
        return Node(pre[0])
    root = mid.index(pre[0])
    flag = Node(pre[0])
    flag.left = reconstruct_1(pre[1:root+1], mid[:root])
    flag.right = reconstruct_1(pre[root+1:], mid[root+1:])
    return flag

#根据后序和中序遍历
def reconstruct_2(pos, mid):
    if len(pos)==0:
        return None
    elif len(pos)==1:
        return Node(pos[0])
    root = mid.index(pos[-1])
    flag = Node(pos[-1])
    flag.left = reconstruct_2(pos[:root], mid[:root])
    flag.right = reconstruct_2(pos[root:-1], mid[root+1:])
    return flag

#根据前序和后序遍历
def reconstruct_3(pre, pos):
    print(pre)
    print(pos)
    if len(pos)==0:
        return None
    elif len(pos)==1:
        return Node(pos[0])
    index = pos.index(pre[1])
    flag = Node(pre[0])
    if index==len(pos)-2:
        if flag.val<pos[0]: #判断应该在左子树还是右子树,所以要求是二叉搜索树
            flag.right = reconstruct_3(pre[1:], pos[:-1])
        else:
            flag.left = reconstruct_3(pre[1:], pos[:-1])
    else:
        flag.left = reconstruct_3(pre[1:index+2], pos[:index+1])
        flag.right = reconstruct_3(pre[index+2:], pos[index+1:-1])
    return flag
  • 树的子结构

输入两棵二叉树A,B,判断B是不是A的子结构。(我们约定空树不是任意一个树的子结构)。

class Solution:
    def HasSubtree(self, pRoot1, pRoot2):
        # write code here
        if not pRoot1 or not pRoot2:
            return False
        return self.is_subtree(pRoot1, pRoot2) or self.HasSubtree(pRoot1.left, pRoot2) or self.HasSubtree(pRoot1.right, pRoot2)

    def is_subtree(self, a, b):
        if not b:
            return True
        if not a or a.val != b.val:
            return False
        return self.is_subtree(a.left, b.left) and self.is_subtree(a.right, b.right)
  • 二叉树的镜像

将给定的二叉树变换为其镜像。

class Solution():
    def Mirror(self, root):
        if not root:
            return 
        if not root.left and not root.right:
            return 
        root.left, root.right = root.right, root.left
        self.Mirror(root.left)
        self.Mirror(root.right)
        return root
  • 二叉树中和为某一值的路径

输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)

class Solution():
    def FindPath(self, root, expectNumber):
        if not root:
            return []
        if not root.left and not root.right and root.val==expectNumber:
            return [[root.val]]
        res = []
        left = self.FindPath(root.left, expectNumber-root.val)
        right = self.FindPath(root.right, expectNumber-root.val)
        for i in left+right:
            res.append([root.val]+i)
        return res 
  • 二叉搜索树与双向链表

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

class Solution:
    def __init__(self):
        self.listHead = None
        self.listTail = None
    def Convert(self, pRootOfTree):
        if not pRootOfTree:
            return
        self.Convert(pRootOfTree.left)
        if not self.listHead:
            self.listHead = pRootOfTree
            self.listTail = pRootOfTree
        else:
            self.listTail.right = pRootOfTree
            pRootOfTree.left = self.listTail
            self.listTail = pRootOfTree
        self.Convert(pRootOfTree.right)
        return self.listHead
  • 二叉树的深度
#递归版
class Solution():
    def TreeDepth(self, pRoot):
        if not pRoot:
            return 0
        left = self.TreeDepth(pRoot.left)
        right = self.TreeDepth(pRoot.right)
        return left+1 if left>right else right+1

#循环版
    def TreeDepth(self, pRoot):
        if not pRoot:
            return 0
        p = [pRoot]
        last = p[-1]
        layer = 0
        while p:
            p1 = p.pop(0)
            if p1.left:
                p.append(p1.left)
            if p1.right:
                p.append(p1.right)
            if p1==last:
                layer += 1
                if p:
                    last = p[-1]
        return layer
  • 平衡二叉树

输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左、右子树的深度相差不超过1,那么它就是平衡二叉树。

class Solution:
    def IsBalanced_Solution(self, pRoot):
        if not pRoot:
            return True
        if abs(self.TreeDepth(pRoot.left)-self.TreeDepth(pRoot.right))>1:
            return False
        return self.IsBalanced_Solution(pRoot.left) and self.IsBalanced_Solution(pRoot.right)

    def TreeDepth(self, pRoot):
        if not pRoot:
            return 0
        left = self.TreeDepth(pRoot.left)
        right = self.TreeDepth(pRoot.right)
        return max(left+1, right+1)
  • 二叉树的下一个结点

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

class TreeLinkNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
        self.next = None

class Solution: 
    def GetNext(self, pNode):
        if not pNode:
            return None
        if pNode.right:
            p = pNode.right
            while p.left:
                p = p.left
            return p 
        else:
            while pNode.next:
                if pNode.next.left==pNode:
                    return pNode.next
                pNode = pNode.next 
        return None
  • 对称的二叉树

请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
(1)如果左右子树有一个为空,那么该二叉树肯定不是对称二叉树
(2)如果左右子树均不为空,但是节点的值不同,那么该二叉树肯定不是对称二叉树

class Solution:
#对称比较方法,其实也就是前序和镜像前序遍历比较的方法,和下面的对称遍历方法一个意思
    def isSymmetrical(self, pRoot):
        if not pRoot:
            return True
        if (pRoot.left and not pRoot.right) or (pRoot.right and not pRoot.left):
            return False
        return self.iSame(pRoot.left, pRoot.right)
    def iSame(self, p1, p2):
        if not p1 and not p2:
            return True
        if not p1 or not p2 or (p1.val!=p2.val):
            return False
        return self.iSame(p1.left, p2.right) and self.iSame(p1.right, p2.left)

#对称遍历方法(先存储后比较)
    def isSymmetrical(self, pRoot):
        if not pRoot:
            return True
        if (pRoot.left and not pRoot.right) or (pRoot.right and not pRoot.left):
            return False
        return self.preorder(pRoot) == self.preorder_n(pRoot)

    def preorder(self, pRoot):
        if not pRoot:
            return [None]
        left = self.preorder(pRoot.left)
        right = self.preorder(pRoot.right)
        return [pRoot.val]+left+right

    def preorder_n(self, pRoot):
        if not pRoot:
            return [None]      
        left = self.preorder_n(pRoot.left)    
        right = self.preorder_n(pRoot.right)    
        return [pRoot.val]+right+left
  • 按之字形顺序打印二叉树

请实现一个函数按照之字形打印二叉树,即第一层按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三层按照从左到右的顺序打印,其他行以此类推。

class Solution:
    def Print(self, pRoot):
        if not pRoot:
            return []
        res = []
        res_1 = []
        temp = [pRoot]
        left_to_right = 1
        last = temp[-1]
        while temp:
            p = temp.pop(0)
            res_1.append(p.val)
            if p.left:
                temp.append(p.left)
            if p.right:
                temp.append(p.right)
            if p==last:
                res.append(res_1 if left_to_right else res_1[::-1])
                left_to_right = not left_to_right
                res_1 = []
                if temp:
                    last = temp[-1]
        return res 
  • 序列化二叉树

请实现两个函数,分别用来序列化和反序列化二叉树

class Solution:
    def Serialize(self, root):
        if not root:
            return '#,'
        s = str(root.val) + ','
        left = self.Serialize(root.left)
        right = self.Serialize(root.right)
        s += left + right
        return s 

    def Deserialize(self, s):
        list1 = s.split(',')
        return self.deserializeTree(list1)

    def deserializeTree(self, list1):
        if len(list1)<=0:
            return None
        val = list1.pop(0)
        root = None # 每次递归需要初始化,不然程序不知道是全局变量还是局部变量
        if val != '#':
            root = Node(int(val))
            root.left = self.deserializeTree(list1)
            root.right = self.deserializeTree(list1)
        return root
  • 二叉搜索树的第k个结点
class Solution:
    def KthNode(self, pRoot, k):
        if not pRoot:
            return None
        temp = [pRoot]
        res = []
        while temp:
            while temp[-1]:
                temp.append(temp[-1].left)
            temp.pop()
            if temp:
                p = temp.pop()
                res.append(p)
                temp.append(p.right)
                if len(res)==k:
                    return res[-1]

在这里插入图片描述

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 把一个链表反向,递归,非递归都写一遍。 1.试编写3个函数实现   (1)建立一个双向链表   (2)插入一个节点   (3)删除一个节点 2.自己定义数据结构,写出程序:二叉的前序遍历。 3.实现双向链表删除一个节点P,在节点P后插入一个节点,写出这两个函数。 4.下面哪种排序法对12354最快 a quick sort b.buble sort c.merge sort 5.哪种结构,平均来讲,获取一个值最快 a. binary tree b. hash table c. stack 6.一个二叉的三种遍历方法的输出结果 7.链表按升序打印每打印完一个节点就将该节点从链表中删除 8.选择一种算法来整理出一个链接表。你为什么要选择这种方法?现在用o(n)时间来做。 9. 用一种算法在一个循环的链接表里插入一个节点,但不得穿越链接表。    10.给两个变量,如何找出一个带环单链表中是什么地方出现环的? 11.哈希表和数组的定义,区别,优缺点。 12.链接表和数组之间的区别是什么? 任选一门语言,当场定义二叉排序数据结构,写出两个函数:初始化,删除一个节点,20分钟 13. 递归的折半查找算法[不限语言] 14. 解释一下什么是B+,如何实现B+的查找和插入.(用图示) 15.实现双向链表删除一个节点P,在节点P后插入一个节点,写出这两个函数。 13.排序方法比较 (intel) 排序方法 平均时间 最坏时间 辅助存储 直接插入排序 O(N2) O(N2) O(1) 起泡排序 O(N2) O(N2) O(1) 快速排序 O(Nlog2N) O(N2) O(Nlog2N) 简单选择排序 O(N2) O(N2) O(1) 堆排序 O(Nlog2N) O(Nlog2N) O(1) 归并排序 O(Nlog2N) O(Nlog2N) O(n) 基数排序 O(d(n+radix)) O(d(n+radix)) O(radix) 17.一个链表的操作,注意代码的健壮和安全性。要求: (1)增加一个元素; (2)获得头元素; (3)弹出头元素(获得值并删除)。 18.内排序算法 19.折半查找的复杂度,证明 20.sizeof()和strlen()的使用. 21.顺序存储结构的优点,散列法的思想是什么? 22.汉罗塔算法,不能递归... 23.一个链表的结点结构 struct Node { int data ; Node *next ; }; typedef struct Node Node ; (1)已知链表的头结点head,写一个函数把这个链表逆序 ( Intel) (2)已知两个链表head1 和head2 各自有序,请把它们合并成一个链表 依然有序。 (3)已知两个链表head1 和head2 各自有序,请把它们合并成一个链表 依然有序,这次要求用递归方法进行。 ( Autodesk) 24.编最优化Bubble(int *pIntArray,int L),要求:交换元素不能用临时变量,如果有序需要最优。
### 回答1: CSND的数据结构面试往往涵盖了各种经典的问,需要在有限的时间内展示出自己的理论知识和解决问的能力。回答这类问时,通常需要从以下几个方面来展开回答。 首先,对于常见的数据结构,如数组、链表、栈、队列、、图等,需要了解它们的特性、操作以及常见的应用场景。这样一来,在面试中能够很好地判断使用何种数据结构,并理解其优缺点及适用范围。 其次,应对针对具体数据结构的问,我们应该熟悉并能够灵活运用各种操作和算法,如遍历、插入、删除、查找等。例如,对于链表,我们需要清楚如何反转链表、检测环、寻找中间节点等;对于,我们需要熟悉二叉的遍历方式,以及常见的二叉搜索的操作和平衡二叉的实现。 此外,还需了解常用的排序和查找算法,如快速排序、归并排序、二分查找等,并熟悉它们的时间复杂度和空间复杂度,以及在不同情况下的使用场景。 最后,面试官可能会要求我们在具体场景中应用数据结构来解决问,并分析算法的效率。在这种情况下,我们需要将问抽象成相应的数据结构,然后给出解决方案,并且合理解释算法的复杂度,并认真考虑算法的边缘情况。 总之,在面试过程中,要全面展示自己对于数据结构的理解和应用能力,同时要注重理论知识的掌握和实际问解决能力的展示,这样才能在数据结构面试中脱颖而出。 ### 回答2: 数据结构是计算机科学中的重要基础知识,面试中经常会涉及到相关问。以下是关于“数据结构面试”的回答。 数据结构面试通常包括以下内容:数组、链表、栈、队列、、图、哈希表等。对于数组,常见的问包括数组的查找、插入、删除操作,以及数组的有序性,如二分查找等。链表问包括链表的初始化、插入、删除操作,以及链表的环检测等。栈和队列问主要考察栈和队列的基本操作,如压栈、出栈、入队、出队等。 数据结构面试中的重点,包括二叉、平衡、二叉搜索等。常见问包括二叉的遍历(前序、中序、后序)、的深度和高度、的层次遍历等。对于图问,主要考察图的遍历(深度优先搜索、广度优先搜索)、最短路径问(Dijkstra算法、Floyd-Warshall算法)以及最小生成(Prim算法、Kruskal算法)等。哈希表问主要考察哈希函数的设计、哈希冲突的解决方法,以及哈希表的性能分析等。 在准备数据结构面试时,需要牢固掌握各种数据结构的基本操作,理解其原理和实现方式,并能够熟练应用到具体问中。另外,面试过程中还需要注重对算法的分析和优化思路的展示,展示自己对问的思考能力和解决能力。在回答问时要清晰表达自己的思路,思路清晰、逻辑严谨的回答更容易给面试官留下好印象。 最后,通过刷、模拟面试等多种方式来增强自己的实际操作能力和解决问的能力可以更好地应对数据结构面试。多练习、多总结可以提高自己的数据结构和算法水平,为面试打下坚实基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值