二叉查找树,对于大多数情况下的查找和插入在效率上来说是没有问题的,但是他在最差的情况下效率比较低

红黑树保证在最坏的情况下插入和查找效率都能保证在对数(Log(n))的时间复杂度内完成

1.红黑树的性质:

  • 性质1.节点是红色或黑色
  • 性质2.根是黑色
  • 性质3.所有叶子都是黑色(叶子是NIL节点
  • 性质4.如果一个节点是红的,则它的两个子节点都是黑的(从每个叶子到根的所有路径上不能有两个连续的红色节点)
  • 性质5.从任一节点到其叶子的所有路径都包含相同数目的黑色节点。

注:清晰理解红黑树的性质,对红黑树算法的实现有非常重要的作用。

最近发现一个旧金山大学计算机系的一个网站,可以根据你输入的插入、删除和查找的的值,提供非常直观的插入、删除和查找动画展示,删除选取的左子树的最大节点作为删除节点的替换节点。

Red/Black Tree Visualization

红黑树的代码实现:C#数据结构-红黑树实现_()鹅厂程序小哥的博客-CSDN博客_c# 红黑树

同时,贴上前辈大神红黑树的详细解析:【数据结构和算法05】 红-黑树(看完包懂~)

2.红黑树的查找和插入(和二叉树几乎一样):

将要查找的value和节点的value比较,如果小于,那么就在Left Node节点查找;如果大于,则在Right Node节点查找,如果相等,更新Value。

新插入的节点都为红色

3.红黑树的删除:

1.如果删除节点没有子节点,直接删除,返回null

2.如果只有一个子节点,删除节点,然后返回其子节点代替删除节点即可

3.当左右子节点都不为空时,找到其右子树中的最小节点,替换删除节点的位置

在实现原理上,红黑树的查找和删除,跟二叉查找树是一致的。不过,为了保证树在插入、删除完成之后,保持红黑树的平衡状态,需要实现更多更复杂的逻辑。

4.红黑树的平衡性修正

4.1 变色

比如A和S是红色(新插入都节点都为红色),加入再往里面插入一个红色子节点,无论是下方4个可能性中的任何一个,都会导致两个连续的红色节点,所以需要集体一行一行变色。A和S变成黑色,E变成红色。

21让22变色:

22让25变色:

25让27变色: 

4.2 左旋

之所以左旋右旋,是因为当红黑树不平衡了,左边多了,或者右边多了,就需要做旋转平衡处理。

下图演示旋转方法:

4.3 右旋

5.左倾树,3种插入和3种删除,以及2-3-4树转换红黑树(面试常考)

左倾红黑树: 如果在树中出现了红色节点,那么这个节点必须是左儿子

2-3-4树(阶为 4 的B树): 

  • 2-节点,就是说,它包含 1 个元素和 2 个儿子,
  • 3-节点,就是说,它包含 2 个元素和 3 个儿子,
  • 4-节点,就是说,它包含 3 个元素和 4 个儿子 。

5.1 为什么要有红色节点:

在红黑树中有红、黑两种颜色,由于红黑树是2-3-4树的一种抽象表示,所以红黑树需要能和2-3-4树互相转换,红色节点可以构成转换的方式。使用黑色节点去表示 2-3-4 树的所有节点。使用红色的子节点来让该节点代表 3-node 和 4-node。

  • 两个节点之间是黑色的连接代表两个 2-node 节点的普通连接
  • 两个节点之间是红色的连接代表一个 3-node
  • 当一个节点与两个子节点都是红色连接,说明是一个 4-node。

5.2 红黑树的三种插入

情形1. N为根节点(父节点为NULL)

当前平衡节点N为根节点时,直接涂黑根节点即可。

情形2. 父黑

父节点为黑色时,无需其他操作,已然平衡。

情形3. 父红-叔红

父红-叔红时,将父/叔节(P/U)点涂黑,祖父节点(GP)涂红;而后以祖父节点(GP)作为新的平衡节点N,递归执行平衡操作。

情形4. 父红-叔黑

情形4.1 父N(New)同左

“父N同左”指的是:父节点为祖父节点的左子,N为父节点的左子
此时以祖父节点(GP)为支点进行右旋;然后将P涂黑,将GP涂红。

旋转后,P涂黑是因为要涂为原GP的黑色(往上兼容GP的父节点);而GP涂红则是因为右旋后,经过U的路径的黑色节点数量+1,涂红进行数量平衡;下同。

情形4.2 父N同右

“父N同右”指的是:父节点是祖父节点的右子,N为父节点的右子
此时以祖父节点(GP)为支点进行左旋;将P涂黑,将GP涂红。

情形4.3 父左N右

“父左N右”指的是:父节点是祖父节点的左子,N为父节点的右子
此时,以父节点(P)进行左旋,旋转后,以P作为新的平衡节点N,转至 [情形4.1 父N同左] 处理。

情形4.4 父右N左

“父右N左”指的是:父节点是祖父节点的右子,N为父节点的左子
此时,以父节点(P)进行右旋,旋转后,以P作为新的平衡节点,此时再进行[情形4.2 父N同右]处理。

4.5 插入总结与实例

首先是先插入再说;插入后,以刚插入的节点作为当前平衡节点N,进行平衡操作。现在回头看插入平衡的这几种情形,其实并不复杂:

  1. N为根:涂黑完事;
  2. 父黑:啥事不用管;
  3. 父红叔红:父/叔涂黑,祖父涂红,然后把祖父当成新的平衡节点递归处理(我们下面平衡了,让他老人家和上面沟通吧);
  4. 父红叔黑:父节点和新插入节点同一边的话,扭一下就完事了(同左右旋,同右左旋,顺便涂色);不在同一边的话,先扭到同一边吧。

例:插入 10,20,15,30,5,8;
为了简化,图中没有画出null的黑色节点。

硬核图解面试最怕的红黑树「建议反复阅读」 - 知乎linux服务器开发相关视频解析: 红黑树,在Linux内核的那些故事 90分钟搞定红黑树应用c/c++ linux服务器开发学习地址: c/c++ linux后台服务器高级架构师注:本文比较硬核但是很值得大家花心思看完,看完你一定会…https://zhuanlan.zhihu.com/p/386065726

彻底理解红黑树(二)之 插入 - 简书彻底理解红黑树(一)之 二叉搜索树[https://www.jianshu.com/p/a9c064d38a92]彻底理解红黑树(二)之 插入[https://www.jia...https://www.jianshu.com/p/96e652ccf720

理解红黑树(RBTree)的性质与操作 - 哔哩哔哩从博客复制过来的,不知道排版哪些地方会乱,可以到我博客阅读原文: https://korilin.com/blog/DSA/red-black-tree/红黑树(Red-Black Tree)是一种自平衡的二叉查找树(Binary Search Tree, BST),由于基于二叉查找树(并不是基于 AVL 树 (opens new window)),因此它是有序的。它出现于 1978 年 Leo J. Guibas 和 Robert Sedgewick 的一篇论文。红黑树和 AVL 树很像,都是https://www.bilibili.com/read/cv11727779

6.完整源码

红-黑树的一些其他操作,比如:查找特定值、遍历、返回最值、销毁树等操作我将放到源码中给大家呈现出来,详见下面红-黑树的完整代码。

​
using System;
using System.Collections.Generic;namespace StructScript
{/// 红黑树定义:/// 性质1.节点是红色或黑色/// 性质2.根是黑色/// 性质3.所有叶子都是黑色(叶子是NIL节点)/// 性质4.如果一个节点是红的,则它的两个子节点都是黑的(从每个叶子到根的所有路径上不能有两个连续的红色节点)/// 性质5.从任一节点到其叶子的所有路径都包含相同数目的黑色节点。public class RedBlackTree<T>{//根节点private RedBlackTreeNode<T> mRoot;//比较器private Comparer<T> mComparer;private const bool RED = true;private const bool BLACK = false;public RedBlackTree(){mRoot = null;mComparer = Comparer<T>.Default;}public bool Contains(T value){RedBlackTreeNode<T> node;return Contain(value, out node);}public bool Contain(T value, out RedBlackTreeNode<T> newNode){if (value == null){throw new ArgumentNullException();}newNode = null;RedBlackTreeNode<T> node = mRoot;while (node != null){int comparer = mComparer.Compare(value, node.Data);if (comparer > 0){node = node.RightChild;}else if (comparer < 0){node = node.LeftChild;}else{newNode = node;return true;}}return false;}public void Add(T value){if (mRoot == null){// 根节点是黑色的mRoot = new RedBlackTreeNode<T>(value, BLACK);}else{// 新插入节点是红色的Insert1(new RedBlackTreeNode<T>(value, RED), value);}}private void Insert1(RedBlackTreeNode<T> newNode, T value){//遍历找到插入位置RedBlackTreeNode<T> node = mRoot;//插入节点的父节点RedBlackTreeNode<T> parent = null;while (node != null){parent = node;int comparer = mComparer.Compare(value, node.Data);if (comparer > 0){node = node.RightChild;}else if (comparer < 0){node = node.LeftChild;}else{node.Data = value;return;}}//找到插入位置,设置新插入节点的父节点为currentnewNode.Parent = parent;//比较插入节点的值跟插入位置的值的大小, 插入新节点int comparer1 = mComparer.Compare(value, parent.Data);if (comparer1 > 0){parent.RightChild = newNode;}else if (comparer1 < 0){parent.LeftChild = newNode;}//将它重新修整为一颗红黑树InsertFixUp(newNode);}private void InsertFixUp(RedBlackTreeNode<T> newNode){RedBlackTreeNode<T> parent = newNode.Parent; //插入节点的父节点RedBlackTreeNode<T> gParent = null; //插入节点的祖父节点//父节点的颜色是红色,并且不为空while (IsRed(parent) && parent != null){//获取祖父节点,这里不用判空,//因为如果祖父节点为空,parent就是根节点,根节点是黑色,不会再次进入循环gParent = parent.Parent;//若父节点是祖父节点的左子节点 if (parent == gParent.LeftChild){RedBlackTreeNode<T> uncle = gParent.RightChild; //获得叔叔节点  //case1: 叔叔节点也是红色  if (uncle != null && IsRed(uncle)){//把父节点和叔叔节点涂黑,祖父节点涂红parent.Color = BLACK;uncle.Color = BLACK;gParent.Color = RED;//把祖父节点作为插入节点,向上继续遍历newNode = gParent;parent = newNode.Parent;continue; //继续while,重新判断  }//case2: 叔叔节点是黑色,且当前节点是右子节点  if (newNode == parent.RightChild){//从父节点处左旋//当这种情况时,只能左旋,因为父亲节点和祖父节点变色,无论左旋还是右旋,都会违背红黑树的基本性质RotateLeft(parent);//当左旋后,红黑树变成case3的情况,区别就是插入节点是父节点//所以,将父节点和插入节点调换一下,为下面右旋做准备RedBlackTreeNode<T> tmp = parent;parent = newNode;newNode = tmp;}//case3: 叔叔节点是黑色,且当前节点是左子节点// 父亲和祖父节点变色,从祖父节点处右旋parent.Color = BLACK;gParent.Color = RED;RotateRight(gParent);}else{//若父节点是祖父节点的右子节点,与上面的完全相反RedBlackTreeNode<T> uncle = gParent.LeftChild;//case1: 叔叔节点也是红色  if (uncle != null & IsRed(uncle)){//把父节点和叔叔节点涂黑,祖父节点涂红parent.Color = BLACK;uncle.Color = BLACK;gParent.Color = RED;//把祖父节点作为插入节点,向上继续遍历newNode = gParent;parent = newNode.Parent;continue;//继续while,重新判断}//case2: 叔叔节点是黑色的,且当前节点是左子节点  if (newNode == parent.LeftChild){//从父节点处右旋//当这种情况时,只能右旋,因为父亲节点和祖父节点变色,无论左旋还是右旋,都会违背红黑树的基本性质RotateRight(parent);RedBlackTreeNode<T> tmp = parent;parent = newNode;newNode = tmp;}//case3: 叔叔节点是黑色的,且当前节点是右子节点  // 父亲和祖父节点变色,从祖父节点处右旋parent.Color = BLACK;gParent.Color = RED;RotateLeft(gParent);}}//将根节点设置为黑色mRoot.Color = BLACK;}public bool IsRed(RedBlackTreeNode<T> node){if (node == null){return false;}if (node.Color == RED){return true;}return false;}public bool IsBlack(RedBlackTreeNode<T> node){if (node == null){return false;}if (node.Color == BLACK){return true;}return false;}// 左旋转,逆时针旋转/*************对红黑树节点x进行左旋操作 ******************//* * 左旋示意图:对节点x进行左旋 *     p                       p *    /                       / *   x                       y *  / \                     / \ * lx  y                   x  ry *    / \                 / \ *   ly ry               lx ly * 左旋做了三件事: * 1. 将y的左子节点赋给x的右子节点,并将x赋给y左子节点的父节点(y左子节点非空时) * 2. 将x的父节点p(非空时)赋给y的父节点,同时更新p的子节点为y(左或右) * 3. 将y的左子节点设为x,将x的父节点设为y */private void RotateLeft(RedBlackTreeNode<T> x){//1. 将y的左子节点赋给x的右子节点,并将x赋给y左子节点的父节点(y左子节点非空时)  RedBlackTreeNode<T> y = x.RightChild;x.RightChild = y.LeftChild;if (y.LeftChild != null){y.LeftChild.Parent = x;}//2. 将x的父节点p(非空时)赋给y的父节点,同时更新p的子节点为y(左或右) if (x.Parent != null){y.Parent = x.Parent;}if (x.Parent == null){mRoot = y; //如果x的父节点为空,则将y设为父节点y.Parent = null;//设置y的父节点为空  }else{//如果x是左子节点  if (x == x.Parent.LeftChild){//则也将y设为左子节点  x.Parent.LeftChild = y;}else{//否则将y设为右子节点 x.Parent.RightChild = y;}}//3. 将y的左子节点设为x,将x的父节点设为y  y.LeftChild = x;x.Parent = y;}// 右旋转,顺时针旋转/*************对红黑树节点y进行右旋操作 ******************//* * 左旋示意图:对节点y进行右旋 *        p                   p *       /                   / *      y                   x *     / \                 / \ *    x  ry               lx  y *   / \                     / \ * lx  rx                   rx ry * 右旋做了三件事: * 1. 将x的右子节点赋给y的左子节点,并将y赋给x右子节点的父节点(x右子节点非空时) * 2. 将y的父节点p(非空时)赋给x的父节点,同时更新p的子节点为x(左或右) * 3. 将x的右子节点设为y,将y的父节点设为x */private void RotateRight(RedBlackTreeNode<T> y){//1.将x的右子节点赋值给y的左子节点,同时将y赋值给x的右子节点的父节点(如果x的右子节点非空)RedBlackTreeNode<T> x = y.LeftChild;y.LeftChild = x.RightChild;if (x.RightChild != null){x.RightChild.Parent = y;}//2.如果y的父节点非空时,将y的父节点赋值给x的父节点,同时更新p的子节点为xif (y.Parent != null){x.Parent = y.Parent;}//如果y的父节点为空,则将x设为父节点if (y.Parent == null){mRoot = x;x.Parent = null;//设置x的父节点为空}else{//如果y是右子节点if (y == y.Parent.RightChild){//则也将y设为右子节点  y.Parent.RightChild = x;}else{//否则将x设为左子节点y.Parent.LeftChild = x;}}//3.将x的右子节点设为y,y的父节点设置为xx.RightChild = y;y.Parent = x;}public int Count{get{return CountLeafNode(mRoot);}}private int CountLeafNode(RedBlackTreeNode<T> root){if (root == null){return 0;}else{return CountLeafNode(root.LeftChild) + CountLeafNode(root.RightChild) + 1;}}public int Depth{get{return GetHeight(mRoot);}}private int GetHeight(RedBlackTreeNode<T> root){if (root == null){return 0;}int leftHight = GetHeight(root.LeftChild);int rightHight = GetHeight(root.RightChild);return leftHight > rightHight ? leftHight + 1 : rightHight + 1;}public T Max{get{RedBlackTreeNode<T> node = mRoot;while (node.RightChild != null){node = node.RightChild;}return node.Data;}}public T Min{get{if (mRoot != null){RedBlackTreeNode<T> node = GetMinNode(mRoot);return node.Data;}else{return default(T);}}}public void DelMin(){mRoot = DelMin(mRoot);}private RedBlackTreeNode<T> DelMin(RedBlackTreeNode<T> node){if (node.LeftChild == null){return node.RightChild;}node.LeftChild = DelMin(node.LeftChild);return node;}public void Remove(T value){mRoot = Delete(mRoot, value);}private RedBlackTreeNode<T> Delete(RedBlackTreeNode<T> node, T value){if (node == null){Console.WriteLine("没有找到要删除的节点: " + value);return null;}int comparer = mComparer.Compare(value, node.Data);if (comparer > 0){node.RightChild = Delete(node.RightChild, value);}else if (comparer < 0){node.LeftChild = Delete(node.LeftChild, value);}else{// a.如果删除节点没有子节点,直接返回null// b.如果只有一个子节点,返回其子节点代替删除节点即可if (node.LeftChild == null){if (node.RightChild != null){node.RightChild.Parent = node.Parent;}return node.RightChild;}else if (node.RightChild == null){if (node.LeftChild != null){node.LeftChild.Parent = node.Parent;}return node.LeftChild;}else{// c.被删除的节点“左右子节点都不为空”的情况  RedBlackTreeNode<T> child;RedBlackTreeNode<T> parent;bool color;// 1. 先找到“删除节点的右子树中的最小节点”,用它来取代被删除节点的位置// 注意:这里也可以选择“删除节点的左子树中的最大节点”作为被删除节点的替换节点RedBlackTreeNode<T> replace = node;replace = GetMinNode(replace.RightChild);// 2. 更新删除父节点及其子节点// 要删除的节点不是根节点  if (node.Parent != null){// 要删除的节点是:删除节点的父节点的左子节点 if (node == node.Parent.LeftChild){// 把“删除节点的右子树中的最小节点”赋值给“删除节点的父节点的左子节点” node.Parent.LeftChild = replace;}else{// 把“删除节点的右子树中的最小节点”赋值给“删除节点的父节点的右子节点”node.Parent.RightChild = replace;}}else{// 要删除的节点是根节点// 如果只有一个根节点,把mRoot赋值为null,这时replace为null// 如果不止一个节点,返回根节点的右子树中的最小节点mRoot = replace;}// 记录被删除节点的右子树中的最小节点的右子节点,父亲节点及颜色,没有左子节点child = replace.RightChild;parent = replace.Parent;color = replace.Color;// 3. 删除“被删除节点的右子树中的最小节点”,同时更新替换节点的左右子节点,父亲节点及颜色// 替换节点 也就是 最小节点if (parent == node){// 被删除节点的右子树中的最小节点是被删除节点的子节点parent = replace;}else{//如果最小节点的右子节点不为空,更新其父节点if (child != null){child.Parent = parent;}//更新最小节点的父节点的左子节点,指向最小节点的右子节点parent.LeftChild = child;//更新替换节点的右子节点replace.RightChild = node.RightChild;//更新删除节点的右子节点的父节点node.RightChild.Parent = replace;}//更新替换节点的左右子节点,父亲节点及颜色replace.Parent = node.Parent;//保持原来位置的颜色replace.Color = node.Color;replace.LeftChild = node.LeftChild;//更新删除节点的左子节点的父节点node.LeftChild.Parent = replace;//红黑树平衡修复//如果删除的最小节点颜色是黑色,需要重新平衡红黑树//如果删除的最小节点颜色是红色,只需要替换删除节点后,涂黑即可//上面的保持原来位置的颜色已经处理了这种情况,这里只需要判断最小节点是黑色的情况if (color == BLACK){//将最小节点的child和parent传进去RemoveFixUp(child, parent);}return replace;}}return node;}private void RemoveFixUp(RedBlackTreeNode<T> node, RedBlackTreeNode<T> parent){RedBlackTreeNode<T> brother;// 被删除节点的右子树中的最小节点 不是 被删除节点的子节点的情况while ((node == null || IsBlack(node)) && (node != mRoot)){if (parent.LeftChild == node){//node是左子节点,下面else与这里的刚好相反  brother = parent.RightChild; //node的兄弟节点  if (IsRed(brother)){//case1: node的兄弟节点brother是红色的 brother.Color = BLACK;parent.Color = RED;RotateLeft(parent);brother = parent.RightChild;}//case2: node的兄弟节点brother是黑色的,且brother的两个子节点也都是黑色的//继续向上遍历  if ((brother.LeftChild == null || IsBlack(brother.LeftChild)) &&(brother.RightChild == null || IsBlack(brother.RightChild))){//把兄弟节点设置为黑色,平衡红黑树brother.Color = RED;node = parent;parent = node.Parent;}else{//case3: node的兄弟节点brother是黑色的,且brother的左子节点是红色,右子节点是黑色  if (brother.RightChild == null || IsBlack(brother.RightChild)){brother.LeftChild.Color = BLACK;brother.Color = RED;RotateRight(brother);brother = parent.RightChild;}//case4: node的兄弟节点brother是黑色的,且brother的右子节点是红色,左子节点任意颜色  brother.Color = parent.Color;parent.Color = BLACK;brother.RightChild.Color = BLACK;RotateLeft(parent);node = mRoot;break;}}else{//与上面的对称  brother = parent.LeftChild;if (IsRed(brother)){// Case 1: node的兄弟brother是红色的   brother.Color = BLACK;parent.Color = RED;RotateRight(parent);brother = parent.LeftChild;}// Case 2: node的兄弟brother是黑色,且brother的俩个子节点都是黑色的 if ((brother.LeftChild == null || IsBlack(brother.LeftChild)) &&(brother.RightChild == null || IsBlack(brother.RightChild))){//把兄弟节点设置为黑色,平衡红黑树brother.Color = RED;node = parent;parent = node.Parent;}else{// Case 3: node的兄弟brother是黑色的,并且brother的左子节点是红色,右子节点为黑色。if (brother.LeftChild == null || IsBlack(brother.LeftChild)){brother.RightChild.Color = BLACK;brother.Color = RED;RotateLeft(brother);brother = parent.LeftChild;}// Case 4: node的兄弟brother是黑色的;并且brother的左子节点是红色的,右子节点任意颜色  brother.Color = parent.Color;parent.Color = BLACK;brother.LeftChild.Color = BLACK;RotateRight(parent);node = mRoot;break;}}}//如果删除的最小节点的右子节点是红色,只需要替换最小节点后,涂黑即可if (node != null){node.Color = BLACK;}}private RedBlackTreeNode<T> GetMinNode(RedBlackTreeNode<T> node){while (node.LeftChild != null){node = node.LeftChild;}return node;}// 中序遍历:首先遍历其左子树,然后访问根结点,最后遍历其右子树。// 递归方法实现体内再次调用方法本身的本质是多个方法的简写,递归一定要有出口public void ShowTree(){ShowTree(mRoot);}private void ShowTree(RedBlackTreeNode<T> node){if (node == null){return;}ShowTree(node.LeftChild);string nodeColor = node.Color == RED ? "red" : "black";string log;if (node.Parent != null){log = node.Data + " " + nodeColor + " parent= " + node.Parent.Data;}else{log = node.Data + " " + nodeColor + " parent= null";}//打印节点数据Console.WriteLine(log);ShowTree(node.RightChild);}}public class RedBlackTreeNode<T>{//数据public T Data { get; set; }//左子节点public RedBlackTreeNode<T> LeftChild { get; set; }//右子节点public RedBlackTreeNode<T> RightChild { get; set; }//父节点public RedBlackTreeNode<T> Parent { get; set; }//该节点颜色public bool Color { get; set; }public RedBlackTreeNode(T value, bool color){Data = value;LeftChild = null;RightChild = null;Color = color;}}
}​

引用

C#数据结构-红黑树实现_鹅厂程序小哥的博客-CSDN博客_c# 红黑树

什么是红黑树,一篇文章解决所有疑惑~~ - 知乎

红黑树(平衡二叉查找树) - 知乎

彻底理解红黑树(二)之 插入 - 简书

算法学习二,红黑树查找算法相关推荐

  1. 算法手札二:红黑树的插入原理,原理与实现篇

    红黑树的五大性质(性质四与性质五特别重要) 1. 节点必须是红色或者是黑色 2. 根节点是黑色的 3. 所有的叶子节点是黑色的. 4. 每个红色节点的两个子节点是黑色的,也就是不能存在父子两个节点全是 ...

  2. 数据结构算法学习 之 红黑树

    1.红黑树的特性 (1)每个节点或者是黑色,或者是红色. (2)根节点是黑色. (3)每个叶子节点(NIL)是黑色. [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!] (4)如果一个节 ...

  3. 《算法导论》红黑树详解(一):概念

    在学习红黑树之前,读者应先掌握二叉查找树的相关知识.学习红黑树或者二叉查找树,推荐大家看<算法导论>.<算法导论>原书第3版 高清PDF 带详细书签目录下载 密码:acis & ...

  4. 【算法】红黑树-二叉树-算法

    红黑树-二叉树-算法 红黑树查找_百度搜索(5 条消息)AVL树,红黑树,B树,B+树,Trie树都分别应用在哪些现实场景中? - 知乎查找(二):彻底理解红黑树和平衡查找树 - @瞪着太阳的乌鸦 - ...

  5. 【数据结构和算法05】 红-黑树(转发)

    2019独角兽企业重金招聘Python工程师标准>>> [数据结构和算法05] 红-黑树(看完包懂~) 置顶 2016年04月13日 15:50:25 eson_15 阅读数:526 ...

  6. OpenCV学习(二十) :分水岭算法:watershed()

    OpenCV学习(二十) :分水岭算法:watershed() 参考博客: OpenCV-分水岭算法 图像处理--分水岭算法 OpenCV学习(7) 分水岭算法(1) Opencv分水岭算法--wat ...

  7. 算法导论 之 红黑树 - 添加[C语言]

    作者:邹奇峰 邮箱:Qifeng.zou.job@hotmail.com 博客:http://blog.csdn.net/qifengzou 日期:2013.12.24 21:00 转载请注明来自&q ...

  8. 数据结构 - 学习笔记 - 红黑树

    数据结构 - 学习笔记 - 红黑树 定义 简介 知识点 1. 结点属性 2. 前驱.后继 3. 旋转 查找 插入 父结点为黑色 父结点为红色 1. 有4种情形只需要变色(对应234树4结点) 1.1. ...

  9. 《MATLAB智能算法30个案例》:第23章 基于蚁群算法的二维路径规划算法

    <MATLAB智能算法30个案例>:第23章 基于蚁群算法的二维路径规划算法 1. 前言 2. MATLAB 仿真示例 3. 小结 1. 前言 <MATLAB智能算法30个案例分析& ...

最新文章

  1. 软考高项之各大管理计划内容-攻坚记忆
  2. myeclipse maven 创建 web项目
  3. login控件authenticate_asp.net Login控件基本属性及事件说明
  4. 【clickhouse】clickhouse 原生监控
  5. java future 不足_java Future用法和意义一句话击破
  6. 前端人最需要的学习资料有哪些?我现在免费送给你!
  7. nginx1.6.2编译安装
  8. 赚不到钱的5大原因!
  9. linux 固态硬盘 分区工具,固态硬盘怎么分区?使用免费分区助手轻松搞定!
  10. 修改服务器线路,介绍几种常见的网络服务器线路
  11. ASP.NET Core 在 IIS 上的进程内 (InProcess) 托管
  12. 【备忘】Oracle商业智能BI产品OBIEE11G深入浅出全套视频教程
  13. 使用vuepress搭建一个完全免费的个人网站
  14. API网关之Kong初识
  15. UI设计需要学会哪些软件?
  16. QT窗口:透明与半透明、不规则异形窗口、控件透明与半透明、不规则异形按钮
  17. Linux动物乐园 Ubuntu版本代号赏析
  18. 网神通留言本群发 v3.0 免费
  19. php中reset是什么意思,路由器的RESET是什么意思有什么用
  20. C-Lodop提示“有窗口已打开,先关闭它(持续如此请刷新页面)!”

热门文章

  1. python创建数组
  2. 设计模式 -责任链模式
  3. 通俗易懂的讲解CPU/GPU/TPU/NPU/XPU/…
  4. 2T架构师教学视频打包分享
  5. 风炫安全Web安全学习第二节课 HTML基础
  6. 以前总觉得PPT的SmartArt功能太丑,用过之后,真香
  7. 20181030 周二 日记
  8. 360详解儿童手表背后技术:五颗芯片共同定位
  9. 20170220找女朋友之路思考总结
  10. OpenGL ES之VBO、EBO与VAO的说明和使用