背景

很多场景下都需要将元素存储到已排序的集合中。用数组来存储,搜索效率非常高: O(log n),但是插入效率比较低:O(n)。用链表来存储,插入效率和搜索效率都比较低:O(n)。如何能提供插入和搜索效率呢?这就是二叉搜索树的由来,本文先介绍非平衡二叉搜索树。

非平衡二叉搜索树

规则

所有节点的左节点小于节点,所有节点的右节点大于等于自身,即:node.value >  node.left.value && node.value <= node.right.value。

示例

根据上面的规则,我们也很容易找到最大值和最小值,后面也会用到这种算法。最大值可以通过递归方法 node.right 得到,最小值可以递归 node.left 得到。

为什么叫非平衡?

说明:下图变成链表了,这会导致效率非常低,后面找机会再介绍平衡算法。

实现

搜索、遍历(前序、中序和后序)、添加算法都比较简单,可以直接看后面的代码,这里重点介绍一下删除算法。

如何删除元素?

第一步:要找到删除的元素(current)。

第二步:判断 current 满足如下哪种场景:

  1. current.Right == null
    示例

    代码

                         if (parent == null)
    {
    this.Root = current.Left;
    }
    else if (isLeft)
    {
    parent.Left = current.Left;
    }
    else
    {
    parent.Right = current.Left;
    }

    结果

  2. current.Right != null && current.Right.Left == null
    示例

    代码
                         current.Right.Left = current.Left;
    
                         if (parent == null)
    {
    this.Root = current.Right;
    }
    else if (isLeft)
    {
    parent.Left = current.Right;
    }
    else
    {
    parent.Right = current.Right;
    }

    结果

  3. current.Right != null && current.Right.Left != null
    示例

    代码
                         Node<T> currentRightSmallestParent = current.Right;
    var currentRightSmallest = current.Right.Left; this.FindSmallest(ref currentRightSmallestParent, ref currentRightSmallest); currentRightSmallestParent.Left = currentRightSmallest.Right;
    currentRightSmallest.Left = current.Left;
    currentRightSmallest.Right = current.Right;
    if (parent == null)
    {
    this.Root = currentRightSmallest;
    }
    else if (isLeft)
    {
    parent.Left = currentRightSmallest;
    }
    else
    {
    parent.Right = currentRightSmallest;
    }

    结果

    说明
    这里的重点是 FindSmallest,找出 current.Right.Left 子树中最小的元素,然后用它替换 current。

