jsdk-offical
Version:
JSDK is the most comprehensive TypeScript framework, like JDK.
316 lines (270 loc) • 9.55 kB
text/typescript
/**
* @project JSDK
* @license MIT
* @website https://github.com/fengboyue/jsdk
*
* @version 2.0.0
* @author Frank.Feng
*/
/// <reference path='../lang/Type.ts'/>
module JS {
export namespace ds {
let J = Jsons;
export type LinkedNode<T> = {
data: T,
next: LinkedNode<T>,
prev: LinkedNode<T>
}
/**
* 双向链表
* 适合大数据量的高频插入/删除操作
*/
export class LinkedList<T> implements Iterware<T>{
//size
private _s = 0;
//head
private _hd: LinkedNode<T> = null;
//tail
private _tl: LinkedNode<T> = null;
constructor() {
}
public each(fn: (item: T, index: number, iter: LinkedList<T>) => boolean, thisArg?: any) {
if (this._s == 0) return true;
let rst = true, i = 0, node = this._hd;
while (node) {
if (!fn.call(thisArg || this, node.data, i, this)) {rst = false;break;}
node = node.next;
++i;
}
return rst;
}
public size() {
return this._s
}
public isEmpty() {
return this._s == 0
}
public clear() {
this._hd = null;
this._tl = null;
this._s = 0;
}
public clone(): LinkedList<T> {
let list = new LinkedList<T>();
if (this._s > 0) {
let node = this._hd;
while (node) {
list.add(J.clone(node.data));
node = node.next;
}
}
return list;
}
public toArray(): Array<T> {
let arr = [];
this.each(d => {
arr[arr.length] = d;
return true
})
return arr;
}
public getFirst(): T {
return this._hd ? this._hd.data : null
}
public getLast(): T {
return this._tl ? this._tl.data : null
}
public get(i: number): T {
if (i > this._s || i < 0) return null;
if (i == 0) return this._hd ? this._hd.data : null;
if (i == this._s - 1) return this._tl ? this._tl.data : null;
let node = this._findAt(i);
return node ? node.data : null;
}
private _findAt(i: number): LinkedNode<T> {
return i < this._s / 2 ? this._fromFirst(i) : this._fromLast(i);
}
private _fromFirst(i: number): LinkedNode<T> {
if (i<=0) return this._hd;
let node = this._hd, count = 1;
while (count <= i) {
node = node.next;
count++;
}
return node;
}
private _fromLast(i: number): LinkedNode<T> {
if (i>=(this.size()-1)) return this._tl;
let node = this._tl, count = this._s - 1;
while (count > i) {
node = node.prev;
count--;
}
return node;
}
public indexOf(data: T, eq?:(data:T,item:T)=>boolean): number {
if (this.isEmpty()) return -1;
let rst = -1;
this.each((item, i) => {
let is = eq?eq(data,item):(data === item);
if (is) rst = i;
return !is;
})
return rst;
}
public lastIndexOf(data: T, eq?:(data:T,item:T)=>boolean): number {
if (this.isEmpty()) return -1;
let j = -1, node = this._tl, i = this._s - 1;
while (node) {
if (eq?eq(data,node.data):(data === node.data)) {
j = i;
break;
}
node = node.prev;
--i;
}
return j;
}
public contains(data: T, eq?:(data:T,item:T)=>boolean) {
return this.indexOf(data, eq) > -1;
}
private _addLast(d: T) {
let node: LinkedNode<T> = { data: J.clone(d), prev: null, next: null };
if (this._tl) {
node.prev = this._tl;
this._tl.next = node;
}
this._tl = node;
if (!this._hd) this._hd = this._tl;
this._s += 1;
}
private _addFirst(d: T) {
let node: LinkedNode<T> = { data: J.clone(d), prev: null, next: null };
if (this._hd) {
node.next = this._hd;
this._hd.prev = node;
}
this._hd = node;
if (!this._tl) this._tl = this._hd;
this._s += 1;
}
public add(a: T | T[]) {
if (Types.isArray(a)) {
(<Array<T>>a).forEach(el => {
this._addLast(el);
});
} else {
this._addLast(<T>a);
}
}
public addAll(list: LinkedList<T>) {
if (!list || list.isEmpty()) return;
list.each(d => {
this._addLast(d);
return true
})
}
private _addAt(i: number, a: T) {
let nextNode = this._findAt(i);
if (!nextNode) return;
let prevNode = nextNode.prev, newNode = { data: J.clone(a), next: nextNode, prev: prevNode };
prevNode.next = newNode;
nextNode.prev = newNode;
this._s += 1;
}
public addAt(i: number, a: T | T[]) {
if (i <= 0) {
this.addFirst(a);
return
} else if (i >= this.size()) {
this.addLast(a);
return
}
if (!Types.isArray(a)) {
this._addAt(i, <T>a);
} else {
(<T[]>a).forEach((t, j) => {
this._addAt(i + j, t);
})
}
}
public addLast(a: T | T[]) {
this.add(a);
}
public addFirst(a: T | T[]) {
if (Types.isArray(a)) {
for (let i = (<Array<T>>a).length - 1; i >= 0; i--) {
this._addFirst(a[i]);
}
} else {
this._addFirst(<T>a);
}
}
public removeFirst(): T {
if (this._s == 0) return null;
let data = this._hd.data;
if (this._s > 1) {
this._hd = this._hd.next;
this._hd.prev = null;
} else {
this._hd = null;
this._tl = null;
}
this._s--;
return data
}
public removeLast(): T {
if (this._s == 0) return null;
let data = this._tl.data;
if (this._s > 1) {
this._tl = this._tl.prev;
this._tl.next = null;
} else {
this._hd = null;
this._tl = null;
}
this._s--;
return data
}
public removeAt(i: number) {
if (this.isEmpty() || i > this._s || i < 0) return null;
if (i == 0) {
return this.removeFirst()
} else if (i == this.size() - 1) {
return this.removeLast()
}
let node = this._findAt(i);
if (!node) return null;
let next = node.next, prev = node.prev;
if (next) next.prev = prev;
if (prev) prev.next = next;
this._s--;
return node.data
}
/**
* Retrieves, but does not remove, the first element of this list.
*/
public peek(): T {
return this._hd ? this._hd.data : null;
}
/**
* Retrieves, but does not remove, the first element of this list, or returns null if this list is empty.
*/
public peekFirst(): T {
return this.peek();
}
/**
* Retrieves, but does not remove, the last element of this list, or returns null if this list is empty.
*/
public peekLast(): T {
return this._tl ? this._tl.data : null;
}
public toString() {
return '[' + this.toArray().toString() + ']'
}
}
}
}
//预定义短类名
import LinkedList = JS.ds.LinkedList;
import LinkedNode = JS.ds.LinkedNode;