用Java实现线段树
线段树是为区间更新和区间查询而生的数据结构,旨在快速解决区间问题。
一般来说,线段树是不会加节点的,也不支持动态添加节点。线段树也是二叉树的一种,不过它的节点是以一个区间来定义节点的。具有一个单一区间的就是叶子节点。所以线段树,本质上就是一棵区间树。
我们在查找的时候,只需要找出结果区间由哪些子区间构成即可。实现代码
首先定义出基础的结构publicclassSegmentTree{privateIntegervalue;privateIntegermaxValue;privateIntegerl;privateIntegerr;privateSegmentTreeleftChild;privateSegmentTreerightChild;}复制代码
l和r用来唯一刻画这个区间。然后其他的内容,与标准的二叉树没得任何区别。
建树过程
与二叉树建树没得区别,我们这里采用前序建树的方式进行。代码如下:publicstaticSegmentTreebuildTree(intleft,intright,int〔〕value){if(leftright){returnnull;}SegmentTreenodenewSegmentTree();node。setValue(value〔left〕);node。setL(left);node。setR(right);if(leftright){TODO:2022117退出条件node。setMaxValue(node。getValue());returnnode;}intmid(leftright)1;node。setLeftChild(buildTree(left,mid,value));node。setRightChild(buildTree(mid1,right,value));if(Objects。isNull(node。getLeftChild())){if(Objects。isNull(node。getRightChild())){node。setMaxValue(node。getValue());}else{node。setMaxValue(node。getRightChild()。getMaxValue());}}else{if(Objects。isNull(node。getRightChild())){node。setMaxValue(node。getLeftChild()。getMaxValue());}else{node。setMaxValue(Math。max(node。getLeftChild()。getMaxValue(),node。getRightChild()。getMaxValue()));}}returnnode;}复制代码
可以看见,这里的叶子节点判断条件就是leftright。其他方面和二叉树没有任何区别。
查询区间最大值publicstaticIntegergetMaxValue(SegmentTreesegmentTree,intleft,intright){if(Objects。isNull(segmentTree))returnnull;if(segmentTree。getL()leftsegmentTree。getR()right){System。out。println(获取了区间〔left,right〕的最大值segmentTree。getMaxValue());returnsegmentTree。getMaxValue();}intsegMid(segmentTree。getL()segmentTree。getR())1;if(segMidleft){returngetMaxValue(segmentTree。getRightChild(),left,right);}if(segMidright){returngetMaxValue(segmentTree。getLeftChild(),left,right);}TODO:2022117左半边答案IntegerleftMaxgetMaxValue(segmentTree。getLeftChild(),left,segMid);IntegerrightMaxgetMaxValue(segmentTree。getRightChild(),segMid1,right);if(Objects。isNull(leftMax)){if(Objects。isNull(rightMax)){return100000;}else{returnrightMax;}}else{if(Objects。isNull(rightMax)){returnleftMax;}else{returnMath。max(leftMax,rightMax);}}}复制代码
从上面的代码分析,设当前节点的区间为【L,R】,那么对于区间〔l,r〕的最大值来说,就需要进行分类讨论,如果LR的区间中点Mid在lr区间的左边,那么max(lr)max(右子树,l,r);如果LR的区间中点在lr区间的右边,则max(lr)max(左子树,l,r);如果Mid在lr区间里面,则max(lr)max(左子树,l,mid)和max(右子树,mid1,r)中的较大值。
下面我们来看看测试用例和运行结果:publicstaticvoidmain(String〔〕args){int〔〕anewint〔〕{2,5,4,7,6,0,1,1,2,3,6,7,0,2,9,8,5,4,7,2};SegmentTreesegmentTreebuildTree(0,a。length1,a);System。out。println(getMaxValue(segmentTree,0,16));}复制代码
结果如下
获取了区间〔0,9〕的最大值7获取了区间〔10,14〕的最大值9获取了区间〔15,16〕的最大值89获取区间和
现在需要对原来的建树过程进行改造,首先,在基础结构中添加sum字段publicclassSegmentTree{privateIntegervalue;privateIntegermaxValue;privateIntegersum;privateIntegerl;privateIntegerr;privateSegmentTreeleftChild;privateSegmentTreerightChild;}复制代码
然后在建树方法中,添加对和的维护publicstaticSegmentTreebuildTree(intleft,intright,int〔〕value){if(leftright){returnnull;}SegmentTreenodenewSegmentTree();node。setValue(value〔left〕);node。setL(left);node。setR(right);if(leftright){TODO:2022117退出条件node。setMaxValue(node。getValue());node。setSum(node。getValue());returnnode;}intmid(leftright)1;node。setLeftChild(buildTree(left,mid,value));node。setRightChild(buildTree(mid1,right,value));if(Objects。isNull(node。getLeftChild())){if(Objects。isNull(node。getRightChild())){node。setMaxValue(node。getValue());node。setSum(node。getValue());}else{node。setMaxValue(node。getRightChild()。getMaxValue());node。setSum(node。getRightChild()。getSum());}}else{if(Objects。isNull(node。getRightChild())){node。setMaxValue(node。getLeftChild()。getMaxValue());node。setSum(node。getLeftChild()。getSum());}else{node。setMaxValue(Math。max(node。getLeftChild()。getMaxValue(),node。getRightChild()。getMaxValue()));node。setSum(node。getLeftChild()。getSum()node。getRightChild()。getSum());}}returnnode;}复制代码
然后获取总和publicstaticIntegergetSum(SegmentTreesegmentTree,intleft,intright){if(Objects。isNull(segmentTree))returnnull;if(segmentTree。getL()leftsegmentTree。getR()right){System。out。println(获取了区间〔left,right〕的和segmentTree。getSum());returnsegmentTree。getSum();}intsegMid(segmentTree。getL()segmentTree。getR())1;if(segMidleft){returngetSum(segmentTree。getRightChild(),left,right);}if(segMidright){returngetSum(segmentTree。getLeftChild(),left,right);}TODO:2022117左半边答案IntegerleftSumgetSum(segmentTree。getLeftChild(),left,segMid);IntegerrightSumgetSum(segmentTree。getRightChild(),segMid1,right);if(Objects。isNull(leftSum)){if(Objects。isNull(rightSum)){returnsegmentTree。getSum();}else{returnrightSum;}}else{if(Objects。isNull(rightSum)){returnleftSum;}else{returnleftSumrightSum;}}}复制代码
测试程序和结果如下:publicstaticvoidmain(String〔〕args){int〔〕anewint〔〕{2,5,4,7,6,0,1,1,2,3,6,7,0,2,9,8,5,4,7,2};SegmentTreesegmentTreebuildTree(0,a。length1,a);System。out。println(getSum(segmentTree,0,3));}复制代码
获取了区间〔0,2〕的和11获取了区间〔3,3〕的和718单点更新这里的leftrightparamsegmentTreeparamleftparamrightparamvaluepublicstaticvoidupdate(SegmentTreesegmentTree,intleft,intright,intvalue){if(segmentTree。getL()leftsegmentTree。getR()right){segmentTree。setValue(value);segmentTree。setMaxValue(value);segmentTree。setSum(value);return;}intmid(segmentTree。getL()segmentTree。getR())1;if(midleft){update(segmentTree。getLeftChild(),left,right,value);}if(midleft){update(segmentTree。getRightChild(),left,right,value);}segmentTree。setMaxValue(Math。max(segmentTree。getLeftChild()。getMaxValue(),segmentTree。getRightChild()。getMaxValue()));segmentTree。setSum(segmentTree。getLeftChild()。getSum()segmentTree。getRightChild()。getSum());}复制代码
更新的时候也是利用递归的方法,不断从左右节点中寻找到需要被更新的区间,同时更新上级节点的最新值。总结
可以按需进行延伸,记住一点,线段树是以区间为维度的二叉树,或者说,是以二维维度进行刻画的二叉树,普通二叉树只有一维。这样一来,我们在计算多维度的值的时候,其实也可以利用这样的方式构建线段树(二维树,三维树,n维树)。不管几维树,找到结束状态和下级子状态就是关键中的关键。典型的方法就是分类讨论,前期不用怕分得过细,细了可以进行合并。最后
如果你觉得此文对你有一丁点帮助,点个赞。或者可以加入我的开发交流群:1025263163相互学习,我们会有专业的技术答疑解惑
如果你觉得这篇文章对你有点用的话,麻烦请给我们的开源项目点点star:http:github。crmeb。netudefu不胜感激!
PHP学习手册:https:doc。crmeb。com
技术交流论坛:https:q。crmeb。com
如何看待刚认识就要微信的现象?这最多是对微信走火入魔而已,至于能否遇上知音,从此网上诉说衷情,还是认识了骗子,不幸落入圈套,咎由自取,休怪他人。若是微信交友别有用心,也可能利用微信招遥撞骗,拉人网购三……
电影21克拉全国15站商场寻找灵魂伴侣活动重庆开启场面火爆由何念执导,郭京飞、迪丽热巴主演,大鹏、包贝尔、刘芮麟特别演出的电影《21克拉》将于4月20日全国公映。4月14日、15日,《21克拉》全国15站商场寻找灵魂伴侣活动在重庆举行……
包文婧亮相北京国际电影节蕾丝纱裙展现灵动优雅第八届北京国际电影节于昨日正式拉开帷幕,开幕式上包文婧作为电影《查理九世》的主演之一受邀与其他主创一起走上红毯。在当天曝出的红毯造型中,身穿一袭白色蕾丝纱裙,搭配简单丸子头的包……
新能源发展对电网影响会议纪要电网会是解决消纳问题的核心关键环节,从明年开始结构性、总量、方向上新型电网板块都会有新的投资。双碳方面不会减速,我国建设以新能源为主体的供应系统,但煤电的重要性强化了,今年下半……
为什么移动电信和联通,都愿意预存话费,从而白送一个手机?〔大笑〕这才叫套路!!!这是高消费的一个卡,它有限制,必须用它的这个套餐,消费到这个手机,一年以后,才可以换卡,手机白给你,每月话费98或108。或者158元,他是根据手……
颜值最高的小米手机,曲面屏55W丝绒AG,跌至1749元值得说起小米手机,相信大家对它的印象是性价比,其配置和价格往往都很良心,但外观设计向来是它的弱点,毕竟成本控制摆在那里,厂商们只能是顾头不顾尾,为了挽回颜值党的这类用户,雷军也是做……
猪猪侠不可思议的世界火爆热映领跑暑期动画电影星关系7月10日讯暑假正式拉开序幕,炎炎夏日最为开心的消暑模式就是走进电影院观看一部精彩的电影。《猪猪侠不可思议的世界》(以下简称《猪猪侠》大电影)这部由广东咏声动漫股份有限公……
python列表推导式和生成器表达式列表推导式和生成器表达式以及字典推导式通常被视为Python中函数式编程的一部分,列表推导允许您使用包含较少代码的for循环创建列表。列表推导式用〔〕包围ll〔ifori……
张榕容贵妃娘娘变废柴特工颠覆出演惊呆观众星关系7月10日讯演员张榕容出席由她主演的电影《素人特工》北京首映礼,在高贵典雅和干练帅酷之间完美转换。《妖猫传》中让人过目不忘的贵妃娘娘,摇身变成集水火性格于一身的废柴特工,……
银河补习班成都首映上演父女和解影院给暑期一份力量星关系7月9日讯7月8日,电影《银河补习班》在成都举行首映礼,导演邓超、俞白眉携主演王西、梁超、魏尊重磅亮相。提前观影的观众将影厅围得水泄不通,观众们毫不吝啬自己的掌声与尖叫,……
小红书回应审核漏放部分内容已被回查处理近日,媒体报道称,小红书涉嫌泄露未成年隐私及内容审核不严问题。对此,小红书对报道提及审核漏放情况致歉,并透露平台将于近期启动新一轮未成年治理专项。小红书回应称,报道中提及……
银河补习班重庆首映四代同堂来观影女孩现场作文念哭邓超星关系7月8日讯我觉得没有哪一部电影,让我觉得泪点和笑点这么密集、电影让我感受到了咱们国家这几十年的发展、这部影片在视觉设计上极为讲究,大量细节都真实还原了90年代特征性的东西……