数据结构与算法学习笔记(十)

1.红黑树

红黑树是一种自平衡二叉查找树,它保证了每个节点在树中的黑色深度相同,并且满足以下性质:

  1. 节点要么是黑色,要么是红色。

  2. 根节点是黑色的。

  3. 叶子节点都是黑色的空节点。

  4. 如果一个节点是红色的,则它的两个子节点都是黑色的。

  5. 对于每个节点,从该节点到其子孙节点的所有路径上包含相同数目的黑色节点。

通过这些性质,红黑树可以保证在插入和删除节点时能够自动地平衡树的结构,从而保证了查找、插入、删除等操作的时间复杂度为O(logn)。

红链所连的两个的节点可以合看成一个3-节点,合为一个节点,拥有三个子节点。

黑链所连为一般父子节点关系。

这里我们实现的是左偏红黑树,其中只有父节点与左节点链接处才为红链,根节点处不为红链(特殊),且红链不可连续,比如两个子节点与父节点相连都不能为红链。

 

我们是要创建一种自平衡二叉查找树(它通过保证左右子树的高度差小于等于1,来保持树的平衡),要控制树的高度平摊,不能像之前一样,添加节点使得树长的歪七扭八。

始终保持插入节点时,节点链接为红链,在之后的调整中进行黑红链的整改。

整改情况与措施:

1.如果子父连续红链,使用右旋法加颜色反转法。

2.如果两子节点都为红链,使用颜色反转法。

3.如果右子节点为红链,使用左选法。

2.左旋法

Node* rotateLeft(Node* node_h)
	{
		Node* node_x = node_h->right;	//先把h节点的右节点取出

		node_h->right = node_x->left;	//换个向,使得红链接在左边的同时使得节点有序

		node_x->left = node_h;

		node_x->color = node_h->color;

		node_h->color = RED;

		return node_x;
	}

出现了右节点红链,需要把红链移到左节点,移动后,父子节点值要进行改动(父节点大于左子节点,小于右子节点),且介于父子节点的节点也转换位置。

1.先取出父节点的右子节点

2.设父节点的右子节点为原右子节点的左节点(介于父子节点的节点)

3.设原右子节点的左节点为父节点

4.返回原右子节点,让原父节点的父节点指向

3.右旋法

Node* rotateRight(Node* node_h)
	{
		Node* node_x = node_h->left;

		node_h->left = node_x->right;

		node_x->right = node_h;

		node_x->color = node_h->color;

		node_h->color = RED;

		return node_x;
	}

1.先取出父节点的左子节点

2.让父节点的左子节点为原左子节点的右节点

3.让原左子节点的右节点为原父节点

4.返回原左子节点,让原父节点的父节点指向

左右旋如此”别扭“的目的:保持树的平衡

4.颜色反转法

	void flipColor(Node* node)		//颜色反转
	{
		node->color = RED;

		node->left->color = BLACK;
		node->right->color = BLACK;
	}

字面意思,维持树的性质

添加数据后,再做些判断使用以上三个方法

添加函数put():

void put(int key, string value)
	{
		root=put(root, key, value);

		if (root->left != NULL)            /*两个if为特殊情况处理,根节点的两个左右子节点链
		{                                    不为红链*/
			root->left->color = BLACK;
		}
		

		if (root->right != NULL)
		{
			root->right->color = BLACK;
		}
	}

Node* put(Node* node,int key, string value)
	{
		if (node == NULL)
		{
			N++;
			return new Node(key, value,NULL,NULL, RED);
		}

		if (key < node->key)
		{
			node->left = put(node->left, key, value);
		}
		else if(key>node->key)
		{
			node->right = put(node->right, key, value);
		}
		else
		{
			node=new Node(key, value, NULL, NULL, RED);
		}

		//进行左旋
		if (node->right->color == RED)
		{
			node=rotateLeft(node);
			return node;
		}

		//进行右旋
		if (node->left->color == RED && node->left->left->color == RED)
		{
			cout << value << endl;
			cout << N << endl;
			node=rotateRight(node);
		}

		//进行反转
		if (node->left->color == RED && node->color == RED)
		{
			flipColor(node);
		}
		return node;
	}

