亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java數(shù)據(jù)結(jié)構(gòu)之線段樹的原理與實(shí)現(xiàn)

 更新時(shí)間:2022年06月15日 09:19:50   作者:Carol  
線段樹是一種二叉搜索樹,是用來維護(hù)區(qū)間信息的數(shù)據(jù)結(jié)構(gòu)。本文將利用示例詳細(xì)講講Java數(shù)據(jù)結(jié)構(gòu)中線段樹的原理與實(shí)現(xiàn),需要的可以參考一下

簡介

線段樹是一種二叉搜索樹,是用來維護(hù)區(qū)間信息的數(shù)據(jù)結(jié)構(gòu)??梢栽贠(logN)的時(shí)間復(fù)雜度內(nèi)實(shí)現(xiàn)單點(diǎn)修改、區(qū)間修改、區(qū)間查詢(區(qū)間求和,求區(qū)間最大值,求區(qū)間最小值)等操作。接下來我以實(shí)現(xiàn)區(qū)間求和為例子來講解線段樹(最大值和最小值與求和實(shí)現(xiàn)方式幾乎無異),假設(shè)存在一個(gè)數(shù)組[1,4,6,3,9]。

實(shí)現(xiàn)思路

從線段樹的定義,我們首先需要定義一個(gè)樹節(jié)點(diǎn),節(jié)點(diǎn)包含區(qū)間和(23),區(qū)間([1-5]),左節(jié)點(diǎn),右節(jié)點(diǎn)等。(如果要實(shí)現(xiàn)求區(qū)間最大值,最小值,則還需包含這些)。然后需要提供構(gòu)建線段樹,線段樹支持修改節(jié)點(diǎn)操作方法。

節(jié)點(diǎn)定義

@Data
public?static?class?Node?{
? ?//區(qū)間起始下標(biāo)
? ?private?int?start;
? ?//區(qū)間結(jié)尾下標(biāo)
? ?private?int?end;
? ?//當(dāng)前區(qū)間和值
? ?private?int?value;
? ?private?Node?left;
? ?private?Node?right;
? ?Node(int?start,?int?end,?int?value) {
? ? ? ?this.start?=?start;
? ? ? ?this.end?=?end;
? ? ? ?this.value?=?value;
? }
}

構(gòu)建線段樹

因?yàn)闃?gòu)建線段樹時(shí)候需要計(jì)算當(dāng)前區(qū)間和,所以我們可以先初始化一個(gè)前綴和數(shù)組,在構(gòu)建線段樹時(shí)候利用下標(biāo)快速計(jì)算出區(qū)間和,同時(shí)為了保證每個(gè)節(jié)點(diǎn)有一致的操作,初始化一個(gè)頭節(jié)點(diǎn),指向root(這是鏈表樹等常用的簡化操作的方法)

//head 指向線段樹root節(jié)點(diǎn)的指針,使得root節(jié)點(diǎn)與其余節(jié)點(diǎn)操作保持一致
? ?Node?head;
? ?int?size;
? ?List<Integer>?nums;

? ?//前綴和數(shù)組,便于構(gòu)建線段樹時(shí)候計(jì)算區(qū)間值,用于初次構(gòu)建輔助
? ?List<Integer>?prefixSum?;
? ?public?void?init(List<Integer>?nums) {
? ? ? ?//初始化一個(gè)頭節(jié)點(diǎn),便于操作
? ? ? ?this.head?=?new?Node(-1,?-1,?-1);
? ? ? ?this.nums?=?nums;
? ??//初始化前綴和數(shù)組
? ? ? ?prefixSum?=?new?ArrayList<>(nums.size());
? ? ? ?prefixSum.add(0);
? ? ? ?for?(int?i?=?0;?i?<?nums.size() ;?i++) {
? ? ? ? ? ?prefixSum.add(prefixSum.get(prefixSum.size()?-?1)?+?nums.get(i));
? ? ? }
? ??//構(gòu)建線段樹
? ? ? ?this.build(1,?nums.size());
? ? ? ?size?=?nums.size();
? }

