数据结构 —— AVL树

news2024/11/26 6:18:25

目录

1. AVL的概念

2.AVL树的结构

3.AVL树的插入

3.1 平衡因子更新

4. 旋转

4.1 旋转的原则

 4.2 右单旋

4.2.1 右单旋代码实现

4.3 左单旋

4.3.1 左单旋代码实现

4.4 左右双旋

4.4.1 左右双旋代码实现

4.5 右左双旋

​编辑 4.5.1 右左双旋代码实现

5. AVL树的判断

6. AVL树的查找 


1. AVL的概念

1. AVL树是最先发明的⾃平衡⼆叉查找树,AVL是⼀颗空树或者具备下列性质的⼆叉搜索树:它的左右⼦树都是AV树,且左右⼦树的⾼度差的绝对值不超过1

     

2. AVL树是⼀颗⾼度平衡搜索⼆叉树,通过控制⾼度差去控制平衡
     
3. AVL树实现这⾥我们引⼊⼀个平衡因⼦(balance factor)的概念:每个结点都有⼀个平衡因⼦,任何结点的平衡因⼦等于右⼦树的⾼度减去左⼦树的⾼度,也就是说任何结点的平衡因⼦等于0/1/-1

     
AVL树并不是必须要平衡因⼦,但是有了平衡因⼦可以更⽅便我们去进⾏观察和控制树是否平衡,就像⼀个⻛向标⼀样
       
4. AVL树整体结点数量和分布和完全⼆叉树类似,⾼度可以控制在 logN ,那么增删查改的效率也可以控制在 O(logN) ,相⽐⼆叉搜索树有了本质的提升

   

5. 为什么AVL树是⾼度平衡搜索⼆叉树,要求⾼度差不超过1,⽽不是⾼度差是0呢?因为有些情况是做不到⾼度差是0的

    

比如⼀棵树是2个结点,4个结点等情况下,⾼度差最好就是1,⽆法作为⾼度差是0

 


2.AVL树的结构

//节点
template<class K, class V>
struct AVLTreeNode
{
    //需要parent指针,后续更新平衡因?可以看到 
    pair<K, V> _kv;
    AVLTreeNode<K, V>* _left;
    AVLTreeNode<K, V>* _right;
    AVLTreeNode<K, V>* _parent;//加上一个_parent构成三叉列
    int _bf; // balance factor 平衡因子
    AVLTreeNode(const pair<K, V>& kv)
        :_kv(kv)
        , _left(nullptr)
        , _right(nullptr)
        , _parent(nullptr)
        , _bf(0)
    {}
};

//整棵树
template<class K, class V>
class AVLTree
{
    typedef AVLTreeNode<K, V> Node;
public:
private:
    Node* _root = nullptr;
};


3.AVL树的插入

