算法导论第13章-红黑树

《算法导论》第三版第13章 红黑树 练习&思考题 个人答案 13.1 红黑树的性质 13.1-1 解: 完全二叉搜索树: 黑高为2的红黑树: 黑高为3的红黑树: 黑高为4的红黑树: 13.1-2 解:如果标红,不满足性质4,因为35是36的父结点,也是红色;如果标黑,不满足性质5,该条路径黑高超过其他路径。 13.1-3 解:可以验证所得到的树仍然满足5个条件,所以是红黑树。 13.1-4 解: (1)如果“吸收”前两个子结点都已经是黑色了,度为2... 阅读详情
   实际应用中,我们不会直接使用二叉搜索树,因为二叉搜索树的性能严重依赖于元素的插入顺序,尤其是当元素以递增的形式插入时,此时的二叉搜素树就会成为一条链表;我们在实际应用中,使用”平衡“二叉搜索树,包括AVL树,红黑树,AA树,最常用的是红黑树(其中STL中关联容器的底层实现都是使用的红黑树),可以保证最坏情况下基本动态集合操作的时间复杂度为O(lgn)


红黑树在每个节点上,增加一个颜色属性,可以是RED或BLACK,由于红黑树的性质,可以保证没有一条路径会比其他路径长出倍,因此是”近似平衡“的,但是红黑树通常能导致良好的平衡状态,经验告诉我们,红黑树的搜索平均效率与AVL树相等


红黑树的性质:
 1.每个结点或者是红色,或者是黑色;
 2.根结点是黑色
 3.每个叶结点(NULL)是黑色
 4.如果一个结点是红色的,则它的两个子结点都是黑色的
 5.对每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点

红黑树的实现策略:
 增加哨兵:T.nil来代表NIL,其中T.nil是与普通结点具有相同属性的对象,所有指向NIL的指针都用指向T.nil的指针替换(主要原因是NIL无法加颜色)
 我们可以像图(a)一样,为每一个叶结点增加哨兵,这样每个NIL的父结点都有良好的定义,但是会浪费大量空间,所以我们只用一个哨兵T.nil来代表所有的NIL:所有的叶结点和根结点的父结点。

可能大家会有疑问,为什么要定义一个T.nil呢?直接用NULL来表示,我们默认为是黑色不就行了吗?STL中确实没有这个哨兵,但是,stl中没有删除操作------据我所知,T.nil的最大作用在于删除操作------它的父结点可以改变为任何一个节点,用于回溯其父结点。


在红黑树的实现中,能够改变子树高度,也就是能够使其不同于一般二叉搜索树的操作是:旋转。旋转可以改变子树的高度,维持红黑树的性质:


左旋(x,y都不是T.nil)提升y,降低x;主要是交换好各自的父子关系:

LEFT-ROTATE(T,x)
 y=x.right
 x.right=y.left
 if y.left!=T.nil
   y.left.p=x
 y.p=x.p
 if x.p==T.nil//x为根
   T.root=y
 else if x==x.p.left
   x.p.left=y
 else
   x.p.right=y
 y.left=x
 x.p=y

右旋:

RIGHT-ROTATE(T,x)
 y=x.left
 x.left=y.right
 if y.right!=T.nil
   y.right.p=x
 y.p=x.p
 if x.p=T.nil
   T.root=y
 elseif x==x.p.left
   x.p.left=y
 else
   x.p.right=y
 y.right=x
 x.p=y


插入操作:

插入操作分为两部分:插入和调整;

假设要插入的节点都为红色,那么红黑树的性质1,3,5不变,当原来的树为空时,会改变性质2;还有可能改变的性质是性质四;

我们之后进行的调整工作就是能够再次使性质2和4保持。

RB-INSERT(T,z)
 y=T.nil
 x=T.root
 while x!=T.nil
   y=x
   if z.key<x.key
     x=x.left
   else
     x=x.right

 z.p=y
 if y==T.nil
   T.root=z
 elseif z.key<y.key
   y.left=z
 else y.right=z
 //下面是比一般二叉搜索树多出来的部分
 z.left=T.nil
 z.right=T.nil
 z.color=RED
 RB-INSERT-FIXUP(T,z)//调整
调整的原则是把破坏规则的节点尽量上移,最坏情况下如果上移到根结点,只要把根结点设置成黑色,就万事大吉。
调整发生在:当插入结点的父结点是红结点时,此时必有祖父结点为黑色,叔父结点未知:

