【记录】红黑树-基本操作(插入、查找、删除)+ 旋转调色(插入调色和删除调色)

开学小半年,Andy家里闲

(省略掉令人头痛的开场部分)

(明明就是偷懒直到最近才想起来更新点博客)

-------------------------------(分割线)---------------------------------

今天我们主讲一波红黑树的实现,作为一个初学小白的总结,也方便和我一样的小白们能获得一篇简单的实(速)现(通)方(教)法(学)。

看过网上很多很多篇关于红黑树的帖子(啊关了浏览器一下子找不到链接...),关于原理以及最最最重要理解的调色和旋转都有讲的非常好的文章

所以提前声明:如果你是想知道“为什么红黑树要这样转/红黑树调色的动画/旋转的演示”这里一定不会讲

这里有的:# 四种插入情况 # 三种删除操作+五(七)种调色方法 #基本的二叉树讲解

首先,复习一下简单的BST的搜索和插入:

1.Left<Parent<Right

搜索一个点:while(now!=Res){

                              if(now<Res)找左孩子
                                      eles if(now>Res)找右孩子
                                      else if(now==Res)   找到啦
                             }
        插入一个点:搜索+返回末节点指针+记录是左/是右孩子
       

啊这时候就有小伙伴要问啦,为什么不讲删除呢? 
       博主不会(doge)(bushi XD)
       因为红黑树的删除无法在BST删除的基础上直接增加函数,有很大的改动,所以就不细说咯
       那么,基于二叉树的结构,再其上进行适当的改造,就可以成为一棵红黑树。         

附上BST代码,有兴趣的小伙伴可以以此为基础尝试将其改造为红黑树

#include<bits/stdc++.h>
using namespace std;	
template<class Key,class Value>
class node {									// 树的节点
public:
	Key key;
	Value data;
	node* left;
	node* right;
	node* parent;
	node<Key,Value>() {
		left = nullptr;
		right = nullptr;
		parent = nullptr;
	}
	~node() {
		left = nullptr;
		right = nullptr;
		parent = nullptr;
	}
};	
template<class Key,class Value>					//泛化编程 以后可以做成自己的头文件(啊 当然二叉搜索树就不做了...本身不优秀)
class BItree {									// BI(二分)tree树 (非完全二叉树)
public:
	typedef node<Key,Value> BItree_node;
	typedef BItree_node* node_ptr;				//typedef换名称 好处多多 还有逼格(bushi)//当然是为了更清楚的表达代码
protected:
	node_ptr header;							//树根
	int size_counter;							//节点数量
public:
	BItree() {
		header = new BItree_node();
		size_counter = 0;						//这里用 0 是因为 用户没有给出数据,不认为new出来的算一个节点
	}
	BItree(Key key,Value data) {
		header = new BItree_node();
		header->key = key;
		header->data = data;
		size_counter = 1;
	}											//构造函数x2
	node_ptr& Search(Key sth) {					//注意这里要返回“引用”
		node_ptr tmp = new BItree_node();
		tmp = header;							//从树根开始//当然我们有另一种写法:传入一个node_ptr指针:search 成为一个通用函数
		if (tmp == NULL) {
			return tmp;
		}										//内存错误调用警告 x1 ,没有if会出事
		while (tmp->key != sth) {		
			if (tmp->key < sth) {
				if (tmp->right == nullptr) {
					return tmp;					
				}tmp = tmp->right;				//这里没有用tmp->parent ,因为不同于STL的设计(其实是我想不出来),叶子节点没有两个 NULL型子节点
			}
			else {
				if (tmp->left== nullptr) {
					return tmp;					//VS警告:返回局部变量或临时变量的地址:tmp //我...没想出来怎么解决这个警告,但是功能是对的
				}tmp = tmp->left;
			}
		}return tmp;
		delete(tmp);
	}
	node_ptr& nxt_mem(node_ptr st) {									//后继: 比当前节点key 大一个单位的 节点
		if (st->right)st = st->right;									//方法: 向右走一个 , 然后一直向左走
		else return st;
		while (st->left) {
			st = st->left;
		}return st;
	}
	node_ptr& pre_mem(node_ptr st) {									//前驱: 比当前节点key 小一个单位的 节点
		if (st->left)st = st->left;										//方法: 向左走一个 , 然后一直向右走
		else return st;
		while (st->right) {
			st = st->right;
		}return st;
	}
	void delete_node(Key key) {	
		node_ptr Res = Search(key);											//定位                                       
		if (Res->key != key) {	
			cout << "the DATA didn't exist" << endl;
			return;
		}
		if (size_counter == 1) {											//如果就一个,直接删除root
			size_counter--;
			delete(Res); return;
		} 
		if (Res->left==nullptr&&Res->right==nullptr) {						//删除的地方是叶子
			if (Res->parent->left == Res)Res->parent->left = nullptr;		//断开叶子与父节点的链接
			if (Res->parent->right == Res)Res->parent->right = nullptr;
			delete(Res); size_counter--;
			return;
		}	
		else if (Res->left == nullptr) {									//左子树为空,上下链接 “链”式删除
			if (Res->parent) {								
				Res->parent->right = Res->right;
				Res->right->parent = Res->parent;
			}																
			else {															//如果是root,更改header指针
				header = Res->right;
			}
			delete(Res); size_counter--;
		}
		else if(Res->right == nullptr){										//对称的
			if (Res->parent) {
				Res->parent->left = Res->left;
				Res->left->parent = Res->parent;
			}
			else {
				header = Res->left;
			}
			delete(Res); size_counter--;
		}
		else {																//左右都有子树
			node_ptr tmp = nxt_mem(Res);									//找到后继节点(比它大一点点的节点)
			if (tmp->right) {												//后继有右子树(因为是后继 所以没有左子树)
				tmp->parent->left = tmp->right;								//仿照删除“链”
				tmp->right->parent = tmp->parent;
			}
			else {
				if (tmp->parent->left == tmp)tmp->parent->left &#
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值