? ?//構(gòu)建線段樹
? ?public?void?build(int?start,?int?end) {
? ? ??Node?root?=?new?Node(start,?end,?prefixSum.get(end)?-?prefixSum.get(start?-?1));
? ? ?//將頭節(jié)點(diǎn)右子樹指向root
? ? ??head.right?=?root;
? ? ?//從root開始構(gòu)建線段樹
? ? ??this.madeChild(root,?start,?end);
? }
private?void?madeChild(Node?node,?int?start,?int?end) {
? ? ? ?if?(start?>=?end) {
? ? ? ? ? ?return;
? ? ? }
? ? ? ?//分個(gè)左右子樹,左子樹取start~mid,右子樹取mid+1~end
? ? ? ?int?mid?=?start?+?((end?-?start)?>>?1);
? ? ? ?if?(start?<=?mid) {
? ? ? ? ? ?Node?left?=?new?Node(start,?mid,?prefixSum.get(mid)?-?prefixSum.get(start?-?1));
? ? ? ? ? ?node.left?=?left;
? ? ? ? ? ?madeChild(left,?start,?mid);
? ? ? }
? ? ? ?if?(mid?+?1?<=?end) {
? ? ? ? ? ?Node?right?=?new?Node(mid?+?1,?end,?prefixSum.get(end)?-?prefixSum.get(mid));
? ? ? ? ? ?node.right?=?right;
? ? ? ? ? ?madeChild(right,?mid?+?1,?end);
? ? ? }
? }

求解區(qū)間和

求解區(qū)間和過程就是遍歷線段樹,將求解區(qū)間與當(dāng)前節(jié)點(diǎn)區(qū)間進(jìn)行比較,如果全部存在于左子樹或者右子樹,則直接深度繼續(xù)在左子樹右子樹遍歷即可,但是如果求解區(qū)間在當(dāng)前節(jié)點(diǎn)的左右子樹均有部分,則需要將當(dāng)前區(qū)間分為兩個(gè)部分,然后分別深度遍歷左右子樹,最后將結(jié)果相加。

//求解區(qū)間和
? ?public?int?findSectionSum(int?start,?int?end) {
? ? ? ?//深度遍歷線段樹,找到對應(yīng)區(qū)間
? ? ? ?if?(start?<?1?||?end?>?size?||?start?>?end) {
? ? ? ? ? ?return?-1;
? ? ? }
? ? ? ?return?dfsFindSectionSum(head.right,?start,?end);
? } ? ?
/**
? ??* 深度遍歷線段樹結(jié)構(gòu),分為三種情況
? ??* 1.區(qū)間在當(dāng)前節(jié)點(diǎn)的左子樹中
? ??* 2.區(qū)間在當(dāng)前節(jié)點(diǎn)的右子樹中
? ??* 3.左子樹中一部分,右子樹中一部分
? ??* @param node
? ??* @param start
? ??* @param end
? ??* @return
? ??*/
? ?private?int?dfsFindSectionSum(Node?node,?int?start,?int?end) {
? ? ? ?if?(node.start?==?start?&&?node.end?==?end) {
? ? ? ? ? ?//找到區(qū)間
? ? ? ? ? ?return?node.value;
? ? ? }
? ? ? ?if?(this.isContain(node.left.start,?node.left.end,?start,?end)) {
? ? ? ? ? ?//在左子樹中
? ? ? ? ? ?return?this.dfsFindSectionSum(node.left,?start,?end);
? ? ? }
? ? ? ?if?(this.isContain(node.right.start,?node.right.end,?start,?end)) {
? ? ? ? ? ?//包含在右子樹中
? ? ? ? ? ?return?this.dfsFindSectionSum(node.right,?start,?end);
? ? ? }
? ? ? ?//左邊一部分,右邊一部分
? ? ? ?return?this.dfsFindSectionSum(node.left,?start,?node.left.end)?+?this.dfsFindSectionSum(node.right,?node.right.start,?end);
? }
? ?/**
? ??* 判斷區(qū)間[start2, end2]是否包含在[start1, end1]中
? ??* @param start1
? ??* @param end1
? ??* @param start2
? ??* @param end2
? ??* @return
? ??*/
? ?private?boolean?isContain(int?start1,?int?end1,?int?start2,?int?end2){
? ? ? ?return?start2?>=?start1?&&?end2?<=?end1;
? }

更新線段樹

當(dāng)更新指定位置元素的值的時(shí)候,我們需要將線段樹中區(qū)間包含該節(jié)點(diǎn)的區(qū)間和進(jìn)行更新。我們可以從根節(jié)點(diǎn)開始深度遍歷線段樹,如果當(dāng)前節(jié)點(diǎn)包含該位置,我們更新區(qū)間和,然后根據(jù)當(dāng)前節(jié)點(diǎn)左右子節(jié)點(diǎn)的區(qū)間,判斷走左子樹還是右子樹,直至更新到葉子節(jié)點(diǎn),則更新完成。