此时有六种情况,下面分析当插入结点的父结点是祖父节点的左孩子时的三种情况:

case1:叔节点为红色(插入节点为左侧插入---外插,或者为右侧插入---内插)

这时候,只要把c遍为红色,B,D变为黑色,blak-height不变,此时,唯一有可能违反性质的节点是C,所以破坏规则的节点上移了。

case2:叔节点是黑色,插入节点是右侧插入---内插:


我们将内侧插入转变为外侧插入,以插入节点的父结点A做左旋,此时令z指向B,变为外侧插入,即第三种情况

case3:叔节点是黑色,插入节点是左侧插入---外插


此时以C为支点,做右旋,然后把B变成黑色,C变成红色即可。

RB-INSERT-FIXUP(T,z)
 while z.p.color==RED
   if z.p==z.p.p.left
     y=z.p.p.right//叔父结点
	 if y.color==RED//case1
	   z.p.color=BLACK
	   y.color=BLACK
	   z.p.p.color=RED
	   z=z.p.p
	 elseif z=z.p.right//case2
	   z=z.p
	   LEFT-ROTATE(T,z)
	   //此时成为外侧插入,执行case3
	   z.p.color=BLACK
	   z.p.p.color=RED
	   RIGHT-ROTATE(T,z.p.p)
   else //插入节点的父结点为祖父节点的右孩子
     将[left]与[right]互换
 T.root.color=BLACK

对于删除操作,也分为删除和调整两部分

首先是删除操作的辅助程序-TRANSPLANT,将以u为根的子树用以v为根的子树替换,通常适用于v是u的唯一子结点时

RB-TRANSPLANT(T,u,v)
 if u.p==T.nil
   T.root=v
 elseif u==u.p.left
   u.p.left=v
 else u.p.rigth=v
 v.p=u.p

删除程序同二叉搜索树,[见二叉搜索树代码解析]

调整:

这次的焦点放在-y:从树中删除的节点或者移至树中的节点(即原来要删除节点的后继)

当y为红色时,直接删除,不违反性质;

当y为黑色时,对于y为删除节点,那么包含y的任意简单路径上黑节点少1;对于y为移动节点,同理;

这里我们采用的策略是:

令x为删除或移动y后顶替位置的元素,那么设x还有一重黑色,但是现在的问题变为:x既不是红色也不是黑色,违反性质1.


当x是其父节点的左孩子时:

case0:

当x是单重黑色,单重红色时,直接令x为黑色,则完成任务;


case1:x是双重黑色,x的兄弟节点w是红色,此时必有x父结点为黑色:


此时我们要做的是:以x的父结点B左旋,使B的颜色变为红色,w的颜色变为黑色,此时除性质1外,其他性质保持

<经过case1之后,x的兄弟节点为黑色>

case2:x是双重黑色,x的兄弟节点w是黑色,且w的两个子结点都是黑色:


此时,令w的颜色变为红色,去掉x的一重黑色,将x父结点上加上一重黑色即可,此时,唯一违反性质的节点是x的父结点。

case3:x是双重黑色,x的兄弟节点w是黑色,w的左孩子是黑色,右孩子是红色:



此时我们将w右旋,且C变为新的w,C的颜色变为黑色,D的颜色变为红色,此时转到第四种情况

case4:x是双重黑色,兄弟节点w是黑色,且w的右孩子是红色:


此时,可以去掉x的一重黑色--如图。

RB-DELETE-FIXUP
 while x!=T.root and x.color==BLACK//此时为两重黑色
  if x=x.p.left//当x为父结点的左孩子
    w=x.p.right//x的兄弟节点
	if w.color==RED//case1
	  w.color=BLACK
	  x.p.color=RED
	  LEFT-ROTATE(T,x.p)
	  w=x.p.right
	if w.left.color==BLACK and w.right.color=BLACK//case2
	  w.color=RED
	  x=x.p
	elseif w.right.color==BLACK//case3
	  w.left.color=BLACK
	  w.color=RED
	  RIGHT-ROTATE(T,w)
	  w=x.p.right
	 //case4
	 w.color=x.p.color
	 x.p.color=BLACK
	 w.right.color=BLACK
	 LEFT-ROTATE(T,x.p)
	 x=T.root
  else 
     left与right互换
 x.color=bBLACK//case0
	  
    

下面附一份STL版的红黑树,简单版的红黑树把二叉搜索树扩展一下即可得到:

//下面使用stl版本的红黑树,简单版的红黑树跟二叉搜索树基本相同,除了插入和删除稍麻烦外。
#include"myconstruct.h"
#include"myiterator.h"
#include"mymemory.h"
#include<utility>
//表示颜色
typedef bool _rb_tree_color_type;
const _rb_tree_color_type _rb_tree_red=false;//红色为0
const _rb_tree_color_type _rb_tree_black=true;//黑色为1
//节点结构
template<typename Value>
struct _rb_tree_node
{
	typedef _rb_tree_color_type color_type;
	typedef _rb_tree_node<Value> node_type;
	
	color_type color;
	Value value_field;
	node_type* parent;
	node_type* left;
	node_type* right;

	static node_type* minimum(node_type* x)
	{
		while(x->left!=0) x=x->left;
		return x;
	}
	static node_type* maximum(node_type* x)
	{
		while(x->right!=0) x=x->right;
		return x;
	}
};

//迭代器设计:
template<typename Value,typename Ref,typename Ptr>
struct _rb_tree_iterator
{
	typedef bidirectional_iterator_tag iterator_category;
	typedef size_t       difference_type;
	typedef _rb_tree_node<Value>  node_type;
	typedef Value  value_type;
	typedef Ref reference;
	typedef Ptr pointer;
	typedef _rb_tree_iterator<Value,Value&,Value*>  iterator;
	typedef _rb_tree_iterator<Value,const Value&,const Value*> const_iterator;
	typedef _rb_tree_iterator<Value,Ref,Ptr>  self;

	node_type* node;//与容器的联系

	_rb_tree_iterator(){}
	_rb_tree_iterator(node_type* x){node=x;}
	_rb_tree_iterator(const iterator& it){node=it.node;}

	reference operator*() const {return node->value_field;}
	pointer   operator->() const{return &(operator*());}

	self& operator++(){increment();return *this;}
	self  operator++(int){self tmp=*this;increment();return tmp;}

	self& operator--(){decrement();return *this;}
	self   operator--(int){self tmp=*this;decrement();return tmp;}

	bool operator== (const self& x)const{return x.node==node;}
	bool operator!=(const self& x)const{return x.node!=node;}
private://辅助程序
	void increment();//后继
	void decrement();//前驱
};
//-------------------------------------------------------------------------------------------
/*返回中序遍历时,x的后继,其中二叉搜索树的结构允许我们不通过任何关键字的比较获得O(h):
 *case1:如果x的右子树非空,那么后继y是x右子树的最小元素
 *case2:如果x的右子树为空:
 *          case1’:如果x是父结点的左孩子,那么x的后继为父结点
 *          case2’:如果x是父结点y的右孩子,那么寻找这样一个节点z,使x,y所在的子树为z的左子树
 */
template<typename Value,typename Ref,typename Ptr>
void _rb_tree_iterator<Value,Ref,Ptr>::increment()
{
	if(node->right!=0){//case1
		node=node_type::minimum(node->right);
	}else{//case2
		//case1':
		node_type* y= node->parent;
		//case2':
		while(node==y->right){
			node=y;
			y=y->parent;
		}
		if(node->right!=y)
			node=y;
	}
}
//----------------------------------------------------------------------------------------
/*返回中序遍历时,x的前驱:O(h)
 *case1:x有左子树,那么x的前驱是x左子树的最大值;
 *case2:x无左子树
 *         case1’:x是其父结点y的右孩子,那么前驱为y
 *         case2’:x是其父结点y的左孩子,寻找祖先z,使x,y所在子树是z的右子树
 */