1. 插⼊⼀个值按⼆叉搜索树规则进⾏插⼊

    
2. 新增结点以后,只会影响祖先结点的⾼度,也就是可能会影响部分祖先结点的平衡因⼦,所以更新从新增结点->根结点路径上的平衡因⼦,实际中最坏情况下要更新到根,有些情况更新到中间就可以停⽌了 (更新平衡因子

   
3. 更新平衡因⼦过程中没有出现问题,则插⼊结束(所有的平衡因子绝对值都是小于2的,新增节点的平衡因子一定是0,因为新增的左右孩子都为空

   
4. 更新平衡因⼦过程中出现不平衡,对不平衡⼦树进行旋转,旋转后本质调平衡的同时,本质降低了⼦树的⾼度,不会再影响上⼀层,所以插⼊结束


3.1 平衡因子更新

更新原则:

   
1. 平衡因⼦ = 右⼦树⾼度-左⼦树⾼度(左 - 右 也可以)

   
2. 只有⼦树⾼度变化才会影响当前结点平衡因⼦

   
3. 插⼊结点,会增加⾼度,所以新增结点在parent的右⼦树,parent的平衡因⼦++,新增结点在parent的左⼦树,parent平衡因⼦--

    
4. 是否会继续往上更新取决于parent所在⼦树的⾼度是否变化

更新停⽌条件:

    
1. 更新后parent的平衡因⼦等于0,更新中parent的平衡因⼦变化为-1->0 或者 1->0,说明更新前parent⼦树⼀边⾼⼀边低新增的结点插⼊在低的那边插⼊后parent所在的⼦树⾼度不变,不会影响parent的⽗亲结点的平衡因⼦更新结束

    
2.  更新后parent的平衡因⼦等于1 或 -1,更新前更新中parent的平衡因⼦变化为0->1 或者 0->-1,说明更新前parent⼦树两边⼀样⾼,新增的插⼊结点后,parent所在的⼦树⼀边⾼⼀边低parent所在的⼦树符合平衡要求,但是⾼度增加了1,会影响arent的⽗亲结点的平衡因⼦,所以要继续向上更新

   
3. 更新后parent的平衡因⼦等于2 或 -2,更新前更新中parent的平衡因⼦变化为1->2 或者 -1->-2,说明更新前parent⼦树⼀边⾼⼀边低新增的插⼊结点在⾼的那边,parent所在的⼦树⾼的那边更⾼了,破坏了平衡,parent所在的⼦树不符合平衡要求,需要旋转处理

    

旋转的⽬标有两个:

                                1、把parent⼦树旋转平衡

                                2、降低parent⼦树的⾼度,恢复到插⼊结点以前的⾼度。所以旋转后也不需要继续往上更新,插⼊结束

//如果更新后的parent平衡因子为0,那么就不更新
if (parent->_bf == 0)
{
	break;
}
else if (parent->_bf == 1 || parent->_bf == -1)
{
	//如果更新后的parent平衡因子为1/-1,那么就继续向上更新
	cur = parent;
	parent = parent->parent;
}
else if (parent->_bf == 2 || parent->_bf == -2)
{
	//如果更新后的parent平衡因子为2/-2,那么就不符合平衡要求,需要继续旋转
	// 旋转

	break;
}
else
{
	//如果更新之后的平衡因子不为上面三种情况中的其中一种
	assert(false);
}

1. 更新到10结点,平衡因⼦为2,10所在的⼦树已经不平衡,需要旋转处理

2. 更新到中间结点,3为根的⼦树⾼度不变,不会影响上⼀层,更新结束

3. 最坏更新到根停⽌ 


4. 旋转

4.1 旋转的原则

1. 保持搜索树的规则

   
2. 让旋转的树从不平衡变平衡

    

3. 降低旋转树的高度,也就是恢复成插入之前的高度

    
旋转总共分为四种,左单旋/右单旋/左右双旋/右左双旋


 4.2 右单旋

1. 本图1展⽰的是10为根的树,有a/b/c抽象为三棵⾼度为h的⼦树(h>=0),a/b/c均符合AVL树的要求。10可能是整棵树的根,也可能是⼀个整棵树中局部的⼦树的根。这⾥a/b/c是⾼度为h的⼦树,是⼀种概括抽象表⽰,他代表了所有右单旋的场景,实际右单旋形态有很多种,具体图2/图3/图4/图5进⾏了详细描述

     
2.  在a⼦树中插⼊⼀个新结点,导致a⼦树的⾼度从h变成h+1,不断向上更新平衡因⼦,导致10的平衡因⼦从-1变成-2,10为根的树左右⾼度差超过1,违反平衡规则。10为根的树左边太⾼了,需要往右边旋转,控制两棵树的平衡

    
3. 旋转核⼼步骤,因为5 < b⼦树的值 < 10,将b变成10的左⼦树,10变成5的右⼦树,5变成这棵树新的根,符合搜索树的规则,控制了平衡,同时这棵的⾼度恢复到了插⼊之前的h+2,符合旋转原则。如果插⼊之前10整棵树的⼀个局部⼦树,旋转后不会再影响上⼀层,插⼊结束了 

图1 

 图2

图3

图4

图5

 


 

4.2.1 右单旋代码实现

下图的根节点的平衡因子为-2,即左子树深度过深,需要将左子树旋转,我们将根节点命名为parent,根节点的左节点命名为subL,parent的左孩子的右孩子命名为subLR,我们先将subLR接入parent的左节点,然后判断subLR是否为空,不为空就把subLR的父节点的指针指向parent,然后将subL调整为调整子树的根节点,最后更新平衡因子

 

//右单旋
void RotateR(Node* parent)
{
	//起始位置
	//subL是parent的左节点
	Node* subL = parent->_left;
	Node* subLR = subL->_right;

	//开始旋转
	//parent的左节点是subLR
	parent->_left = subLR;
	//如果subLR不为空  对subLR和parent的父节点进行更新
	if (subLR)
		subLR->_parent = parent;//subLR的父节点为parent

	//如果传入的根节点是一个子树的根节点则需要将旋转后的根节点重新接入原来的节点
	Node* pParent = parent->_parent;

	//subL作为新的根节点
	subL->_right = parent;
	parent->_parent = subL;//parent的根节点为subL

	//旋转的树可能是一个整棵树的子树,还需要和上一层进行链接
	//两种情况:1.parent之前就是根
	if (parent == _root)
	{
		_root = subL;//subL作为新的根
		subL->_parent = nullptr;//subL为根,指向的parent置为空
	}
	else//不是根,那么就一定有parent的parent(pparent)
	{
		//判断之前parent是pparent的左还是右
		if (pParent->_left == parent)
		{
			pParent->_left = subL;
		}
		else
		{
			pParent->_right = subL;
		}

		//链接完之后将subL的Parent指向pParent
		subL->_parent = pParent;
	}

	//更新平衡因子
	subL->_bf = 0;
	parent->_bf = 0;

}


4.3 左单旋


1. 本图6展⽰的是10为根的树,有a/b/c抽象为三棵⾼度为h的⼦树(h>=0),a/b/c均符合AVL树的要求。10可能是整棵树的根,也可能是⼀个整棵树中局部的⼦树的根。这⾥a/b/c是⾼度为h的⼦树,是⼀种概括抽象表⽰,他代表了所有右单旋的场景,实际右单旋形态有很多种,具体跟上⾯左旋类似

   
2. 在a⼦树中插⼊⼀个新结点,导致a⼦树的⾼度从h变成h+1,不断向上更新平衡因⼦,导致10的平衡因⼦从1变成2,10为根的树左右⾼度差超过1,违反平衡规则。10为根的树右边太⾼了,需要往左边旋转,控制两棵树的平衡

   
3. 旋转核⼼步骤,因为10 < b⼦树的值 < 15,将b变成10的右⼦树,10变成15的左⼦树,15变成这棵树新的根,符合搜索树的规则,控制了平衡,同时这棵的⾼度恢复到了插⼊之前的h+2,符合旋转原则。如果插⼊之前10整棵树的⼀个局部⼦树,旋转后不会再影响上⼀层,插⼊结束了

图6


4.3.1 左单旋代码实现

左单旋和右单旋相反

//左单旋
void RotateL(Node* parent)
{
	Node* subR = parent->_right;
	Node* subRL = subR->_left;

	parent->_right = subRL;
	if (subRL)
		subRL->_parent = parent;

	Node* parentParent = parent->_parent;

	subR->_left = parent;
	parent->_parent = subR;

	if (parentParent == nullptr)
	{
		_root = subR;
		subR->_parent = nullptr;
	}
	else
	{
		if (parent == parentParent->_left)
		{
			parentParent->_left = subR;
		}
		else
		{
			parentParent->_right = subR;
		}
		subR->_parent = parentParent;
	}

	parent->_bf = subR->_bf = 0;
}


4.4 左右双旋

通过图7和图8可以看到,左边⾼时,如果插⼊位置不是在a⼦树,⽽是插⼊在b⼦树,b⼦树⾼度从h变成h+1,引发旋转,右单旋⽆法解决问题,右单旋后,我们的树依旧不平衡。右单旋解决的纯粹的左边⾼,但是插⼊在b⼦树中,10为跟的⼦树不再是单纯的左边⾼,对于10是左边⾼,但是对于5是右边⾼,需要⽤两次旋转才能解决,以5为旋转点进⾏⼀个左单旋,以10为旋转点进⾏⼀个右单旋,这棵树这棵树就平衡了

图7 

图8

图7和图8分别为左右双旋中h==0和h==1具体场景分析,下⾯我们将a/b/c⼦树抽象为⾼度h的AVL⼦树进⾏分析,另外我们需要把b⼦树的细节进⼀步展开为8和左⼦树⾼度为h-1的e和f⼦树,因为我们要对b的⽗亲5为旋转点进⾏左单旋,左单旋需要动b树中的左⼦树。b⼦树中新增结点的位置不同,平衡因⼦更新的细节也不同,通过观察8的平衡因⼦不同,这⾥我们要分三个场景讨论

 

场景1:h >= 1时,新增结点插⼊在e⼦树,e⼦树⾼度从h-1并为h并不断更新8->5->10平衡因⼦,引发旋转,其中8的平衡因⼦为-1,旋转后8和5平衡因⼦为0,10平衡因⼦为1

     
场景2:h >= 1时,新增结点插⼊在f⼦树,f⼦树⾼度从h-1变为h并不断更新8->5->10平衡因⼦,引发旋转,其中8的平衡因⼦为1,旋转后8和10平衡因⼦为0,5平衡因⼦为-1

     
场景3:h == 0时,a/b/c都是空树,b⾃⼰就是⼀个新增结点,不断更新5->10平衡因⼦,引发旋转,其中8的平衡因⼦为0,旋转后8和10和5平衡因⼦均为0

 

和下面的图9结合看 

图9 

4.4.1 左右双旋代码实现

如果想区分上面的三种情况,只需要关注更新之后8这个节点的平衡因子 ,平衡因子更新之后是-1就是在e插入,是1就是在f插入,是0节点8自己就是新增

//左右双旋  先进行左旋再进行右旋
void RotateLR(Node* parent)
{
	Node* subL = parent->_left;
	Node* subLR = subL->_right;
	//双旋需要记录subLR的平衡因子
	int bf = subLR->_bf;

	//调用左右单旋
	RotateL(parent->_left);
	RotateR(parent);

	//按照图上的三种情况讨论 
	if (bf == -1)//如果节点8的平衡因子为-1(结合图看)
	{
		//旋转之后
		subLR->_bf = 0;
		subL->_bf = 0;
		parent->_bf = 1;
	}
	else if (bf == 1)
	{
		subLR->_bf = 0;
		subL->_bf = -1;
		parent->_bf = 0;
	}
	else if (bf == 0)
	{
		subLR->_bf = 0;
		subL->_bf = 0;
		parent->_bf = 0;
	}
	else//出现错误直接断言,避免调试
	{
		assert(false);
	}

}

 


4.5 右左双旋

跟左右双旋类似,下⾯我们将a/b/c⼦树抽象为⾼度h的AVL⼦树进⾏分析,另外我们需要把b⼦树的细节进⼀步展开为12和左⼦树⾼度为h-1的e和f⼦树,因为我们要对b的⽗亲15为旋转点进⾏右单旋,右单旋需要动b树中的右⼦树。b⼦树中新增结点的位置不同,平衡因⼦更新的细节也不同,通过观察12的平衡因⼦不同,这⾥我们要分三个场景讨论

场景1:h >= 1时,新增结点插⼊在e⼦树,e⼦树⾼度从h-1变为h并不断更新12->15->10平衡因⼦,引发旋转,其中12的平衡因⼦为-1,旋转后10和12平衡因⼦为0,15平衡因⼦为1

     
场景2:h >= 1时,新增结点插⼊在f⼦树,f⼦树⾼度从h-1变为h并不断更新12->15->10平衡因⼦,引发旋转,其中12的平衡因⼦为1,旋转后15和12平衡因⼦为0,10平衡因⼦为-1

     
场景3:h == 0时,a/b/c都是空树,b⾃⼰就是⼀个新增结点,不断更新15->10平衡因⼦,引发旋转,其中12的平衡因⼦为0,旋转后10和12和15平衡因⼦均为0 

 4.5.1 右左双旋代码实现

//右左双旋
void RotateRL(Node* parent)
{
	Node* subR = parent->_right;
	Node* subRL = subR->_left;

	int bf = subRL->_bf;

	RotateR(parent->_right);
	RotateL(parent);

	if (bf == 0)
	{
		subR->_bf = 0;
		subRL->_bf = 0;
		parent->_bf = 0;
	}
	else if (bf == 1)
	{
		subR->_bf = 0;
		subRL->_bf = 0;
		parent->_bf = -1;
	}
	else if (bf == -1)
	{
		subR->_bf = 1;
		subRL->_bf = 0;
		parent->_bf = 0;
	}
	else
	{
		assert(false);
	}
}


5. AVL树的判断

int _Height(Node* root)
{
	if (root == nullptr)
	{
		return 0;
	}

	int leftheight = _Height(root->_left);
	int rightheight = _Height(root->_right);

	return leftheight > rightheight ? leftheight + 1 : rightheight + 1;
}

bool _IsAVLTree(Node* root)
{
	if (root == nullptr)
	{
		return true;
	}

	int leftheight = _Heighr(root->_left);
	int rightheight = _Height(root->_right);
	int diff = rightheight - leftheight;

	if (abs(diff) >= 2)
	{
		cout << root->_kv.first << "高度差异常" << endl;
		return false;
	}
	if (diff != root->_bf)
	{
		cout << root->_kv.first << "平衡因子异常" << endl;
	}

	return _IsAVLTree(root->_left) && _IsAVLTree(root->_right);
}

 


6. AVL树的查找 

Node* Find(const K& key)
{
	Node* cur = _root;
	while (cur)
	{
		if (cur->_kv.first < key)
		{
			cur = cur->_right;
		}
		else if (cur->_kv.first > key)
		{
			cur = cur->_left;
		}
		else
		{
			return cur;
		}
	}
	return nullptr;
}


完结撒花~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2228397.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[GXYCTF 2019]Ping Ping Ping 题解(多种解题方式)

知识点: 命令执行 linux空格绕过 反引号绕过 变量绕过 base64编码绕过 打开页面提示 "听说php可以执行系统函数&#xff1f;我来康康" 然后输入框内提示输入 bjut.edu.cn 输入之后回显信息,是ping 这个网址的信息 输入127.0.0.1 因为提示是命令…

Python小游戏16——开心消消乐

运行结果显示 代码如下 import pygame import random # 初始化pygame pygame. init() # 定义一些常量 WIDTH 600 HEIGHT 600 NUM_GRID8 GRID_SIZE WIDTH // NUM_GRID FPS 30 # 定义颜色 WHITE (255&#xff0c; 255&#xff0c;255) BLACK(0&#xff0c;0&#xff0c;0) COL…

基于树莓派的安保巡逻机器人--(一、快速人脸录入与精准人脸识别)

目录 零、前言 一、人脸检测 二、人脸识别 1、采集人脸 2、训练人脸识别模型 3、人脸识别应用 零、前言 随着智能安防需求的增长&#xff0c;基于人工智能和物联网的安保系统逐渐成为趋势。树莓派因其低成本、高扩展性等特点&#xff0c;成为很多AI项目的理想平台。本文将为大…

HTB:BoardLight[WriteUP]

目录 连接至HTB服务器并启动靶机 1.How many TCP ports are listening on BoardLight? 2.What is the domain name used by the box? 3.What is the name of the application running on a virtual host of board.htb? 4.What version of Dolibarr is running on Board…

react18中redux-saga实战系统登录功能及阻塞与非阻塞的性能优化

redux-saga中的effect常用的几个是有区分出阻塞与非阻塞的&#xff0c;这里主要看下call和fork两者的区别。 实现效果 非阻塞的task执行&#xff0c;不用等到登录成功后请求的list接口完成&#xff0c;点击退出按钮可以立即退出 阻塞task的执行&#xff0c;必须等到登录成功…

【JavaEE】【多线程】进阶知识

目录 一、常见的锁策略1.1 悲观锁 vs 乐观锁1.2 重量级锁 vs 轻量级锁1.3 挂起等待锁 vs 自旋锁1.4 普通互斥锁 vs 读写锁1.5 可重入锁 vs 不可重入锁1.6 不公平锁 vs 公平锁 二、synchronized特性2.1 synchronized的锁策略2.2 synchronized加锁过程2.3 其它优化措施 三、CAS3.…

炫酷的登录框!(附源码)

大家想看什么前端效果请留言 预览效果 源码 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>登录页…

RK3568平台开发系列讲解(内存篇)ioremap进行物理内存的映射

🚀返回专栏总目录 文章目录 一、使用案例:二、ioremap 函数的使用三、volatile 的使用一、使用案例: ioremapdevm_ioremap (你不用担心资源的释放)二、ioremap 函数的使用

中小企业设备资源优化:Spring Boot系统实现

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

基于SSM(spring+springmvc+mybatis)+MySQL开发的新闻推荐系统

基于内容的新闻推荐系统 一、环境搭建 开发框架&#xff1a;SSM(springspringmvcmybatis)开发语言&#xff1a;Java、HTML5、JavaScript开发工具&#xff1a;MyEclipse软件依赖&#xff1a;tomcat8、MySQL 1.1 新建工程 打开 myeclispe&#xff0c;新建一个 maven 工程&…

STM32 HAL ADC FIR 窗函数实现低通滤波

FIR 窗函数实现低通滤波 文章目录 FIR 窗函数实现低通滤波1.窗的分类与选择2.matlab设计3.代码编写4.结果欣赏与群延迟5.其他可能报错5.1.adc采集的数据没问题&#xff0c;vofa打印成-nan5.2.vofa打印的滤波数据为初始化的0 6.代码备忘 1.窗的分类与选择 2.matlab设计 主页命令…

例程学习(学习笔记)

project括号里面表示工程的名称&#xff0c;决定了最后生成的bin文件的名称&#xff0c;比如我们现在编译后的bin文件名称就是hello_world.bin文件&#xff0c;如果改成了project(xxx)&#xff0c;编译后的名称就是xxx.bin 这个文件用来设置路径&#xff0c;咱们得例程案例里面…

uniapp:上拉加载更多、下拉刷新、页面滚动到指定位置

提醒 本文实例是使用uniapp进行开发演示的。 一、需求场景 在开发商品&#xff08;SKU&#xff09;列表页面时&#xff0c;通常有三个需求&#xff1a; 页面下拉刷新&#xff0c;第一页展示最新数据&#xff1b;上拉加载更多数据&#xff1b;列表页面可以滚动到指定位置&#x…

5G在汽车零部件行业的应用

5G技术在汽车零部件行业的应用正在不断深入&#xff0c;为行业的智能化、自动化和高效化转型提供了强大的技术支持。 1、5G技术特点与优势 5G技术具有高速度、低延迟、大连接和切片技术等特点与优势。这些特性为汽车零部件行业提供了稳定、可靠、高效的通信连接&#xff0c;使…

jmeter的基本使用

Jmeter基本使用 一、变量 1.用户定义变量 2.用户参数 二、函数 1.计数器${__counter(,)} 2.时间函数 3.加密函数${__digest(,,,,)} 4. 整数相加${__intSum(,,)} 5.属性函数&#xff0c;${__P(,)}、${__property(,,)}、${__setProperty(,,)} 6.V函数 三、获取响应数据…

算法的学习笔记—和为 S 的连续正数序列(牛客JZ74)

&#x1f600;前言 在牛客网的《剑指 Offer》系列题中&#xff0c;有一道关于输出和为给定值 S 的连续正数序列的问题。这是一道典型的双指针问题&#xff0c;考察我们对连续数列求和的理解和双指针的应用。本文将详细解析这道题的思路&#xff0c;并展示如何实现代码。 &#…

D53【python 接口自动化学习】- python基础之模块与标准库

day53 自定义模块 学习日期&#xff1a;20241030 学习目标&#xff1a;模块与标准库 -- 67 自定义模块&#xff1a;如何编写一个完整功能&#xff1f; 学习笔记&#xff1a; 创建自定义模块 自定义模块注意事项 自定义模块 def func1():return this is a functionclass Cl…

上市公司企业数字金融认知数据集(2001-2023年)

一、测算方式&#xff1a;参考C刊《经济学家》王诗卉&#xff08;2021&#xff09;老师的做法&#xff0c;数字金融认知使用每万字年报描述中包含的对数字金融相关关键词的提及次数&#xff0c;关键词为&#xff1a;互联网、数字化、智能、大数据、电子银行、金融科技、科技金融…

4.2-7 运行MR应用:词频统计

文章目录 1. 准备数据文件2. 文件上传到HDFS指定目录2.1 创建HDFS目录2.2 上传文件到HDFS2.3 查看上传的文件 3. 运行词频统计程序的jar包3.1 查看Hadoop自带示例jar包3.2 运行示例jar包里的词频统计 4. 查看词频统计结果5. 在HDFS集群UI界面查看结果文件6. 在YARN集群UI界面查…

How to Train Neural Networks for Flare Removal

Abstract 当相机指向强光源时&#xff0c;生成的照片可能包含镜头眩光伪影。 耀斑以多种形式出现&#xff08;光晕、条纹、渗色、雾霾等&#xff09;&#xff0c;这种外观的多样性使得去除耀斑变得具有挑战性。 现有的分析解决方案对伪影的几何形状或亮度做出了强有力的假设&a…