完整代码

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace DataStuctureStudy.Trees
{
class UnBalancedBinarySearchTree
{
class Node<T>
where T : IComparable<T>
{
public T Value { get; set; } public Node<T> Left { get; set; } public Node<T> Right { get; set; } public void InOrderTraverse(Action<T> action)
{
if (this.Left != null)
{
this.Left.InOrderTraverse(action);
} action(this.Value); if (this.Right != null)
{
this.Right.InOrderTraverse(action);
}
} public int Depth()
{
var leftDepth = ;
var rightDepth = ; if (this.Left != null)
{
leftDepth = this.Left.Depth();
}
if (this.Right != null)
{
rightDepth = this.Right.Depth();
} return
leftDepth > rightDepth
? leftDepth +
: rightDepth + ;
}
} public class Tree<T>
where T : IComparable<T>
{
private Node<T> Root { get; set; } public void Display()
{
Console.WriteLine(); if (this.Root == null)
{
return;
} var depth = this.Root.Depth();
var buffers = new string[depth][];
for (int i = ; i < buffers.Length; i++)
{
buffers[i] = new string[(int)(Math.Pow(, depth) - )];
} this.BuildArray(this.Root, depth, buffers, , ); for (int i = ; i < buffers.Length; i++)
{
for (int j = ; j < buffers[i].Length; j++)
{
if (buffers[i][j] == null)
{
Console.Write(new string(' ', ));
}
else
{
var leftPad = ( - buffers[i][j].Length) / ;
Console.Write(buffers[i][j]
.PadLeft(leftPad + buffers[i][j].Length)
.PadRight());
}
}
Console.WriteLine();
Console.WriteLine();
}
} private void BuildArray(Node<T> node, int nodeDepth, string[][] buffers, int row, int startColumn)
{
if (node == null)
{
return;
} var nodeWidth = Math.Pow(, nodeDepth) - ;
var column = (int)(startColumn + nodeWidth / ); buffers[row][column] = node.Value.ToString(); this.BuildArray(node.Left, nodeDepth - , buffers, row + , startColumn);
this.BuildArray(node.Right, nodeDepth - , buffers, row + , column + );
} public bool Contains(T item)
{
var current = this.Root; while (current != null)
{
if (item.CompareTo(current.Value) == )
{
return true;
}
else if (item.CompareTo(current.Value) < )
{
current = current.Left;
}
else
{
current = current.Right;
}
} return false;
} public void InOrderTraverse(Action<T> action)
{
if (this.Root != null)
{
this.Root.InOrderTraverse(action);
}
} public void Insert(T item)
{
var node = new Node<T> { Value = item }; Node<T> parent = null;
var current = this.Root;
var isLeft = false; while (current != null)
{
parent = current; if (item.CompareTo(current.Value) < )
{
current = current.Left;
isLeft = true;
}
else
{
current = current.Right;
isLeft = false;
}
} if (parent == null)
{
this.Root = node;
}
else if (isLeft)
{
parent.Left = node;
}
else
{
parent.Right = node;
}
} public bool Delete(T item)
{
Node<T> parent = null;
var current = this.Root;
var isLeft = false; this.Find(item, ref parent, ref current, ref isLeft); if (current == null)
{
return false;
} if (current.Right == null)
{
if (parent == null)
{
this.Root = current.Left;
}
else if (isLeft)
{
parent.Left = current.Left;
}
else
{
parent.Right = current.Left;
}
}
else if (current.Right != null && current.Right.Left == null)
{
current.Right.Left = current.Left; if (parent == null)
{
this.Root = current.Right;
}
else if (isLeft)
{
parent.Left = current.Right;
}
else
{
parent.Right = current.Right;
}
}
else
{
Node<T> currentRightSmallestParent = current.Right;
var currentRightSmallest = current.Right.Left; this.FindSmallest(ref currentRightSmallestParent, ref currentRightSmallest); currentRightSmallestParent.Left = currentRightSmallest.Right;
currentRightSmallest.Left = current.Left;
currentRightSmallest.Right = current.Right;
if (parent == null)
{
this.Root = currentRightSmallest;
}
else if (isLeft)
{
parent.Left = currentRightSmallest;
}
else
{
parent.Right = currentRightSmallest;
}
} return true;
} private void Find(T item, ref Node<T> parent, ref Node<T> current, ref bool isLeft)
{
while (current != null)
{
if (item.CompareTo(current.Value) == )
{
break;
} parent = current; if (item.CompareTo(current.Value) < )
{
current = current.Left;
isLeft = true;
}
else
{
current = current.Right;
isLeft = false;
}
}
} private void FindSmallest(ref Node<T> parent, ref Node<T> current)
{
while (current != null)
{
if (current.Left == null)
{
break;
} parent = current;
current = current.Left;
}
}
}
}
}

备注

学完这个树的最大收获就是,找到了一种输出树形结构相对高效的方法,比我之前用的高效,这种算法可以用在组织结构图的生成中。