template<typename Value,typename Ref,typename Ptr>
void _rb_tree_iterator<Value,Ref,Ptr>::decrement()
{
	if(node->color==_rb_tree_red&&node->parent->parent==node)//header
		node=node->right;
	else if(node->left!=0){//case1
		node=node_type::maximum(node->left);
	}else{//case2
		//case1':
		node_type* y=node->parent;
		//case2':
		while(node==y->left){
			node=y;
			y=y->parent;
		}
		node=y;
	}
}
//----------------------------------------------------------------------------------------------
//红黑树
template<typename Key,typename Value,typename KeyOfValue,typename Compare,
	typename Alloc=alloc>
	class rb_tree
	{
	protected:
		typedef void* void_pointer;
		typedef _rb_tree_node<Value> node_type;
		typedef simple_alloc<node_type,Alloc> rb_tree_node_allocator;
		typedef _rb_tree_color_type color_type;
	public:
		typedef Key  key_type;
		typedef Value value_type;
		typedef value_type* pointer;
		typedef const value_type* const_pointer;
		typedef value_type&  reference;
		typedef const value_type& const_reference;
		typedef size_t size_type;
		typedef size_t  difference_type;

		typedef _rb_tree_iterator<value_type,reference,pointer> iterator;

	protected://内存管理
		//配置一个节点
		node_type* get_node(){return rb_tree_node_allocator::allocate();}
		//释放一个节点
		void           put_node(node_type* p){rb_tree_node_allocator::deallocate(p);}
		node_type* create_node(const value_type& x){node_type* tmp=get_node();
		construct(&tmp->value_field,x);
		return tmp;
		//可以直接使用new,不过需要节点定义构造函数
		}
		node_type* clone_node(node_type* x);//复制一个节点
		void destroy_node(node_type* p){destroy(&p->value_field);//析构内容
		put_node(p);//可以直接使用delete,但是需要定义析构函数
		}
		
	protected:
		size_type node_count;
		node_type* header;//红色,技巧性实现
		Compare key_compare;//函数对象,用于比较

		node_type*& root() const{return header->parent;}
		node_type*& leftmost() const{return header->left;}
		node_type*& rightmost()const{return header->right;}
		//用于取得节点的值
		static node_type*& left(node_type* x){return x->left;}
		static node_type*& right(node_type* x){return x->right;}
		static node_type*& parent(node_type* x){return x->parent;}
		static reference   value(node_type* x){return x->value_field;}
		static const Key& key(node_type* x){return KeyOfValue()(value(x));}
		static color_type& color(node_type* x){return x->color;}
		
	private:
		iterator _insert(node_type* x,node_type* y,const value_type& v);
		void init();
		void clear();

	public://构造和析构
		rb_tree(const Compare& comp=Compare())
			:node_count(0),key_compare(comp){init();}
		~rb_tree(){clear();put_node(header);}
		rb_tree<Key,Value,KeyOfValue,Compare,Alloc>&
			operator=(const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& x);
	public:
		Compare key_comp() const{return key_compare;}
		iterator  begin(){return leftmost();}//红黑树的最小元素
		iterator end(){return header;}//header作为终点
		bool empty()const{return node_count==0;}
		size_type size() const{return node_count;}
		size_type max_size() const{return size_type(-1);}//?
	public:
		//不允许节点值重复
		std::pair<iterator,bool>  insert_unique(const value_type& x);
		//允许节点值重复
		iterator insert_equal(const value_type& x);
		iterator find(const Key& k);
	};
//----------------------------------------------------------------------------------------
	
    template<typename Key,typename Value,typename KeyOfValue,typename Compare,
	typename Alloc>
	typename rb_tree<Key,Value,KeyOfValue,Compare,Alloc>::node_type*
	rb_tree<Key,Value,KeyOfValue,Compare,Alloc>::clone_node(node_type* x)
	{
		node_type tmp=create_node(x->value_field);
		tmp->color=x->color;
		tmp->left=0;
		tmp->right=0;
		return tmp;
	}
//----------------------------------------------------------------------------------------------
	template<typename Key,typename Value,typename KeyOfValue,typename Compare,
	typename Alloc>
	void  rb_tree<Key,Value,KeyOfValue,Compare,Alloc>::init()
	 {//header左右子结点指向自己
		 header=get_node();
		 color(header)=_rb_tree_red;
		 root()=0;
		 leftmost()=header;
		 rightmost()=header;
	}
//----------------------------------------------------------------------------------------
template<typename Key,typename Value,typename KeyOfValue,typename Compare,
	typename Alloc>
typename rb_tree<Key,Value,KeyOfValue,Compare,Alloc>::iterator
rb_tree<Key,Value,KeyOfValue,Compare,Alloc>::insert_equal(const Value& v)
{
	node_type* y=header;
	node_type* x=root();
	while(x!=0){//从根节点开始
		y=x;
		x=key_compare(KeyOfValue()(v),key(x))?left(x):right(x);
		//遇大往左走,遇小于等于往右走
	}
	return _insert(x,y,v);//y为插入点的父结点,x为插入点
}
//---------------------------------------------------------------------------------------------
template<typename Key,typename Value,typename KeyOfValue,typename Compare,
	typename Alloc>