//更新線段樹,將index位置的值更新為value,需要更新沿路的值
? ?public?void?update(int?index,?int?value) {
? ? ? ?Node?root?=?head.right;
? ? ? ?while?(null?!=?root) {
? ? ? ? ? ?if?(index?>=?root.start?&&?index?<=?root.end) {
? ? ? ? ? ? ? ?root.value?+=?value?-?nums.get(index?-?1);
? ? ? ? ? }
? ? ? ? ? ?int?mid?=?root.start?+?((root.end?-?root.start)?>>?1);
? ? ? ? ? ?if?(index?<=?mid) {
? ? ? ? ? ? ? ?root?=?root.left;
? ? ? ? ? ? ? ?continue;
? ? ? ? ? }
? ? ? ? ? ?root?=?root.right;
? ? ? }
? ? ? ?nums.set(index?-?1,?value);
? }

以上就是Java數(shù)據(jù)結(jié)構(gòu)之線段樹的原理與實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于Java 線段樹的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 一文告訴你為什么要重寫hashCode()方法和equals()方法

    一文告訴你為什么要重寫hashCode()方法和equals()方法

    本篇文章帶大家了解一下為什么重寫hashCode()方法和equals()方法,文中有非常詳細(xì)的說明以及代碼示例,對正在學(xué)習(xí)java的小伙伴們很有幫助,需要的朋友可以參考下
    2021-05-05
  • SpringBoot集成Swagger2構(gòu)建在線API文檔的代碼詳解

    SpringBoot集成Swagger2構(gòu)建在線API文檔的代碼詳解

    這篇文章主要介紹了SpringBoot集成Swagger2構(gòu)建在線API文檔,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12
  • SpringMVC中RequestParam注解的簡單理解

    SpringMVC中RequestParam注解的簡單理解

    @RequestMapping RequestMapping是一個(gè)用來處理請求地址映射的注解,可用于類或方法上,下面這篇文章主要給大家介紹了關(guān)于SpringMVC中RequestParam注解的簡單理解,需要的朋友可以參考下
    2022-03-03
  • 詳解java注解相關(guān)知識

    詳解java注解相關(guān)知識

    今天給大家?guī)淼氖顷P(guān)于Java的相關(guān)知識,文章圍繞著java注解的使用展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • Java實(shí)現(xiàn)簡易撲克牌游戲的完整實(shí)例

    Java實(shí)現(xiàn)簡易撲克牌游戲的完整實(shí)例

    這篇文章主要介紹了Java實(shí)現(xiàn)簡易撲克牌游戲的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • Opencv創(chuàng)建車牌圖片識別系統(tǒng)方法詳解

    Opencv創(chuàng)建車牌圖片識別系統(tǒng)方法詳解

    本文主要介紹了一個(gè)基于spring?boot+maven+opencv實(shí)現(xiàn)的圖像識別及訓(xùn)練項(xiàng)目,可以實(shí)現(xiàn)車牌識別功能,感興趣的可以跟隨小編一起試一試
    2022-01-01
  • SpringBoot整合Elasticsearch實(shí)現(xiàn)索引和文檔的操作方法

    SpringBoot整合Elasticsearch實(shí)現(xiàn)索引和文檔的操作方法

    Elasticsearch 基于 Apache Lucene 構(gòu)建,采用 Java 編寫,并使用 Lucene 構(gòu)建索引、提供搜索功能,本文分步驟通過綜合案例給大家分享SpringBoot整合Elasticsearch的相關(guān)知識,感興趣的朋友跟隨小編一起看看吧
    2021-05-05
  • MyBatis動態(tài)Sql之if標(biāo)簽的用法詳解

    MyBatis動態(tài)Sql之if標(biāo)簽的用法詳解

    這篇文章主要介紹了MyBatis動態(tài)Sql之if標(biāo)簽的用法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下
    2019-07-07
  • MyBatis高級映射和查詢緩存

    MyBatis高級映射和查詢緩存

    這篇文章主要介紹了MyBatis高級映射和查詢緩存的相關(guān)資料,需要的朋友可以參考下
    2016-06-06
  • Springmvc調(diào)用存儲過程,并返回存儲過程返還的數(shù)據(jù)方式

    Springmvc調(diào)用存儲過程,并返回存儲過程返還的數(shù)據(jù)方式

    這篇文章主要介紹了Springmvc調(diào)用存儲過程,并返回存儲過程返還的數(shù)據(jù)方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11

最新評論