【一份代码搞定数据结构】红黑树(更新中)

在介绍红黑树之前先说明什么是二叉查找树和平衡二叉树。

一、二叉查找树(BST)

1 . 二叉查找树本身就是一个空树。

2 . 左子树的数值 < 根节点 < 右子树的数值。

基本四个操作:查找 , 插入 , 建树 , 删除。由于不是重点要说明的,所以只是贴出来用一下。

#include<iostream>
using namespace std;

struct node{
	int data;
	node* lchild;
	node* rchild;
};

node* newNode(int x){
	node* Node = new node;
	Node->data = x;
	Node->lchild = NULL:
	Node->rchild = NULL;
	return Node;
} 

void search(node* root , int x){
	//根节点的数值// 
	if(root == NULL){
		printf("search failed!\n");
		return ;
	}
	//找到的话// 
	if(x == root->data){
		printf("%d\n" , root->data);
	}
	//比它小,往左走// 
	else if(x < root->data){
		search(root->lchild , x);
	}
	//比它大 ,往右走// 
	else{
		search(root->rchild , x);
	}
}

//插入操作//
void insert(node* root , int x){
	if(root == NULL){
		root = newNode(x);
		return ;
	}
	if(x == root->data){
		return ;
	}
	else if(x < root->lchild){
		insert(root->lchild , x);
	}
	else{
		insert(root->rchild , x);
	}
} 
//辅助删除函数,用于找一个数值的节点// 
node* findMax(node* root){
	while(root->rchild != NULL){
		root = root->rchild;
	}
	return ;
}

node* findMin(node* root){
	while(root->lchild != NULL){
		root = root->lchild;
	}
	return ;
}

void deleteNode(node* &root , int x){
	//范围// 
	if(root == NULL){
		return ;
	}
	//当输入的数值和要删除的数值是一样的话// 
	if(root->data == x){
		//本身数值没有左右子节点,放空即可// 
		if(root->lchild == NULL && root->rchild == NULL){
			root = NULL;
		}
		//如果左结点不空的时候// 
		else if(root->lchild != NULL){
			//删除结点的数值// 
			node* pre = findMax(root->lchild);
			root->data = pre->data;
			deleteNode(root->lchild , pre->data);
		}
		//如果右结点不空的时候// 
		else{
			node* next = findMin(root->rchild);
			root->data = next->data;
			deleteNode(root->rchild , next->data);
		}
	//如果找的左右节点的数值不一样的话,接着找.// 
	else if(root->data > x){
		deleteNode(root->lchild , x);
	}
	else{
		deleteNode(root->rchild , x);		
	} 
}

 

二、平衡二叉树(AVL)

平衡二叉树最关键的一点就是结点的平衡因子。所谓平衡因子就是左子树的数值和右子树的高度差。当每个结点的平衡因子的数值的决定不超过1的时候,即为平衡二叉树。

基本操作几乎一致,主要是旋转注意一下。

#include<iostream>
using namespace std;

struct node{
	int v ;
	int height;//当前结点高度// 
	node* lchild;
	node* rchild;
}; 

//创建结点//
node* newNode(int v){
	node* Node = new node;
	Node->v = v;
	Node->height = 1;
	Node->rchild = NULL;
	Node->lchild = NULL;
	return Node;
} 

//结点高度函数//
int getheight(node* root){
	//结点为空// 
	if(root == NULL)	
		return 0;
	return root->height;
} 

//平衡因子的计算//
int getBalance(node* root){
	return getheight(root->lchild) - getheight(root->rchild);
} 

//更新结点的高度//
void updateheight(node *root){
	root->height = max(getheight(root->lchild) , getheight(root->rchild) + 1);
} 

//查找操作//
void search(node* root ,int x){
	if(root == NULL){
		printf("search Falled!\n");
		return ;
	}
	//找到即输出// 
	if(x == root->v){
		printf("%d\n" , root->v);
	}
	//类似二叉搜索树查找// 
	else if(x < root->v){
		search(root->lchild , x);
	}
	else{
		search(root->rchild , x);
	}
} 

//左旋// 
void L(node* &root){
	node *temp = root->rchild;
	root->rchild = temp->rchild;
	temp->lchild = root;
	updateheight(root);
	updateheight(temp);
	root = temp;
}

//右旋//
void R(node* &root){
	node *temp = root->lchild;
	root->lchild = temp->lchild;
	temp->rchild = root;
	updateheight(root);
	updateheight(temp);
	root = temp;
}

void insert(node* &root , int x){
	if(root == NULL){
		root = newNode(x);
		return ;
	}
	//类似平衡二叉树的插入算法 , 加了一点东西// 
	if(x < root->v){
		insert(root->lchild , x);
		//更新高度//
		updateheight(root);
		if(getBalance(root) == 2){
			if(getBalance(root->lchild) == 1){
				R(root);
			}
			else if(getBalance(root->rchild) == -1){
				L(root->lchild);
				R(root);
			}
		}
	}
	else{
		insert(root->rchild , x);
		updateheight(root);
		if(getBalance(root) == -2){
			if(getBalance(root->lchild) == -1){
				L(root);
			}
			else if(getBalance(root->rchild) == 1){
				R(root->rchild);
				L(root);
			}
		}
	}
}

//新建二叉树// 
node* creat(int data[] , int n){
	node* root = NULL;
	//循环插入// 
	for(int i = 0 ; i < n ; i ++) {
		insert(root , data[i]);
	}
	return root;
}

 

三、最终进化 -- 红黑树(RBT)

红黑树的起源,自然是二叉查找树。这种树结构从根节点开始,左子节点小于它,右子节点大于它。每个节点都符合这个特性,所以易于查找,是一种很好的数据结构。但是它有一个问题,就是容易偏向某一侧,这样就像一个链表结构了,失去了树结构的优点,查找时间会变坏, 在这种需求下,平衡树的概念就应运而生了

红黑树的用途:

  • STL(标准模板库)中在set map是基于红黑树实现的。
  • Java中在TreeMap使用的也是红黑树。
  • epoll在内核中的实现,用红黑树管理事件块。
  • linux进程调度Completely Fair Scheduler,用红黑树管理进程控制块

红黑树与他们的前辈们的比较:

  • 从实现细节上来讲,如果插入一个结点引起了树的不平衡,AVL树和红黑树都最多需要2次旋转操作,即两者都是O(1);但是在删除node引起树的不平衡时,最坏情况下,AVL需要维护从被删node到root这条路径上所有node的平衡性,因此需要旋转的量级O(logN),而RB-Tree最多只需3次旋转,只需要O(1)的复杂度。

  • 从两种平衡树对平衡的要求来讲,AVL的结构相较RB-Tree来说更为平衡,在插入和删除node更容易引起Tree的unbalance,因此在大量数据需要插入或者删除时,AVL需要rebalance的频率会更高。因此,RB-Tree在需要大量插入和删除node的场景下,效率更高。自然,由于AVL高度平衡,因此AVL的search效率更高。

红黑树的基本的特点:

  1. 根是黑色。
  2. 所有叶子都是黑色(叶子是NIL结点)。
  3. 每个红色结点必须有两个黑色的子结点。(从每个叶子到根的所有路径上不能有两个连续的红色结点。)
  4. 从任一结点到其每个叶子的所有简单路径都包含相同数目的黑色结点。
  5. http://www.cnblogs.com/skywang12345/p/3624202.html
  6. https://www.sohu.com/a/201923614_466939

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值