std::pair<typename rb_tree<Key,Value,KeyOfValue,Compare,Alloc>::iterator,bool>
rb_tree<Key,Value,KeyOfValue,Compare,Alloc>::insert_unique(const Value& v)
{
	node_type* y=header;
	node_type* x=root();
	bool comp=true;
	while(x!=0){
		y=x;
		comp=key_compare(KeyOfValue()(v),key(x));
		x=comp?left(x):right(x);
	}

	iterator j=iterator(y);
	if(comp){//离开while时,comp为真,插于左侧
		if(j==begin())//如果插入点父结点为最左节点
			return std::pair<iterator,bool>(_insert(x,y,v),true);
		else
			--j;
	}
	if(key_compare(key(j.node),KeyOfValue()(v)))//新键值不与既有节点值重复
		return std::pair<iterator,bool>(_insert(x,y,v),true);

	//至此,则重复
	return std::pair<iterator,bool>(j,false);
}
//------------------------------------------------------------------------------------
template<typename Key,typename Value,typename KeyOfValue,typename Compare,
	typename Alloc>
typename rb_tree<Key,Value,KeyOfValue,Compare,Alloc>::iterator
rb_tree<Key,Value,KeyOfValue,Compare,Alloc>::_insert(node_type* x,node_type* y,
const Value& v)
{
	node_type* x_copy=x;
	node_type* y_copy=y;
	node_type* z;

	if(y==header||x!=0||key_compare(KeyOfValue()(v),key(y))){
		z=create_node(v);
		left(y)=z;
		if(y==header){
			root()=z;
			rightmost()=z;
		}else if(y==leftmost()){
			leftmost()=z;
		}
	}else{
		z=create_node(v);
		right(y)=z;
		if(y==rightmost()){
			rightmost()=z;
		}
	}
		parent(z)=y;
		left(z)=0;
		right(z)=0;
		z->color=_rb_tree_red;
		_rb_insert_fixup(z,header->parent);
		++node_count;
		return iterator(z);
}
//--------------------------------------------------------------------------------------------
template<typename Key,typename Value,typename KeyOfValue,typename Compare,
	typename Alloc>
typename rb_tree<Key,Value,KeyOfValue,Compare,Alloc>::iterator
rb_tree<Key,Value,KeyOfValue,Compare,Alloc>::find(const Key& k)
{
	node_type* y=header;
	node_type* x=root();
	while(x!=0){
		if(!key_compare(key(x),k))//x大于k
			y=x,x=left(x);
		else
			x=right(x);
	}
	iterator j=iterator(y);
	return (j==end()||key_compare(k,key(j.node)))?end():j;
}
//------------------------------------------------------------------------------------------

template<typename Key,typename Value,typename KeyOfValue,typename Compare,
	typename Alloc>
	void rb_tree<Key,Value,KeyOfValue,Compare,Alloc>::clear()
{
	for(iterator it=begin(),next=++it;it!=end();++next){
		destroy_node(it.node);
		it=next;
	}
}
//-----------------------------------------------------------------------------------------
//全局函数1--左旋
template<typename Value>
void _rb_left_rotate(_rb_tree_node<Value>* x,_rb_tree_node<Value>*&  root)
{
	_rb_tree_node<Value>* y=x->right;
	x->right=y->left;
	if(y->left!=0){
		y->left->parent=x;
	}
	y->parent=x->parent;
	if(x==root)
		root=y;
	else if(x==x->parent->left){
		x->parent->left=y;
	}else
		x->parent->right=y;
	y->left=x;
	x->parent=y;
}
//全局函数2-右旋
template<typename Value>
void _rb_right_rotate(_rb_tree_node<Value>* x,_rb_tree_node<Value>*&  root)
{
	_rb_tree_node<Value>* y=x->left;
	x->left=y->right;
	if(y->right!=0)
		y->right->parent=x;
	y->parent=x->parent;

	if(x==root)
		root=y;
	else if(x==x->parent->right)
		x->parent->right=y;
	else 
		x->parent->left=y;
	y->right=x;
	x->parent=y;
}
//----------------------------------------------------------------------------------------
//全局函数三
template<typename Value>
void _rb_insert_fixup(_rb_tree_node<Value>* x,_rb_tree_node<Value>*&  root)
{
	while(x!=root && x->parent->color==_rb_tree_red){
		if(x->parent==x->parent->parent->left){
			_rb_tree_node<Value>* y=x->parent->parent->right;//y为x的叔父结点
			if(y&&y->color==_rb_tree_red){//case1
				x->parent->color=_rb_tree_black;
				y->color=_rb_tree_black;
				x->parent->parent->color=_rb_tree_red;
				x=x->parent->parent;
			}else{
				if(x==x->parent->right){//case2
					x=x->parent;
					_rb_left_rotate(x,root);
				}
				//case3
				x->parent->color=_rb_tree_black;
				x->parent->parent->color=_rb_tree_red;
				_rb_right_rotate(x->parent->parent,root);
			}
		}
		else{//对称的三种情况
			_rb_tree_node<Value>* y=x->parent->parent->left;
			if(y&&y->color==_rb_tree_red){//case1
				x->parent->color=_rb_tree_black;
				y->color=_rb_tree_black;
				x->parent->parent->color=_rb_tree_red;
				x=x->parent->parent;
			}else{
				if(x==x->parent->left){//case2
					x=x->parent;
					_rb_right_rotate(x,root);
				}
				//case3
				x->parent->color=_rb_tree_black;
				x->parent->parent->color=_rb_tree_red;
				_rb_left_rotate(x->parent->parent,root);
			}
		}
	}
	root->color=_rb_tree_black;
}



