前言
Javascript中没有TreeSet这种数据结构,我参考Java中的API用 数组+二分 实现了一个类似功能的数据结构,但事实上,Java中的TreeSet是基于红黑树构建的,因此,二者在性能上并不能相提并论。
正如有些开源库会在开头标注一句:
Note that this project is meant to be used for learning and researching purposes only, and it is not meant to be used for production.
ADT
TreeSet:
-methods
size(): Number 返回有序集合的大小
pop(): Element 弹出末尾元素
shift(): Element 弹出头部元素
add(e): 将e插入有序集合,并使得有序集合依旧有序
remove(e): 将e从有序集合中删除
has(e): Boolean 判断有序集合中是否存在e
get(i): Element 取到排第i+1位的元素
lower(e): Element 查找最大的严格小于e的元素
hihger(e): Element 查找最小的大于等于e的元素
_binarySearch(e):Number 返回值为正数表明有序数组中有该元素;负数表示可插入位置的相反数
-props
arr: Array 内部数据结构为对象数组(有序数组)
comparator: Function 自定义排序规则函数(默认规则为Number类型升序排序)
实现
class TreeSet {
constructor(comparator) {
this.arr = [];
if(comparator) this.comparator = comparator;
else this.comparator = (a,b) => a-b;
}
size() {
return this.arr.length;
}
pop() {
if(this.arr.length <= 0) throw new Error("can not pop() an element from an empty TreeSet!");
return this.arr.splice(this.arr.length-1, 1);
}
shift() {
if(this.arr.length <= 0) throw new Error("can not shift() an element from an empty TreeSet!");
return this.arr.splice(0, 1);
}
add(e) {
let idx = this._binarySearch(e);
if(idx < 0) {
idx = -idx-1;
this.arr.splice(idx, 0, e);
}
}
remove(e) {
let idx = this._binarySearch(e);
if(idx >= 0) this.arr.splice(idx, 1);
else return -1;
}
get(i) {
return this.arr[i];
}
has(e) {
return this._binarySearch(e) >= 0;
}
lower(e) {
let idx = this._binarySearch(e);
if(idx < 0) return this.arr[-idx-2];
else return this.arr[idx-1];
}
higher(e) {
let idx = this._binarySearch(e);
if(idx < 0) return this.arr[-idx-1];
else return this.arr[idx];
}
_binarySearch(e) {
let low = 0;
let high = this.arr.length-1;
while(low <= high) {
let mid = (low + high) >>> 1;
let val = this.arr[mid];
let cmp = this.comparator(val, e);
if(cmp < 0) low = mid+1;
else if(cmp > 0) high = mid-1;
else return mid;
}
return -(low+1);
}
}
测试用例
测试用例还要补充:
lower(9): 预期8
higher(9): 预期11
lower(11): 预期8
higher(11):预期11