算法:非平衡二叉搜索树(UnBalanced Binary Search Tree)的更多相关文章

  1. [数据结构]——二叉树(Binary Tree)、二叉搜索树(Binary Search Tree)及其衍生算法

    二叉树(Binary Tree)是最简单的树形数据结构,然而却十分精妙.其衍生出各种算法,以致于占据了数据结构的半壁江山.STL中大名顶顶的关联容器--集合(set).映射(map)便是使用二叉树实现 ...

  2. 二叉搜索树BST(Binary Search Tree)

    二叉搜索树(Binary Search Tree)也叫二叉排序树或二叉查找树.它满足以下性质: 1.非空左子树的所有键值小于其根结点的键值: 2.非空右子树的所有键值大于其根结点的键值: 3.左右子树 ...

  3. 【数据结构05】红-黑树基础----二叉搜索树(Binary Search Tree)

    目录 1.二分法引言 2.二叉搜索树定义 3.二叉搜索树的CRUD 4.二叉搜索树的两种极端情况 5.二叉搜索树总结 前言 在[算法04]树与二叉树中,已经介绍过了关于树的一些基本概念以及二叉树的前中 ...

  4. 二叉搜索树(Binary Search Tree)

    二叉搜索树(BST,Binary Search Tree),也称二叉排序树或二叉查找树. 二叉搜索树:一棵二叉树,可以为空:如果不为空,满足以下性质: 非空左子树的所有键值小于其根结点的键值: 非空右 ...

  5. 原生JS实现二叉搜索树(Binary Search Tree)

    1.简述 二叉搜索树树(Binary Search Tree),它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若它的右子树不空,则右子 ...

  6. 二叉搜索树(Binary Search Tree)--C语言描述(转)

    图解二叉搜索树概念 二叉树呢,其实就是链表的一个二维形式,而二叉搜索树,就是一种特殊的二叉树,这种二叉树有个特点:对任意节点而言,左孩子(当然了,存在的话)的值总是小于本身,而右孩子(存在的话)的值总 ...

  7. [Swift]LeetCode98. 验证二叉搜索树 | Validate Binary Search Tree

    Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is defined as ...

  8. [Swift]LeetCode173. 二叉搜索树迭代器 | Binary Search Tree Iterator

    Implement an iterator over a binary search tree (BST). Your iterator will be initialized with the ro ...

  9. 数据结构-二叉搜索树(BST binary search tree)

    本文由@呆代待殆原创,转载请注明出处:http://www.cnblogs.com/coffeeSS/ 二叉搜索树简介 顾名思义,二叉搜索树是以一棵二叉树来组织的,这样的一棵树可以用一个链表数据结构来 ...

  10. [Swift]LeetCode99. 恢复二叉搜索树 | Recover Binary Search Tree

    Two elements of a binary search tree (BST) are swapped by mistake. Recover the tree without changing ...

随机推荐

  1. AngularJs(SPA)单页面SEO以及百度统计应用(上)

    只有两种人最具有吸引力,一种是无所不知的人,一种是一无所知的人 问:学生问追一个女孩总是追不上怎么办?回答:女孩不是追来的,是吸引来的,你追的过程是吸引女孩的过程,如果女孩没有看上你,再追都是没有用的 ...

  2. GUC-8 小练习

    import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.uti ...

  3. mysql中的包含语句INSTR的使用

    1.目前测试百万级数据,效率还是相当可观,感觉比like更精准! 例句 今天项目遇到一个问题,每个用户都有自己的所属渠道,当登录后台操作时,要列出隶属于自己拥有渠道的用户列表,当初想到使用全部遍历出来 ...

  4. BZOJ 1036: [ZJOI2008]树的统计Count (树链剖分模板题)

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 14982  Solved: 6081[Submit ...

  5. 易普优APS-3C行业解决方案助力国家智能制造示范车间实现高效计划排程

    一.      项目背景 广东劲胜智能集团国家智能制造专项——移动终端金属加工智能制造新模式项目是2015年国家94家智能制1.造专项之一.本项目实施车间为金属CNC加工车间(下称“智能制造示范车间” ...

  6. NET生成缩略图

    1.添加一个html <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <hea ...

  7. 全文搜索引擎 Elasticsearch (三)logstash-input-jdbc同步数据 到elasticsearch

    参考链接: 1, 源码地址,官方介绍 2, logstash-input-jdbc使用建议 3, 官网介绍例子,使用 logstash-input-jdbc 到 elasticsearch 一.安装 ...

  8. HandlerExceptionResolver统一异常处理 返回JSON 和 ModelAndView

    统一异常处理类的两种方式一种是前后分离,一种是一整套集合返回指定到指定的错误页面显示错误信息 1.由于前后分离,是统一返回JSON的格式 自定义Exception public class Bussi ...

  9. Windows下安装mysql cluster

    0.mysql集群介绍 浅谈mysql集群——http://blog.csdn.net/chenxingzhen001/article/details/7708663: 官网——http://dev. ...

  10. Java_集合与泛型

    Collection 集合,集合是java中提供的一种容器,可以用来存储多个数据.在前面的学习中,我们知道数据多了,可以使用数组存放或者使用ArrayList集合进行存放数据.那么,集合和数组既然都是 ...