如果还是不解,可以了解下自平衡二叉查找树,并结以草图推导以上三个函数。

红黑树的高度比一般二叉查找树的要矮,查找其数据也就更高效,一般被用于实现高效的搜索算法。它不会出现极端情况,比如一颗二叉树从根节点开始就一直往左节点添加,那么查找最小值时是很耗费时间的。

整体代码如下(上传代码包好像太过于麻烦了):

#include <iostream>

using namespace std;

class Node
{
public:
	Node(int key, string value, Node* left, Node* right,bool color)
	{
		this->key = key;
		this->value = value;
		this->left = left;
		this->right = right;
		this->color = color;
	}

	Node* left;
	Node* right;
	int key;
	string value;
	bool color;
};

class RedBlackTree
{
private:
	Node* root;
	int N;
	bool RED;
	bool BLACK;

public:

	RedBlackTree()
	{

		root = NULL;
		N = 0;
		RED = true;
		BLACK = false;
	}

	bool isRED(Node* node)
	{
		if (node == NULL)
		{
			return false;
		}
		if (node->color == RED)
		{
			return true;
		}

		return false;
	}

	Node* rotateLeft(Node* node_h)
	{
		Node* node_x = node_h->right;	//先把h节点的右节点取出

		node_h->right = node_x->left;	//换个向,使得红链接在左边的同时使得节点有序

		node_x->left = node_h;

		node_x->color = node_h->color;

		node_h->color = RED;

		return node_x;
	}

	Node* rotateRight(Node* node_h)
	{
		Node* node_x = node_h->left;

		node_h->left = node_x->right;

		node_x->right = node_h;

		node_x->color = node_h->color;

		node_h->color = RED;

		return node_x;
	}

	void flipColor(Node* node)		//颜色反转
	{
		node->color = RED;

		node->left->color = BLACK;
		node->right->color = BLACK;
	}

	void put(int key, string value)
	{
		root=put(root, key, value);

		if (root->left != NULL)
		{
			root->left->color = BLACK;
		}
		

		if (root->right != NULL)
		{
			root->right->color = BLACK;
		}
	}

	Node* put(Node* node,int key, string value)
	{
		if (node == NULL)
		{
			N++;
			return new Node(key, value,NULL,NULL, RED);
		}

		if (key < node->key)
		{
			node->left = put(node->left, key, value);
		}
		else if(key>node->key)
		{
			node->right = put(node->right, key, value);
		}
		else
		{
			node=new Node(key, value, NULL, NULL, RED);
		}

		//进行左旋
		if (node->right->color == RED)
		{
			node=rotateLeft(node);
			return node;
		}

		//进行右旋
		if (node->left->color == RED && node->left->left->color == RED)
		{
			cout << value << endl;
			cout << N << endl;
			node=rotateRight(node);
		}

		//进行反转
		if (node->left->color == RED && node->color == RED)
		{
			flipColor(node);
		}
		return node;
	}

	string get(int key)
	{
		return get(root, key);
	}

	string get(Node* node, int key)
	{
		if (node == NULL)
		{
			return "无此键值";
		}

		int result = key - node->key;

		if (result==0)
		{
			return node->value;
		}

		if (result<0)
		{
			return get(node->left, key);
		}
		else
		{
			return get(node->right,key);
		}
	}

	int size()
	{
		return N;
	}
};

int main()
{
	RedBlackTree RBtree;

	RBtree.put(1, "张三");
	RBtree.put(2, "李四");
	RBtree.put(3, "王五");

	cout << RBtree.get(1) << endl;
	cout << RBtree.get(2) << endl;
	cout << RBtree.get(3) << endl;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值