学习 《算法导论》第13章 红黑树 总结二 学习 《算法导论》第13章 红黑树 总结二在学习 《算法导论》第13章 红黑树 总结一中学习了红黑树的五个性质,红黑树的结构定义以及旋转。这节学习红黑树的插入和删除操作。红黑树的插入在一棵n个结点的红黑树中插入一个新结点的操作可以在O(lgn)时间内完成。红黑树的插入分为两步:第一步:把红黑树当成是一棵普通的二叉查找树,把新结点插入这棵二叉查找树;第二步:为保证红黑树的性质,将插入的新结点着色.第一 阅读详情

相关推荐

算法导论第13(十三)章红黑树

红黑树是一般的二叉查找树的一种较为”平衡的“

z84616995z的专栏 1万+

《算法导论》第13章 红黑树

  《算法导论》第13章红黑树,内容及练习题。百度网盘:链接:https://pan.baidu.com/s/1yl7GxuhNs5_oAa2nYd_jJg 密码:6r3f 转载于:https://www.cnblogs.com/lijunqiang1997/p/8981713.html...

weixin_30613433的博客 112

【论文阅读】AU检测|《Deep Adaptive Attention for Joint Facial Action Unit Detection and Face Alignment》

摘要 本文旨在从大量没有人工标注的视频中学习用于面部动作单元检测的区分表示。受面部动作是面部肌肉运动这一事实的启发,论文将这些运动描述为不同帧中两幅面部图像之间的转换,并将其用作学习表示的自我监控信号。但是,在不受控制的情况下,这种转换是由面部动作和头部运动引起的。为了消除头部运动的影响,我们提出了一个双圈自动编码器(TCAE),它可以解开面部动作相关运动和头部运动相关运动。具体而言,TCAE被训练成分别将源面部的面部动作和头部姿态改变为目标面部的面部动作和头部姿态。我们的实验验证了TCAE解耦运动的能力。

Celine的博客 4554

算法导论 第13章 红黑树

