日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java 区间树_线段树(区间树)之区间染色和4n推导过程

發布時間:2024/9/3 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 区间树_线段树(区间树)之区间染色和4n推导过程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

線段樹(區間樹)是什么呢?有了二叉樹、二分搜索樹,線段樹又是干什么的呢?最經典的線段樹問題:區間染色;正如它的名字而言,主要解決區間的問題

一、線段樹說明

1、什么是線段樹?

線段樹首先是二叉樹,并且是平衡二叉樹(它是一 棵空樹或它的左右兩個子樹的高度差的絕對值不超過1,并且左右兩個子樹都是一棵平衡二叉樹),并且具有二分性質。

如下圖,就是一顆線段樹:

假如,用數組表示線段樹,如果區間有n個元素,數組表示需要有多少節點?

2、4n節點推導過程

要進行一下

,如果對推導過程不感興趣的,可以直接記住結論,需要4n個節點,推導過程如下圖:  PS:依舊是全博客園最丑圖,當感覺有進步啊!是不是推薦一下,鼓勵一下啊

說明:感覺用盡了洪荒之力,才推導出來了。感覺高考之后再也不會用到等比公式了,但又用到了,還是緣分未盡啊,哈哈哈!最后,都放棄了,一直推導不出來,忘卻了最后一層的null,假設是滿二叉樹,按最大值進行估算,所以4n是完全夠大的!

二、為什么要使用線段樹

線段樹主要解決一些區間問題的,如下:

1、區間染色

有一面墻,長度為n,每次選擇一段墻進行染色,m次操作之后,我們可以看見多少種顏色?

2、區間查詢

查詢區間[i,j]的最大值、最小值,或者區間數字和;實質:基于區間的統計查詢。

例如:2018年注冊用戶中消費最高的用戶?消費最低的用戶?學習最長時間的用戶?

三、代碼實現

1、創建線段樹

二叉樹具有天然遞歸性質,所以用遞歸相對簡單,用迭代也是可以的,我才用遞歸實現,代碼如下:

template

classSegmentTree {private:

T*tree;

T*data;intsize;

std::functionfunction;int leftChild(intindex) {  //左孩子下標;例如用數組存儲,根節點是下標0,則左孩子為1,右孩子為2return index * 2 + 1;

}int rightChild(intindex) {  //右孩子下標return index * 2 + 2;

}void buildSegmentTree(int treeIndex, int l, intr) {if (l ==r) {

tree[treeIndex]=data[l];return;

}int leftTreeIndex =leftChild(treeIndex);int rightTreeIndex =rightChild(treeIndex);int mid = l + (r - l) / 2;  //中間值求法,防止整型溢出

buildSegmentTree(leftTreeIndex, l, mid);  //構建左子樹

buildSegmentTree(rightTreeIndex, mid+ 1, r);  //構建右子樹

tree[treeIndex]=function(tree[leftTreeIndex], tree[rightTreeIndex]);

}public:

SegmentTree(T arr[],int n, std::functionfunction) {  //構造函數,構建一棵樹this->function =function;

data= newT[n];for (int i = 0; i < n; ++i) {

data[i]=arr[i];

}

tree= new T[n * 4];  //分配4n節點

size=n;

buildSegmentTree(0, 0, size - 1);

}

};

2、線段樹查詢

線段樹具有二分查找性質,所以二分查找那種思路就可以了,代碼如下:

T query(int treeIndex, int l, int r, int queryL, intqueryR) {if (l == queryL && r ==queryR) {returntree[treeIndex];

}int mid = l + (r - l) / 2;int leftTreeIndex =leftChild(treeIndex);int rightTreeIndex =rightChild(treeIndex);if (queryL >= mid + 1) {return query(rightTreeIndex, mid + 1, r, queryL, queryR);

}else if (queryR <=mid) {returnquery(leftTreeIndex, l, mid, queryL, queryR);

}

T leftResult=query(leftTreeIndex, l, mid, queryL, mid);

T rightResult= query(rightTreeIndex, mid + 1, r, mid + 1, queryR);returnfunction(leftResult, rightResult);

}

T query(int queryL, intqueryR) {

assert(queryL>= 0 && queryL < size && queryR >= 0 && queryR < size && queryL <=queryR);return query(0, 0, size - 1, queryL, queryR);

}

3、整體代碼

SegmentTree.h如下:

#ifndef SEGMENT_TREE_SEGMENTTREE_H#define SEGMENT_TREE_SEGMENTTREE_H#include#includetemplate

classSegmentTree {private:

T*tree;

T*data;intsize;

std::functionfunction;int leftChild(intindex) {return index * 2 + 1;

}int rightChild(intindex) {return index * 2 + 2;

}void buildSegmentTree(int treeIndex, int l, intr) {if (l ==r) {

tree[treeIndex]=data[l];return;

}int leftTreeIndex =leftChild(treeIndex);int rightTreeIndex =rightChild(treeIndex);int mid = l + (r - l) / 2;

buildSegmentTree(leftTreeIndex, l, mid);

buildSegmentTree(rightTreeIndex, mid+ 1, r);

tree[treeIndex]=function(tree[leftTreeIndex], tree[rightTreeIndex]);

}

T query(int treeIndex, int l, int r, int queryL, intqueryR) {if (l == queryL && r ==queryR) {returntree[treeIndex];

}int mid = l + (r - l) / 2;int leftTreeIndex =leftChild(treeIndex);int rightTreeIndex =rightChild(treeIndex);if (queryL >= mid + 1) {return query(rightTreeIndex, mid + 1, r, queryL, queryR);

}else if (queryR <=mid) {returnquery(leftTreeIndex, l, mid, queryL, queryR);

}

T leftResult=query(leftTreeIndex, l, mid, queryL, mid);

T rightResult= query(rightTreeIndex, mid + 1, r, mid + 1, queryR);returnfunction(leftResult, rightResult);

}public:

SegmentTree(T arr[],int n, std::functionfunction) {this->function =function;

data= newT[n];for (int i = 0; i < n; ++i) {

data[i]=arr[i];

}

tree= new T[n * 4];

size=n;

buildSegmentTree(0, 0, size - 1);

}intgetSize() {returnsize;

}

Tget(intindex) {

assert(index>= 0 && index

}

T query(int queryL, intqueryR) {

assert(queryL>= 0 && queryL < size && queryR >= 0 && queryR < size && queryL <=queryR);return query(0, 0, size - 1, queryL, queryR);

}voidprint() {

std::cout<< "[";for (int i = 0; i < size * 4; ++i) {if (tree[i] !=NULL) {

std::cout<

}else{

std::cout<< "0";

}if (i != size * 4 - 1) {

std::cout<< ",";

}

}

std::cout<< "]" <<:endl>

}

};#endif //SEGMENT_TREE_SEGMENTTREE_H

View Code

main.cpp如下:

#include #include"SegmentTree.h"

intmain() {int nums[] = {-2, 0, 3, -5, 2, -1};

SegmentTree *segmentTree = new SegmentTree(nums, sizeof(nums) / sizeof(int), [](int a, int b) -> int{return a +b;

});

std::cout<< segmentTree->query(2,5) <<:endl>

segmentTree->print();return 0;

}

4、演示

運行結果,如下:

5、時間復雜度分析

更新  O(logn)

查詢  O(logn)

總結

以上是生活随笔為你收集整理的java 区间树_线段树(区间树)之区间染色和4n推导过程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。