二叉搜索树

将有序数组转换为二叉搜索树

醉酒当歌 提交于 2020-04-08 14:04:16
题解思路: 二叉搜索树(Binary Search Tree)是指一棵空树或具有如下性质的二叉树: 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值 任意节点的左、右子树也分别为二叉搜索树 没有键值相等的节点 基于以上性质,我们可以得出一个二叉搜索树的特性:二叉搜索树的中序遍历结果为递增序列。 那么现在题目给了我们一个递增序列,要求我们构造一棵二叉搜索树,就是要我们实现这一特性的逆过程。 递归设计 函数作用:通过上述解题过程我们可以明确该问题的子问题是:构造树的每个节点以及该节点的左右子树。因此,递归函数的作用很明显: 选取要构造关系的节点并创建它 构造该节点的左子树 构造该节点的右子树 函数的输入为递增数组,函数的返回为完成构造的节点。 何时结束 当输入的递增数组为空时,只能构成一棵空树,此时返回空节点。 何时调用 当构造节点的左右子树时,对递增数组进行拆分并进行递归调用。 实现 Java /** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */

高度平衡的二叉搜索树(AVL树)

六眼飞鱼酱① 提交于 2020-04-08 13:52:16
  AVL树的基本概念   AVL树是一种 高度 平衡的(height balanced)二叉搜索树:对每一个结点x,x的左子树与右子树的高度差(平衡因子)至多为1。   有人也许要问:为什么要有AVL树呢?它有什么作用呢?   我们先来看看二叉搜索树吧(因为AVL树本质上是一棵二叉搜索树),假设有这么一种极端的情况:二叉搜索树结点的插入顺序为1,2,3,4,5,也就是:                        显而易见,这棵二叉搜索树已经其退化成一个链表了,也就是说,它在查找上的优势已经全无了—— 在这种情况下,查找一个结点的时间复杂度是O(n)!   如果这棵二叉搜索树是AVL树,在插入顺序仍为1,2,3,4,5的情况下,树的形状如下图:                      可以看出,AVL树基本操作的最坏时间复杂度要比普通的二叉搜索树低—— 除去可能的插入操作外(我们将假设懒惰删除),它是O(logn)。   而插入操作隐含着困难的原因在于,插入一个节点可能破坏AVL树的性质(例如,将6插入到上图的AVL树中会破坏根节点2的平衡条件),如果发生这种情况,就要在插入操作结束之前恢复平衡的性质。事实上,这总可以通过对树进行简单的修正来做到,我们称其为 旋转 。   AVL树的旋转   在AVL树中,假设有一个结点的平衡因子为2(最大就是2

树---二叉搜索树的第K个节点

谁说胖子不能爱 提交于 2020-04-07 09:46:30
给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。 分析:二叉搜索树就是每个节点X,大于其左子树的值,小于其右子树的值,其中序排序是递增的。使用中序遍历,每遍历一个节点,k-1,直到k减到1,即为第K小的节点 /* function TreeNode(x) { this.val = x; this.left = null; this.right = null; } */ function KthNode(pRoot, k) { if (pRoot === null || k === 0) { return null; } // 为了能追踪k,应该把KthNodeCore函数定义在这里面,k应该在KthNodeCore函数外面 function KthNodeCore(pRoot) { let target = null; if (pRoot.left !== null) { target = KthNodeCore(pRoot.left, k); } if (target === null) { if (k === 1) { target = pRoot; } k--; } if (target === null && pRoot.right !== null) { target =

[leetcode] 树(Ⅰ)

耗尽温柔 提交于 2020-04-05 20:21:53
均为 Simple 难度的水题。 二叉树的中序遍历 题目[94]:给定一个二叉树,返回它的 中序 遍历。 解题思路:Too simple. class Solution { public: vector<int> inorderTraversal(TreeNode *root) { return inorderNonRec(root); vector<int> v; innerTraversal(root, v); return v; } void innerTraversal(TreeNode *p, vector<int> &v) { if (p == nullptr) return; innerTraversal(p->left, v); v.push_back(p->val); innerTraversal(p->right, v); } vector<int> inorderNonRec(TreeNode *root) { vector<int> v; if (root != nullptr) { stack<TreeNode *> s; auto p = root; while (!s.empty() || p != nullptr) { if (p != nullptr) { s.push(p); p = p->left; } else { p = s.top(),

说说红黑树——不谈操作,只讲理解

旧巷老猫 提交于 2020-03-24 05:21:41
一、前言   这几天想学一学红黑树这种数据结构,于是上网找了很多篇博客,初看吓了一跳,红黑树竟然如此复杂。连续看了几篇博客后,算是对红黑树有了一些了解,但是它的原理却并不是特别理解。网上的博客,千篇一律的都是在叙述红黑树的操作,如何插入节点、删除节点,旋转、变色等,只关注如何正确构建一棵红黑树,但是却很少提及为什么这么做。这篇博客我就来记录一些我所知道的红黑树中比较重要的东西,以及谈一谈我的理解。   我不会描述红黑树的具体实现,因为阅读红黑树具体实现的过程中,我发现这真的不是很重要,没有太大的意义(这绝对不是自我安慰⊙﹏⊙∥),真正重要的是红黑树的思想。如果想要了解红黑树的具体实现,建议阅读这篇文章: https://mp.weixin.qq.com/s/hGHJonK999TAVJakPDNAkg 二、正文   2.1 二叉搜索树和平衡二叉树   在谈二叉红黑树之前,先来说一说二叉搜索树以及平衡二叉树,因为平衡二叉树是为了弥补二叉搜索树而发明出来的,而红黑树又是为了弥补平衡二叉树。   (1)二叉搜索树   二叉搜索树比较简单,它是一棵二叉树,而且满足这样一个性质: 对于树上的每一个节点,它左子树上的节点的值都比它小,而右子树上的节点的值都比它大 。如下,就是一棵二叉搜索树:   当我们需要往一棵二叉搜索树中插入节点时,只需要从根节点开始,依次比较,若比根节点小,则向左走

二叉搜索树与双向链表

て烟熏妆下的殇ゞ 提交于 2020-03-23 17:21:25
1:题目描述 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。 为了让您更好地理解问题,以下面的二叉搜索树为例: 我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。 下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。 特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/er-cha-sou-suo-shu-yu-shuang-xiang-lian-biao-lcof 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 2:题目分析 解题思路:对于二叉排序树而言,其中序遍历输出就是升序排序。那我们怎么将其做成双向链表尼?着手点肯定是中序遍历;在遍历的迭代逻辑中,我们要将前次迭代和本次迭代处理的节点,按照双向链表的要求进行处理。怎么处理尼?通过一个全局变量保存上次遍历的节点,然后再本次遍历的节点处理中进行如下操作: preNode.right =

数据结构——树的相关概念

强颜欢笑 提交于 2020-03-21 12:58:05
平衡二叉树和二叉查找树 至多有两个子节点的树成为二叉树 1)平衡二叉树 1)树的左右高度差不能超过1. 2)任何往下递归的左子树和右子树,必须符合第一条性质 3)没有任何节点的空树或只有跟节点的树也是平衡二叉树 树的节点Node是key value的形式。因为key可能不连续,甚至不是整数,所以我们没办法使用数组来表示,这个时候我们就可以用二叉查找树来实现 2)二叉查找树 树如其名,二叉查找树非常擅长数据查找。 二叉查找树额外增加了如下要求:它的左子树上所有节点的值都小于它,而它的右子树上所有节点的值都大于它。 查找的过程从树的根节点开始,沿着简单的判断向下走,小于节点值的往左边走,大于节点值的往右边走,直到找到目标数据或者到达叶子节点还未找到。 通常设计Node节点来表示key value这样的数据对 二叉查找树的insert package bobo.algo; // 二分搜索树 // 由于Key需要能够进行比较,所以需要extends Comparable<Key> public class BST<Key extends Comparable<Key>, Value> { // 树中的节点为私有的类, 外界不需要了解二分搜索树节点的具体实现 private class Node { private Key key; private Value value; private

Leetcode 98题验证二叉搜索树(Validate Binary Search Tree) Java语言求解

一曲冷凌霜 提交于 2020-03-20 08:45:59
题目链接 https://leetcode-cn.com/problems/validate-binary-search-tree/ 题目内容 给定一个二叉树,判断其是否是一个有效的二叉搜索树。 假设一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数。 节点的右子树只包含大于当前节点的数。 所有左子树和右子树自身必须也是二叉搜索树。 给出两个案例,如图: 分析 二叉搜索树的特点有: 当前节点的左子树的所有节点的值都应该小于当前节点的值; 当前节点的右子树的所有节点的值都应该大于当前节点的值。 为了简便,我们可以这么做: 如果当前节点是空节点,直接返回true; 如果当前节点不是空节点,那么判断当前节点是否在最小值和最大值之间,如果不是返回false,如果是则递归的对当前节点的左子树和右子树进行判断。 代码 /** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public boolean isValidBST(TreeNode root) { return isValidBST

leetcode-96.-不同的二叉搜索树

丶灬走出姿态 提交于 2020-03-18 12:20:53
描述 给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种? 示例: 输入: 3 输出: 5 解释: 给定 n = 3, 一共有 5 种不同结构的二叉搜索树: 1 3 3 2 1 \ / / / \ \ 3 2 1 1 3 2 / / \ \ 2 1 2 3 解法 class Solution { public int numTrees(int n) { int[] G = new int[n+1]; G[0] = 1; G[1] = 1; for (int i = 2 ; i <= n; i++) { for (int j = 1; j <= i; j++) { G[i] += G[j-1] * G[i-j]; } } return G[n]; } } 时间复杂度: o(N2), 空间复杂度: o(N)  G(N) = f(1) + ... + f(n) f(n) = G(i-1)*G(n-i) + ... + G(n-1)*G(n-n) 这个是该算法的精髓 参考: https://leetcode-cn.com/problems/unique-binary-search-trees/submissions/   来源: https://www.cnblogs.com/wangsong412/p/12516208.html

实现一个二叉搜索树(JavaScript 版)

こ雲淡風輕ζ 提交于 2020-03-13 17:21:37
二叉树在计算机科学中应用很广泛,学习它有助于让我们写出高效的插入、删除、搜索节点算法。二叉树的节点定义:一个节点最多只有两个节点,分别为左侧节点、右侧节点。 二叉搜索树是二叉树中的一种,在二叉搜索树中每个父节点的键值要大于左边子节点小于右边子节点。下图展示一颗二叉搜索树。 二叉搜索树实现大纲 本文将使用 JavaScript 语言,实现一个二叉搜索树,以下为实现的方法: constructor():构造函数,初始化一个二叉搜索树 insert(value):二叉树中查找一个节点,如果存在返回 true 否则返回 false preOrderTraverse(cb):先序遍历或称前序遍历 inOrderTraverse(cb):中序遍历 postOrderTraverse(cb):后序遍历 minNodeValue():最小节点值 maxNodeValue():最大节点值 removeNode(value):移除节点 destory():销毁节点 注意 :在实现二叉树搜索 在这里插入代码片 的很多方法中我们将使用大量的递归操作,如果对它不了解的,可以自行查阅资料学习。 初始化一个二叉搜索树 声明一个 BST 类,在构造函数的 constructor() 里声明它的结构: class BST { constructor () { this.root = null; // 初始化根节点