一、概念 1.定义与性质 (1)定义 红黑树字义:满足(a)每个结点或是红的,或是黑的(b)根结点是黑的(c)每个叶结点(NIL)是黑的(d)如果一个结点是红的,则它的两个儿子是黑的(e)对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点的二叉查找树称为红黑树。 黑高度定义:从某个结点x出发(不包括该结点)到达一个叶结点的任意一条路径上的黑色结点的个数称为x的黑高度。 (2

幸福在路上 1万+

秦时明月6.2魔改版_从零到一部署指南_含安卓客户端配置与GM后台直通

本文提供《秦时明月》6.2魔改版从零开始的完整部署指南。详细讲解CentOS服务器环境准备、服务端文件部署与安装、关键端口开放及进程验证。重点涵盖安卓客户端APK的IP修改与重签名方法,并介绍了GM后台工具的访问与使用,助你快速搭建并管理专属游戏服务器。

garlic的博客 311

深度学习入门:一文详解BP神经网络

在BP神经网络中,输入层和输出层的节点个数都是确定的,而隐含层节点个数不确定,那么应该设置为多少。实际上,隐含层节点个数的多少对神经网络的性能是有影响的,有一个经验公式可以确定隐含层。上面是对隐含层和输出层之间的权值和输出层的阀值计算调整量,而针对输入层和隐含层和隐含层的阀值调。在BP神经网络中,输入层节点没有阀值。神经网络,神经网络在机器学习中应用比较广泛,比如函数逼近,模式识别,分类,数据压缩,数据。要求输入模式要有足够的随机性,对输入模式的噪声比较敏感,即对于剧烈变化的输入模式,训。

Machine Learning with Tutors 4万+

《算法导论》第 13 章 - 红黑树

红黑树是一种高效的自平衡二叉搜索树,通过颜色标记和旋转操作维护平衡性,确保查找、插入、删除等操作的时间复杂度为O(logn)。本文系统介绍了红黑树的五大性质、核心旋转操作,以及插入和删除的详细实现逻辑。文中提供了完整的C++代码实现,包括节点结构定义、左旋/右旋操作、插入修复和删除修复等关键算法,并附有测试用例展示红黑树的实际应用。相比AVL树,红黑树采用"宽松平衡"策略,更适合频繁修改的场景,被广泛应用于C++ STL、Java集合框架等标准库中。代码实现中采用哨兵节点技巧简化边界处理

2302_80961196的博客 1319

智驾域控制器硬件架构:从接口丛林到算力核心的工程解码

本文深入解析了智驾域控制器硬件架构的设计挑战与工程实践。面对复杂的接口丛林,文章详细探讨了如何高效融合摄像头、雷达等多源传感器数据,并构建以多SOC为核心的强大算力平台。同时,文章强调了电源、时钟、散热等最小系统及车规级可靠性设计的关键作用,为工程师提供了从接口驯服到算力核心协同的完整硬件解码指南。

happy2的博客 482

学习 《算法导论》第13章 红黑树 总结一

学习 《算法导论》第13章 红黑树 总结一前面学习了二叉查找树,我们知道一棵高度为h的二叉查找树实现的任何一种动态集合操作,其时间都是O(h); 但若二叉查找树退化为n个结点的线性链后,则最坏情况运行时间为O(n); 下面说的红黑树能保证在最坏情况下,任何一种动态集合操作的运行时间为O(h);红黑树介绍红黑树是一种二叉查找树,但在每个结点上增加了一个存储位表示结点的颜色,可以是RED或BLACK;通

wan198809的专栏 1847

Python处理高光谱数据#3 降维

基于Python的高光谱降维操作 高光谱数据:点击此处可下载 用到的库:matplotlib、scipy、spectral 主要内容:主成分分析(PCA)与线性判别(LDA) 欢迎有兴趣的朋友交流指点。最后,废话不多说直接上代码???? import matplotlib.pyplot as plt from scipy.io import loadmat import spectral as spy

qq_273058791的博客 6937

MATLAB 论文复现——面向电量-调频-容量市场的数据中心园区算力及电力资源规划

如何在保证数据中心服务质量的前提下,考虑数据中心负荷转移特性,并对其进行合理规划,对降低数据中心规划总成本及提升新型电力系统灵活性均有显著意义。然后,根据不同电力市场的结算规则,研究了数据中心园区参与电量-调频-容量市场的方式和经济收益。在此基础上,以综合成本最小化为目标,优化数据中心园区发电机、储能的建设容量以及服务器的建设数量。最后,以阿里巴巴公开运行数据为例,证明考虑多元电力市场能够大大降低数据中心规划成本,激励数据中心园区投资建设更多灵活性资源,为电网提供有效的调频服务和容量支撑。

sjr1478的博客 667

学习 《算法导论》第13章 红黑树 总结三

学习 《算法导论》第13章 红黑树 总结三今天把这编博客写完吧,这里学习红黑树的删除操作,前面学习了 红黑树的定义及旋转 红黑树的插入操作红黑树的删除操作也要结合二叉查找树的删除操作来学习。在一棵n个结点的红黑树中删除一个结点也是一样的,要花O(lgn)的时间,删除操作比插入还要复杂!!!!删除也分为两步:第一步,当成二叉查找树处理,删除一个结点;第二步,修复红黑树的性质;第一步:删除结点第一步

wan198809的专栏 554

深度学习之基于Pytorch手指静脉识别系统(

一、项目背景与目标手指静脉识别技术是一种新兴的生物特征识别技术,它依据人类手指中流动的血液可吸收特定波长的光线这一科学原理,利用手指内的静脉分布图像来进行身份识别。与传统的生物识别技术(如指纹识别)相比,手指静脉识别技术具有不易伪造、识别精度高、非接触性等特点,因此在安全性要求较高的场景(如金融、医疗、公安等)具有广阔的应用前景。本项目旨在利用PyTorch深度学习框架,构建一套高效、准确的手指静脉识别系统。

Q1744828575的博客 832

算法导论-第13章-红黑树

第12章介绍了一棵高度为h的二叉搜索树,它可以支持任何一种基本动态集合操作,如SEARCHSUCCESSORMINIMUMMAXIMUMINSERT和DELETE等,其时间复杂度均为Oh。因此,如果搜素树的高度较低时,这些操作会执行的较快。然而,如果树的高度较高时,这些操作可能不比在链表上执行得快。(red-black tree)是“平衡”搜索树的一种,可以保证在最坏情况下基本动态集合操作得时间复杂度为Ologn。

优快云博客 520

【Python基础】FastAPI 从入门到项目实战操作详解

【Python基础】FastAPI从入门到使用实战操作详解

congge_study的博客 444

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

算法导论 第13章 红黑树(图文详细解说)

二叉查找树的基本操作包括搜索、插入、删除、取最大和最小值等都能够在O(h)时间复杂度内实现,因此能在期望时间O(lgn)下实现,但是二叉查找树的平衡性在这些操作中并没有得到维护,因此其高度可能会变得很高,当其高度较高时,而二叉查找树的性能就未必比链表好了,所以二叉查找树的集合操作是期望时间O(lgn),最坏情况下为O(n)。 红黑树也是一种二叉查找树,它拥有二叉查找树的性质,同时红黑树还

程序缘 3072

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

算法导论 13章 红黑树

红黑树的性质1,每个节点非黑即红。 2,根节点是黑色的。 3,叶节点(NIL)是黑色的。 4,红节点的两个孩子都是黑色的。 5,对每个节点,从该节点到其所有后代的简单路径上,均包含了同样数目的黑节点。 旋转为了维持红黑树的性质,要改变某些节点的颜色和指针结构,旋转改变了指针结构。左旋:以x和y之间的链为“支轴”进行的,使得x的右孩子为y的左孩子,y的父节点为x的父节点,y的左孩子为x。 代码: te

博客 488

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

《算法导论》笔记 第13章 13.1 红黑树的性质

【笔记】 一棵二叉树如果满足下面的红黑性质,则为一棵红黑树 1) 每个节点 【练习】

Azarath Metrion Zinthos 1349

《算法导论》第13章红黑树Java实现与详解

1. 什么是红黑树 (1) 简介 在第12章中介绍了基本动态集合操作时间复杂度均为O(h)的二叉搜索树。但遗憾的是,只有当二叉搜索树高度较低时,这些集合操作才会较快;即当树的高度较高(甚至一种极端情况是树变成了1条链)时,这些集合操作并不比在链表上执行的快。 于是我们需要构建出一种“平衡”的二叉搜索树。 红黑树(red-black tree)正是其中的一种。它...

locallucky的博客 306

【算法导论】第13章,红黑树

红黑树是一种“平衡的”查找树,能确定动态集合操作时间为O(logn) 13.1 红黑树的性质 红黑树的每个节点除了 key, value, p, left, right之外,还有color, 有value的都视为内节点,如果没有儿子,认为儿子都是NIL, 红黑性质:1、每个节点要么红要么黑 2、根节点黑 3、叶子节点(NIL)黑 4、如果节点为红,那么儿子为黑 ...

weixin_30262255的博客 72

红黑树相关算法实现(算法导论13章)

/* * copyright@nciaebupt 转载请保留此标记 * 所有代码已经在linux g++ 下编译通过,直接拷贝运行即可 如有问题欢迎指正 * 红黑树(red-black tree)是许多“平衡的”查找树中的一种。 * 红黑树的性质: * 1、每个结点或是红的,或是黑的。 * 2、根结点是黑的。 * 3、每个叶结点(NIL)是黑的。 * 4、如果一个结点是红的,则它的

nciaebupt 1268

《算法导论》第13章 红黑树 个人笔记

第13章 红黑树 13.1 红黑树的性质 13.2 旋转 13.3 插入 13.4 删除

Amber07的笔记本 500
上一篇: 第十六篇--算法导论排序篇总结-开发实用quicksort算法
下一篇: (二):基二FFT
wangyanphp
博客等级 码龄14年 90粉丝 51原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值