mirror of
https://github.com/tiennm99/zfoo.git
synced 2026-05-19 13:27:10 +00:00
feat[treemap]: fast read only tree map
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.zfoo.net.util;
|
||||
|
||||
import com.zfoo.protocol.collection.ArrayUtils;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* @author godotg
|
||||
*/
|
||||
public class ReadOnlyTreeMapIntLong {
|
||||
|
||||
private int[] keys;
|
||||
private long[] values;
|
||||
|
||||
public ReadOnlyTreeMapIntLong(TreeMap<Integer, Long> treeMap) {
|
||||
var size = treeMap.size();
|
||||
keys = new int[size];
|
||||
values = new long[size];
|
||||
|
||||
// TreeMap遍历是有序的,直接放入数组中就能直接得到从小到大的有序数组
|
||||
var index = 0;
|
||||
for (var entry : treeMap.entrySet()) {
|
||||
var key = entry.getKey();
|
||||
var value = entry.getValue();
|
||||
keys[index] = key;
|
||||
values[index] = value;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(int key) {
|
||||
return indexOf(key) >= 0;
|
||||
}
|
||||
|
||||
public long get(int key) {
|
||||
var index = indexOf(key);
|
||||
if (index < 0) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
return values[index];
|
||||
}
|
||||
|
||||
public long getByIndex(int index) {
|
||||
Objects.checkIndex(index, values.length);
|
||||
return values[index];
|
||||
}
|
||||
|
||||
public int indexOf(int key) {
|
||||
var low = 0;
|
||||
var high = keys.length - 1;
|
||||
while (low <= high) {
|
||||
int mid = (low + high) / 2;
|
||||
if (keys[mid] == key) {
|
||||
return mid;
|
||||
} else if (keys[mid] < key) {
|
||||
low = mid + 1;
|
||||
} else {
|
||||
high = mid - 1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int indexOfCeilingKey(int key) {
|
||||
if (ArrayUtils.isEmpty(keys)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
var size = keys.length;
|
||||
// 目标数小于或等于数组的第一个元素
|
||||
if (key <= keys[0]) {
|
||||
return 0;
|
||||
}
|
||||
// 目标数大于数组的第一个元素
|
||||
if (key > keys[size - 1]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 二分查找目标数
|
||||
var low = 0;
|
||||
var high = size - 1;
|
||||
var nearestIndex = -1;
|
||||
|
||||
while (low <= high) {
|
||||
var mid = low + (high - low) / 2;
|
||||
if (keys[mid] == key) {
|
||||
nearestIndex = mid;
|
||||
break;
|
||||
} else if (keys[mid] < key) {
|
||||
low = mid + 1;
|
||||
} else {
|
||||
high = mid - 1;
|
||||
nearestIndex = mid;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果找到了目标数,那么它的邻近最大值就是目标数本身
|
||||
if (nearestIndex == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return nearestIndex;
|
||||
}
|
||||
|
||||
public long getValueByCeilingKey(int key) {
|
||||
var index = indexOfCeilingKey(key);
|
||||
if (index < 0) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
return values[index];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.zfoo.net.util;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* @author godotg
|
||||
*/
|
||||
public class ReadOnlyTreeMapIntLongTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
var treeMap = new TreeMap<Integer, Long>();
|
||||
for (var i = 0; i < 100; i = i + 2) {
|
||||
treeMap.put(i, (long) i);
|
||||
}
|
||||
|
||||
var fastTreeMap = new ReadOnlyTreeMapIntLong(treeMap);
|
||||
Assert.assertEquals(fastTreeMap.get(0), 0);
|
||||
Assert.assertEquals(fastTreeMap.get(8), 8);
|
||||
Assert.assertEquals(fastTreeMap.get(98), 98);
|
||||
Assert.assertFalse(fastTreeMap.contains(-1));
|
||||
Assert.assertFalse(fastTreeMap.contains(1));
|
||||
Assert.assertFalse(fastTreeMap.contains(100));
|
||||
Assert.assertTrue(fastTreeMap.contains(44));
|
||||
Assert.assertEquals(fastTreeMap.getValueByCeilingKey(-1), 0);
|
||||
Assert.assertEquals(fastTreeMap.getValueByCeilingKey(-100), 0);
|
||||
Assert.assertEquals(fastTreeMap.getValueByCeilingKey(0), 0);
|
||||
Assert.assertEquals(fastTreeMap.getValueByCeilingKey(1), 2);
|
||||
Assert.assertEquals(fastTreeMap.getValueByCeilingKey(45), 46);
|
||||
Assert.assertEquals(fastTreeMap.getValueByCeilingKey(97), 98);
|
||||
Assert.assertEquals(fastTreeMap.getValueByCeilingKey(100), 0);
|
||||
Assert.assertEquals(fastTreeMap.indexOfCeilingKey(-1), 0);
|
||||
Assert.assertEquals(fastTreeMap.indexOfCeilingKey(0), 0);
|
||||
Assert.assertEquals(fastTreeMap.indexOfCeilingKey(1), 1);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user