sangja
Version:
JavaScript data structures library
2,336 lines • 59.9 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define("sangja", [], factory);
else if(typeof exports === 'object')
exports["sangja"] = factory();
else
root["sangja"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // create a fake namespace object
/******/ // mode & 1: value is a module id, require it
/******/ // mode & 2: merge all properties of value into the ns
/******/ // mode & 4: return value when already ns object
/******/ // mode & 8|1: behave like require
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 3);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports) {
/**
* Check if given object is iterable
* @function
* @memberof sangja
* @param {*} obj - An object to check if iterable
* @return {boolean} True if obj is iterable else false
*/
function isIterable(obj) {
// checks for null and undefined
if (obj == null) {
return false;
}
return typeof obj[Symbol.iterator] === 'function';
}
/**
* Default key function.<br>
* Data structures that require compare will use this function as a default key function.<br>
* Returns the input argument as it is.
* @function
* @memberof sangja
*/
const defaultKey = x => x;
/**
* Default compare function.<br>
* Data structures that require compare will use this function as a default compare function.<br>
* Compare 2 given operands and return the result. This function can compare number, string.
* @function
* @memberof sangja
*/
const defaultCompare = (x, y) => {
if (x < y) {
return -1;
}
if (x > y) {
return 1;
}
return 0;
};
function mergeOptions(given = {}, original = {}) {
if (!given) {
return original;
}
const merged = {};
Object.keys(original).forEach((key) => {
merged[key] = given[key] || original[key];
});
return merged;
}
module.exports = {
isIterable,
defaultKey,
defaultCompare,
mergeOptions,
};
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
const Utils = __webpack_require__(0);
const LinkedList = __webpack_require__(2);
/**
* @class
* @memberof sangja
*/
class Queue {
/**
* Creates a new Queue.
* Iterable parameter is optional.
* @constructor
* @param {iterable} [iterable] - Iterator for initialize the queue.
* @throws {TypeError} When given parameter is not queue.
*/
constructor(iterable = []) {
if (!Utils.isIterable(iterable)) {
throw TypeError();
}
this._linkedList = new LinkedList(iterable);
}
/**
* Add value at the rear of the queue.
* @param {*} value - The value to enqueue to the queue.
*/
enqueue(value) {
this._linkedList.addLast(value);
}
/**
* Add values in the given iterator at the rear of the queue.
* @param {iterable} iterable - The iterable values to enqueue
*/
enqueueAll(iterable) {
[...iterable].forEach(v => this._linkedList.addLast(v));
}
/**
* Removes the front of the queue and returns the value at the front of the queue.
* @returns {*} The value at the front of the queue. If empty, return undefined.
*/
dequeue() {
if (this._linkedList.size() === 0) {
return undefined;
}
return this._linkedList.popFirst();
}
/**
* Returns the value at the front of the queue without changing the state of the queue.
* @returns {*} The value at the front of the queue. If empty, return undefined.
*/
peek() {
if (this._linkedList.size() === 0) {
return undefined;
}
return this._linkedList.getFirst();
}
/**
* Returns the number of elements in the queue.
* @returns {number} The number of elements in the queue.
*/
size() {
return this._linkedList.size();
}
/**
* Returns whether the queue is empty.
* @returns {boolean} True if the queue is empty.
*/
isEmpty() {
return this._linkedList.isEmpty();
}
/**
* Removes all values in the queue.
*/
clear() {
this._linkedList = new LinkedList();
}
/**
* For each values in the queue, execute the given procedure f.
* @param {function} f - Procedure to execute
*/
forEach(f) {
this._linkedList.forEach(f);
}
/**
* Returns a new Queue whose values are mapped with given function f.
* @param {function} f - Function to map values
* @return {Stack} Queue([mapped values])
*/
map(f) {
const queue = new Queue();
queue._linkedList = this._linkedList.map(f);
return queue;
}
/**
* Returns a new Queue whose values are mapped with given function f and flattened.
* @param {function} f - Function (this.value) => iterable
* @return {Stack} Queue([mapped and flattened values])
*/
flatMap(f) {
const queue = new Queue();
queue._linkedList = this._linkedList.flatMap(f);
return queue;
}
/**
* Returns a new Queue whose values are filtered with given predicate f.
* @param {function} f - Predicate (this.value) => boolean
* @return {Stack} Queue([filtered values])
*/
filter(f) {
const queue = new Queue();
queue._linkedList = this._linkedList.filter(f);
return queue;
}
/**
* Returns a new Queue whose values are reversed in order.
* @return {Stack} Queue([reversed values])
*/
reversed() {
const queue = new Queue();
queue._linkedList = this._linkedList.reversed();
return queue;
}
/**
* If any of containing values satisfies given f, return true.
* If none of values satisfy f or not contain any value, return false.
* @param {function} f - Predicate
* @returns {boolean}
*/
some(f) {
return this._linkedList.some(f);
}
/**
* If all of containing values satisfies given f or not contain any value, return true.
* If any of value doesn't satisfy f, return false.
* @param {function} f - Predicate
* @returns {boolean}
*/
every(f) {
return this._linkedList.every(f);
}
/**
* If contains given value v, return true.
* @param {*} v
* @returns {boolean}
*/
includes(v) {
return this._linkedList.includes(v);
}
* [Symbol.iterator]() {
yield* this._linkedList;
}
}
module.exports = Queue;
/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
const Utils = __webpack_require__(0);
/**
* @class
* @memberof sangja
*/
class LinkedList {
/**
* Creates a new LinkedList.
* Iterable parameter is optional.
* @constructor
* @param {iterable} [iterable] - Iterator for initialize the list.
* @throws {TypeError} When given parameter is not iterable.
*/
constructor(iterable = []) {
this._linkedList = {
size: 0,
front: null,
end: null,
};
if (!Utils.isIterable(iterable)) {
throw TypeError();
}
[...iterable].forEach(v => this.addLast(v));
}
/**
* Return the node at the given index of the linked list.
* @param {number} index - The index to get node.
* @private
* @return {node} The node at the given index.
* When the given index < 0 or index >= size of the linked list, return undefined.
*/
_getNode(index) {
if (typeof index !== 'number' || index < 0 || index >= this._linkedList.size) {
return undefined;
}
if (index < this._linkedList.size / 2) {
let now = this._linkedList.front;
for (let i = 0; i < index; i += 1) {
now = now.next;
}
return now;
}
let now = this._linkedList.end;
for (let i = this._linkedList.size - 1; i > index; i -= 1) {
now = now.prev;
}
return now;
}
/**
* Add value at the given index of the linked list.
* @param {number} [index] - The index to add the value.
* @param {*} value - The value to add.
* @throws {RangeError} When the given index < 0 or index > size of the linked list.
*/
add(index, value) {
// Index not given. index is the value to add.
if (value === undefined) {
this.addLast(index);
return;
}
if (typeof index !== 'number' || index < 0 || index > this._linkedList.size) {
throw RangeError();
}
if (index === 0) {
const item = {
prev: null,
next: this._linkedList.front,
value,
};
if (this._linkedList.front) {
this._linkedList.front.prev = item;
} else {
// No elements until now.
this._linkedList.end = item;
}
this._linkedList.front = item;
} else if (index === this._linkedList.size) {
const item = {
prev: this._linkedList.end,
next: null,
value,
};
if (this._linkedList.end) {
this._linkedList.end.next = item;
}
this._linkedList.end = item;
} else {
const original = this._getNode(index);
const item = {
prev: original.prev,
next: original,
value,
};
item.prev.next = item;
item.next.prev = item;
}
this._linkedList.size += 1;
}
/**
* Add values in given iterator at the given index of the linked list.
* @param {number} [index] - The index to add the value.
* @param {iterable} iterable - The iterable object that contain values to add.
* @throws {RangeError} When the given index < 0 or index > size of the linked list.
*/
addAll(index, iterable) {
// Index not given. index is iterable object.
if (iterable === undefined) {
this.addAllLast(index);
return;
}
const values = [...iterable];
for (let i = values.length - 1; i >= 0; i -= 1) {
this.add(index, values[i]);
}
}
/**
* Add value at the front of the linked list.
* @param {*} value - The value to add.
*/
addFirst(value) {
this.add(0, value);
}
/**
* Add values in given iterator at the front of the linked list.
* @param {iterable} iterable - The iterable object that contain values to add.
*/
addAllFirst(iterable) {
const values = [...iterable];
for (let i = values.length - 1; i >= 0; i -= 1) {
this.add(0, values[i]);
}
}
/**
* Add value at the end of the linked list.
* @param {*} value - The value to add.
*/
addLast(value) {
this.add(this.size(), value);
}
/**
* Add values in given iterator at the end of the linked list.
* @param {iterable} iterable - The iterable object that contain values to add.
*/
addAllLast(iterable) {
const values = [...iterable];
for (let i = 0; i < values.length; i += 1) {
this.addLast(values[i]);
}
}
/**
* Removes the given index of the linked list and
* returns the value at the given index of the linked list.
* @param {number} [index] - The index to remove the value.
* @return {*} The value at the given index of the linked list. If not found, return undefined.
*/
pop(index) {
if (index === undefined) {
return this.popLast();
}
if (typeof index !== 'number' || index < 0 || index >= this._linkedList.size) {
return undefined;
}
const now = this._getNode(index);
if (now.prev) {
now.prev.next = now.next;
} else {
this._linkedList.front = now.next;
}
if (now.next) {
now.next.prev = now.prev;
} else {
this._linkedList.end = now.prev;
}
this._linkedList.size -= 1;
return now.value;
}
/**
* Removes the first of the linked list and
* returns the value at the first of the linked list.
* @return {*} The value at the front of the linked list. If empty, return undefined.
*/
popFirst() {
return this.pop(0);
}
/**
* Removes the end of the linked list and
* returns the value at the end of the linked list.
* @return {*} The value at the end of the linked list. If empty, return undefined.
*/
popLast() {
return this.pop(this.size() - 1);
}
/**
* Same with pop(i) except that index is required.
* @param {number} index - The index to remove the value.
* @return {(*|undefined)} The value at the given index of the linked list.
* If not found, return undefined.
*/
removeAt(index) {
if (typeof index !== 'number' || index < 0 || index >= this._linkedList.size) {
return undefined;
}
return this.pop(index);
}
/**
* Removes the first occurance of the given value in the linked list and
* returns true if the given value is in the linked list.
* @param {*} value - The value to remove
* @return {boolean} True if the given value is in the linked list else false.
*/
remove(value) {
let now = this._linkedList.front;
while (now) {
if (now.value === value) {
break;
}
now = now.next;
}
if (!now) {
return false;
}
if (now.prev) {
now.prev.next = now.next;
} else {
// now is front
this._linkedList.front = now.next;
}
if (now.next) {
now.next.prev = now.prev;
} else {
// now is end
this._linkedList.end = now.prev;
}
this._linkedList.size -= 1;
return true;
}
/**
* Removes the every occurance of the given value in the linked list and
* returns the number of removed values.
* @param {*} value - The value to remove
* @return {number} The number of removed values.
*/
removeAll(value) {
let now = this._linkedList.front;
let result = 0;
while (now) {
if (now.value === value) {
if (now.prev) {
now.prev.next = now.next;
} else {
// now is front
this._linkedList.front = now.next;
}
if (now.next) {
now.next.prev = now.prev;
} else {
// now is end
this._linkedList.end = now.prev;
}
this._linkedList.size -= 1;
result += 1;
}
now = now.next;
}
return result;
}
/**
* Same with remove(value) if value is given.
* If value is not given, same with popFirst().
* @param {*} [value] - The value to remove
* @return {(*|undefined|boolean)} If remove success, return true.
* If value not given, return popFirst().
*/
removeFirst(value) {
if (value === undefined) {
return this.popFirst();
}
return this.remove(value);
}
/**
* Same with remove(value) but find from start searching from last.
* @param {*} [value] - The value to remove
* @return {(*|undefined|boolean)} If remove success, return true.
* If value not given, return popLast().
*/
removeLast(value) {
let now = this._linkedList.end;
while (now) {
if (now.value === value) {
break;
}
now = now.prev;
}
if (!now) {
return false;
}
if (now.prev) {
now.prev.next = now.next;
} else {
// now is front
this._linkedList.front = now.next;
}
if (now.next) {
now.next.prev = now.prev;
} else {
// now is end
this._linkedList.end = now.prev;
}
this._linkedList.size -= 1;
return true;
}
/**
* Removes the first value that matches given predicate f and
* returns value in the linked list.
* @param {Function} f - Predicate
* @return {(*|undefined)} Found value. If not found, return undefined.
* @throws {TypeError} When the given predicate is not a function.
*/
removeMatch(f) {
if (typeof f !== 'function') {
throw TypeError();
}
let now = this._linkedList.front;
while (now) {
if (f(now.value)) {
break;
}
now = now.next;
}
if (!now) {
return undefined;
}
if (now.prev) {
now.prev.next = now.next;
} else {
// now is front
this._linkedList.front = now.next;
}
if (now.next) {
now.next.prev = now.prev;
} else {
// now is end
this._linkedList.end = now.prev;
}
this._linkedList.size -= 1;
return now.value;
}
/**
* Removes all values that matches given predicate f and
* returns the removed values.
* @param {Function} f - Predicate
* @return {any[]} Removed values.
* @throws {TypeError} When the given predicate is not a function.
*/
removeMatchAll(f) {
if (typeof f !== 'function') {
throw TypeError();
}
let now = this._linkedList.front;
const result = [];
while (now) {
if (f(now.value)) {
if (now.prev) {
now.prev.next = now.next;
} else {
// now is front
this._linkedList.front = now.next;
}
if (now.next) {
now.next.prev = now.prev;
} else {
// now is end
this._linkedList.end = now.prev;
}
this._linkedList.size -= 1;
result.push(now.value);
}
now = now.next;
}
return result;
}
/**
* Same with removeMatch(f)
* @param {Function} f - Predicate
* @return {(*|undefined)} Found value. If not found, return undefined.
* @throws {TypeError} When the given predicate is not a function.
*/
removeMatchFirst(f) {
return this.removeMatch(f);
}
/**
* Same with removeMatch(f) but find from start searching from last.
* @param {Function} f - Predicate
* @return {(*|undefined)} Found value. If not found, return undefined.
* @throws {TypeError} When the given predicate is not a function.
*/
removeMatchLast(f) {
if (typeof f !== 'function') {
throw TypeError();
}
let now = this._linkedList.end;
while (now) {
if (f(now.value)) {
break;
}
now = now.prev;
}
if (!now) {
return undefined;
}
if (now.prev) {
now.prev.next = now.next;
} else {
// now is front
this._linkedList.front = now.next;
}
if (now.next) {
now.next.prev = now.prev;
} else {
// now is end
this._linkedList.end = now.prev;
}
this._linkedList.size -= 1;
return now.value;
}
/**
* Removes all values in the linked list.
*/
clear() {
this._linkedList = {
size: 0,
front: null,
end: null,
};
}
/**
* Returns the value at the given index of the linked list.
* @param {number} index - The index to get the value.
* @return {*} The value at the given index of the linked list.
* When the given index < 0 or index >= size of the linked list, return undefined.
*/
get(index) {
if (typeof index !== 'number' || index < 0 || index >= this._linkedList.size) {
return undefined;
}
const now = this._getNode(index);
return now.value;
}
/**
* Returns the value at the first of the linked list.
* @return {*} The value at the front of the linked list. If empty, return undefined.
*/
getFirst() {
return this.get(0);
}
/**
* Returns the value at the end of the linked list.
* @return {*} The value at the end of the linked list. If empty, return undefined.
*/
getLast() {
return this.get(this.size() - 1);
}
/**
* Updates the value at the given index of the linked list and
* returns the value at the given index of the linked list.
* @param {number} index - The index to update the value.
* @param {*} value - The value to update.
* @throws {RangeError} When the given index < 0 or index >= size of the linked list.
* @return {*} The value at the given index of the linked list.
*/
set(index, value) {
if (typeof index !== 'number' || index < 0 || index >= this._linkedList.size) {
throw RangeError();
}
const now = this._getNode(index);
const ret = now.value;
now.value = value;
return ret;
}
/**
* Returns the value of the first element in the linked list
* that satisfies the provided testing function.
* @param {function} f - Testing function.
* @return {*} The the first value in the linked list
* that satisfies the provided testing function.
* When no element in the linked list satisfies the provided testing function, return undefined.
*/
find(f) {
let now = this._linkedList.front;
while (now && !f(now.value)) {
now = now.next;
}
if (now) {
return now.value;
}
return undefined;
}
/**
* Returns the number of elements in the linked list.
* @return {number} The number of elements in the linked list.
*/
size() {
return this._linkedList.size;
}
/**
* Returns whether the linked list is empty.
* @return {boolean} True if the linked list is empty.
*/
isEmpty() {
return this._linkedList.size === 0;
}
/**
* For each values in the list, execute the given procedure f.
* @param {function} f - Procedure to execute
*/
forEach(f) {
let now = this._linkedList.front;
while (now) {
f(now.value);
now = now.next;
}
}
/**
* Returns a new LinkedList whose values are mapped with given function f.
* @param {function} f - Function to map values
* @return {LinkedList} LinkedList([mapped values])
*/
map(f) {
const list = new LinkedList();
this.forEach(v => list.addLast(f(v)));
return list;
}
/**
* Returns a new LinkedList whose values are mapped with given function f and flattened.
* @param {function} f - Function (this.value) => iterable
* @return {LinkedList} LinkedList([mapped and flattened values])
*/
flatMap(f) {
const list = new LinkedList();
this.forEach(v => list.addAllLast([...f(v)]));
return list;
}
/**
* Returns a new LinkedList whose values are filtered with given predicate f.
* @param {function} f - Predicate (this.value) => boolean
* @return {LinkedList} LinkedList([filtered values])
*/
filter(f) {
const list = new LinkedList();
this.forEach((v) => {
if (f(v)) {
list.addLast(v);
}
});
return list;
}
/**
* Returns a new LinkedList whose values are reversed in order.
* @return {LinkedList} LinkedList([reversed values])
*/
reversed() {
const list = new LinkedList();
this.forEach(v => list.addFirst(v));
return list;
}
/**
* If any of containing values satisfies given f, return true.
* If none of values satisfy f or not contain any value, return false.
* @param {function} f - Predicate
* @return {boolean}
*/
some(f) {
if (this.size() === 0) {
return false;
}
let now = this._linkedList.front;
while (now) {
if (f(now.value)) {
return true;
}
now = now.next;
}
return false;
}
/**
* If all of containing values satisfies given f or not contain any value, return true.
* If any of value doesn't satisfy f, return false.
* @param {function} f - Predicate
* @return {boolean}
*/
every(f) {
let now = this._linkedList.front;
while (now) {
if (!f(now.value)) {
return false;
}
now = now.next;
}
return true;
}
/**
* If contains given value v, return true.
* @param {*} v
* @return {boolean}
*/
includes(v) {
let now = this._linkedList.front;
while (now) {
if (now.value === v) {
return true;
}
now = now.next;
}
return false;
}
* [Symbol.iterator]() {
let now = this._linkedList.front;
while (now) {
yield now.value;
now = now.next;
}
}
}
module.exports = LinkedList;
/***/ }),
/* 3 */
/***/ (function(module, exports, __webpack_require__) {
const Utils = __webpack_require__(0);
const Optional = __webpack_require__(4);
const Stack = __webpack_require__(5);
const Queue = __webpack_require__(1);
const LinkedList = __webpack_require__(2);
const Heap = __webpack_require__(6);
const BinarySearchTree = __webpack_require__(7);
/**
* @namespace sangja
*/
module.exports = {
Optional,
Stack,
Queue,
LinkedList,
Heap,
BinarySearchTree,
isIterable: Utils.isIterable,
defaultKey: Utils.defaultKey,
defaultCompare: Utils.defaultCompare,
};
/***/ }),
/* 4 */
/***/ (function(module, exports) {
/**
* @class
* @memberof sangja
*/
class Optional {
/**
* Creates a new Optional.
* Value parameter is optional. Undefeined for value is not allowed.(Not work well)
* @constructor
* @param {*} [value=undefined] - Value to contain
*/
constructor(value = undefined) {
this.value = value;
}
/**
* Returns the containing value.
* @returns {*|undefined} The containing value. If it does not contain a value, return undefined
*/
get() {
return this.value;
}
/**
* Returns the containing value.
* @returns {*} The containing value. If it does not contain a value, return undefined
*/
getOrElse(value) {
if (this.value === undefined) {
return value;
}
return this.value;
}
/**
* If the optional contains a value, returns 1 else 0.
* @returns {number} The number of elements in the optional(0 or 1)
*/
size() {
if (this.value === undefined) {
return 0;
}
return 1;
}
/**
* If the optional is empty, returns true else returns false.
* @returns {boolean} True if the optional is empty else false
*/
isEmpty() {
if (this.value === undefined) {
return true;
}
return false;
}
/**
* If the optional contains a value, execute the given function f.
* @param {function} f - Function to execute
*/
forEach(f) {
if (this.value === undefined) {
return;
}
f(this.value);
}
/**
* If the optional contains a value, execute the given function f
* and returns the new optional containing f(this.value).<br>
* If the optional is empty or catch error while executing f, returns empty optional.
* @param {function} f - Function to execute with this.value
* @return {Optional} Optional(f(this.value)) or Optional()
*/
map(f) {
if (this.value === undefined) {
return new Optional();
}
try {
return new Optional(f(this.value));
} catch (err) {
return new Optional();
}
}
/**
* If the optional contains a value, execute the given function f
* and flatten the result.<br>
* Returns the new optional containing flatten result of f(this.value)<br>
* If the optional is empty or catch error while executing f, returns empty optional.
* @param {function} f - (this.value) => Optional
* @return {Optional} Optional(...f(this.value)) or Optional()
*/
flatMap(f) {
if (this.value === undefined) {
return new Optional();
}
try {
return new Optional(...f(this.value));
} catch (err) {
return new Optional();
}
}
/**
* If the contained value satisfies the predicate, return this.
* If the optional is empty or given predicate returns false, returns empty optional.
* @param {function} f - Predicate
* @return {Optional} Optional(this.value) or Optional()
*/
filter(f) {
if (this.value === undefined) {
return new Optional();
}
if (f(this.value)) {
return this;
}
return new Optional();
}
/**
* If containing value satisfies given f, return true.
* If not satisfy f or not contain any value, return false.
* @param {function} f - Predicate
* @returns {boolean}
*/
some(f) {
if (this.value === undefined) {
return false;
}
return Boolean(f(this.value));
}
/**
* If not contain any value or containing value satisfies given f, return true.
* If not satisfy f, return false.
* @param {function} f - Predicate
* @returns {boolean}
*/
every(f) {
if (this.value === undefined) {
return true;
}
return Boolean(f(this.value));
}
/**
* If contains given value v, return true.
* @param {*} v
* @returns {boolean}
*/
includes(v) {
if (this.value !== undefined && this.value === v) {
return true;
}
return false;
}
* [Symbol.iterator]() {
if (this.value !== undefined) {
yield this.value;
}
}
}
module.exports = Optional;
/***/ }),
/* 5 */
/***/ (function(module, exports, __webpack_require__) {
const Utils = __webpack_require__(0);
/**
* @class
* @memberof sangja
*/
class Stack {
/**
* Creates a new Stack.
* Iterable parameter is optional.
* @constructor
* @param {iterable} [iterable] - Iterator for initialize the stack.
* @throws {TypeError} When given parameter is not stack.
*/
constructor(iterable = []) {
if (!Utils.isIterable(iterable)) {
throw TypeError();
}
this._stack = [...iterable];
}
/**
* Add value at the top of the stack.
* @param {*} value - The value to push to the stack.
*/
push(value) {
this._stack.push(value);
}
/**
* Add values in the given iterator at the top of the stack.
* @param {iterable} iterable - The iterable values to push to the stack.
*/
pushAll(iterable) {
[...iterable].forEach(v => this._stack.push(v));
}
/**
* Removes the top of the stack and returns the value at the top of the stack.
* @returns {*} The value at the top of the stack. If empty, return undefined.
*/
pop() {
if (this._stack.length === 0) {
return undefined;
}
return this._stack.pop();
}
/**
* Returns the value at the top of the stack without changing the state of the stack.
* @returns {*} The value at the top of the stack. If empty, return undefined.
*/
top() {
if (this._stack.length === 0) {
return undefined;
}
return this._stack[this._stack.length - 1];
}
/**
* Removes all values in the stack.
*/
clear() {
this._stack = [];
}
/**
* Returns the number of elements in the stack.
* @returns {number} The number of elements in the stack.
*/
size() {
return this._stack.length;
}
/**
* Returns whether the stack is empty.
* @returns {boolean} True if the stack is empty.
*/
isEmpty() {
return this._stack.length === 0;
}
/**
* For each values in the stack, execute the given procedure f.<br>
* *Executing order is top to bottom*
* @param {function} f - Procedure to execute
*/
forEach(f) {
for (let i = this._stack.length - 1; i >= 0; i -= 1) {
f(this._stack[i]);
}
}
/**
* Returns a stack whose values are mapped with given function f.
* @param {function} f - Function to map values
* @return {Stack} Stack([mapped values])
*/
map(f) {
const stack = new Stack();
stack._stack = this._stack.map(f);
return stack;
}
/**
* Returns a stack whose values are mapped with given function f and flattened.
* @param {function} f - Function (this.value) => iterable
* @return {Stack} Stack([mapped and flattened values])
*/
flatMap(f) {
const stack = new Stack();
// [...this._stack.map(f)].forEach(arr => arr.forEach(v => stack.push(v)));
this._stack.map(f).forEach(arr => stack.pushAll(arr));
return stack;
}
/**
* Returns a stack whose values are filtered with given predicate f.
* @param {function} f - Predicate (this.value) => boolean
* @return {Stack} Stack([filtered values])
*/
filter(f) {
const stack = new Stack();
stack._stack = this._stack.filter(f);
return stack;
}
/**
* Returns a stack whose values are reversed in order.
* @return {Stack} Stack([reversed values])
*/
reversed() {
return new Stack(this);
}
/**
* If any of containing values satisfies given f, return true.
* If none of values satisfy f or not contain any value, return false.
* @param {function} f - Predicate
* @returns {boolean}
*/
some(f) {
return this._stack.some(f);
}
/**
* If all of containing values satisfies given f or not contain any value, return true.
* If any of value doesn't satisfy f, return false.
* @param {function} f - Predicate
* @returns {boolean}
*/
every(f) {
return this._stack.every(f);
}
/**
* If contains given value v, return true.
* @param {*} v
* @returns {boolean}
*/
includes(v) {
return this._stack.includes(v);
}
* [Symbol.iterator]() {
for (let i = this._stack.length - 1; i >= 0; i -= 1) {
yield this._stack[i];
}
}
}
module.exports = Stack;
/***/ }),
/* 6 */
/***/ (function(module, exports, __webpack_require__) {
const Utils = __webpack_require__(0);
/**
* @class
* @memberof sangja
*/
class Heap {
/**
* Creates a new Heap.
* By default, max-heap is created.
* Iterable a and option object b are optional. But if both are given, a must precede b.
* @constructor
* @param {iterable} [a=[]] - Iterator for initialize
* @param {Object} [b={}] - Option object for initialize
* @param {function} [b.key=sangja.defaultKey] - Key function for each value.
* Each value should be comparable with given key.
* @param {function} [b.compare=sangja.defaultCompare] - Compare function.<br>
* If x precede y, compare(key(x), key(y)) < 0<br>
* If y precede x, compare(key(x), key(y)) > 0<br>
* If the order of x and y is the same, compare(key(x), key(y)) == 0
* @param {function} [b.reverse=false] - If true, compare result is inverted.
*/
constructor(a = {}, b = {}) {
// null, null -> iterator: [], key,compare: default
// iterator, null -> iterator: ok, key,compare: default
// option, null -> iterator: [], key,compare: option
// iterator, option -> iterator: ok, key,compare: option
let iterator = null;
let key = null;
let compare = null;
let reverse = null;
if (Utils.isIterable(a)) {
iterator = a;
// If a is an iterable, b will be an option object.(If not given, {})
({ key, compare, reverse } = b);
} else {
iterator = [];
// If a is not an iterable, a will be an option object.(If not given, {})
({ key, compare, reverse } = a);
}
this._heap = [0];
this._options = {
key: key || Utils.defaultKey,
compare: compare || Utils.defaultCompare,
reverse: reverse || false,
};
this._key = this._options.key;
if (this._options.reverse) {
this._compare = (x, y) => this._options.compare(this._key(y), this._key(x));
} else {
this._compare = (x, y) => this._options.compare(this._key(x), this._key(y));
}
[...iterator].forEach(v => this.add(v));
}
/**
* Add value to the the heap.
* @param {*} value - The value to add
*/
add(value) {
this._heap.push(value);
let now = this._heap.length - 1;
let next = Math.floor(now / 2);
while (now > 1 && this._compare(this._heap[next], this._heap[now]) < 0) {
const tmp = this._heap[next];
this._heap[next] = this._heap[now];
this._heap[now] = tmp;
now = next;
next = Math.floor(now / 2);
}
}
/**
* Add values to the the heap.
* @param {iterable} iterable - The iterable object that contain values to add.
*/
addAll(iterable) {
[...iterable].forEach(v => this.add(v));
}
/**
* Removes the root of the heap and returns the value.
* @returns {*} The value at the root of the heap. If empty, return undefined.
*/
pop() {
if (this._heap.length === 1) {
return undefined;
}
if (this._heap.length === 2) {
return this._heap.pop();
}
const value = this._heap[1];
this._heap[1] = this._heap.pop();
let now = 1;
while (now < this._heap.length) {
const left = now * 2;
const right = now * 2 + 1;
// If now < right child, now <- max(left, right) and continue
if (right < this._heap.length
&& this._compare(this._heap[now], this._heap[right]) < 0) {
let next = null;
if (this._compare(this._heap[left], this._heap[right]) < 0) {
next = right;
} else {
next = left;
}
const tmp = this._heap[now];
this._heap[now] = this._heap[next];
this._heap[next] = tmp;
now = next;
} else if (left < this._heap.length
&& this._compare(this._heap[now], this._heap[left]) < 0) {
const tmp = this._heap[now];
this._heap[now] = this._heap[left];
this._heap[left] = tmp;
now = left;
} else {
break;
}
}
return value;
}
/**
* Returns the value at the root of the heap without changing the state of the heap.
* @returns {*} The value at the root of the heap. If empty, return undefined.
*/
peek() {
if (this._heap.length === 1) {
return undefined;
}
return this._heap[1];
}
/**
* Returns the value of the first element in the heap
* that satisfies the given predicate.<br>
* Searches matching value by bfs order.
* @param {function} f - Predicate
* @returns {(*|undefined)} The the first value in the heap
* that satisfies the provided testing function.
* When no element in the heap satisfies the provided testing function, return undefined.
*/
find(f) {
for (let i = 1; i < this._heap.length; i += 1) {
if (f(this._heap[i])) {
return this._heap[i];
}
}
return undefined;
}
/**
* Returns the number of elements in the heap.
* @returns {number} The number of elements in the heap.
*/
size() {
return this._heap.length - 1;
}
/**
* Returns whether the heap is empty.
* @returns {boolean} True if the heap is empty.
*/
isEmpty() {
return this._heap.length === 1;
}
/**
* Removed all elements in the heap.
*/
clear() {
this._heap = [0];
}
/**
* Execute the given procedure f for each values.
* @param {function} f - Procedure to execute
*/
forEach(f) {
const heapForIter = new Heap(this._heap.slice(1), this._options);
while (!heapForIter.isEmpty()) {
f(heapForIter.pop());
}
}
/**
* Returns a new Heap mapped with given function f.
* @param {function} f - Function
* @param {Object} [options=this._options] - Option object for initialize the heap.<br>
* If not given, inherits from this.
* If only a portion is given, ingerits those that are not given.
* @return {Heap} Heap([mapped values])
*/
map(f, options) {
const heap = new Heap(Utils.mergeOptions(options, this._options));
this.forEach(v => heap.add(f(v)));
return heap;
}
/**
* Returns a new Heap whose values are mapped with given function f and flattened.
* @param {function} f - Function (this.value) => iterable
* @param {Object} [options=this._options] - Option object for initialize the heap.<br>
* If not given, inherits from this.
* If only a portion is given, ingerits those that are not given.
* @return {Heap} Heap([mapped and flattened values])
*/
flatMap(f, options) {
const heap = new Heap(Utils.mergeOptions(options, this._options));
this.forEach(v => heap.addAll([...f(v)]));
return heap;
}
/**
* Returns a new Heap whose values are filtered with given predicate f.
* @param {function} f - Predicate (this.value) => boolean
* @param {Object} [options=this._options] - Option object for initialize the heap.<br>
* If not given, inherits from this.
* If only a portion is given, ingerits those that are not given.
* @return {Heap} Heap([filtered values])
*/
filter(f, options) {
const heap = new Heap(Utils.mergeOptions(options, this._options));
this.forEach((v) => {
if (f(v)) {
heap.add(v);
}
});
return heap;
}
/**
* Return new heap with same items, but reversed option is inverted from this.
* @return {Heap} Heap([reversed values])
*/
reversed() {
return new Heap(this, Utils.mergeOptions({ reverse: !this._options.reverse }, this._options));
}
/**
* If any of containing values satisfies given f, return true.
* If none of values satisfy f or not contain any value, return false.
* @param {function} f - Predicate
* @returns {boolean}
*/
some(f) {
for (let i = 1; i < this._heap.length; i += 1) {
if (f(this._heap[i])) {
return true;
}
}
return false;
}
/**
* If all of containing values satisfies given f or not contain any value, return true.
* If any of value doesn't satisfy f, return false.
* @param {function} f - Predicate
* @returns {boolean}
*/
every(f) {
for (let i = 1; i < this._heap.length; i += 1) {
if (!f(this._heap[i])) {
return false;
}
}
return true;
}
/**
* If contains given value v, return true.
* @param {*} v
* @returns {boolean}
*/
includes(v) {
for (let i = 1; i < this._heap.length; i += 1) {
if (this._heap[i] === v) {
return true;
}
}
return false;
}
* [Symbol.iterator]() {
// Use other heap!
const heapForIter = new Heap(this._heap.slice(1), this._options);
while (!heapForIter.isEmpty()) {
yield heapForIter.pop();
}
}
/**
* Returns breadth first iterator.
* @param {Function} [f] - If f is given, execute f by bfs order.
* @returns {(generator|undefined)} Tree breadth first iterator. If f if given, not return.
*/
// eslint-disable-next-line consistent-return
breadthFirst(f) {
if (!f) {
const that = this;
return (function* _breadthFirst() {
for (let i = 1; i < that._heap.length; i += 1) {
yield that._heap[i];
}
}());
}
for (let i = 1; i < this._heap.length; i += 1) {
f(this._heap[i]);
}
}
}
module.exports = Heap;
/***/ }),
/* 7 */
/***/ (function(module, exports, __webpack_require__) {
const Utils = __webpack_require__(0);
const Queue = __webpack_require__(1);
/**
* @class
* @memberof sangja
*/
class BinarySearchTree {
/**
* Creates a new BinarySearchTree.
* Iterable a and option object b are optional. But if both are given, a must precede b.
* @constructor
* @param {iterable} [a=[]] - Iterator for initialize
* @param {Object} [b={}] - Option object
* @param {function} [b.key=utils.defaultKey] - Key function for each value.
* Each value should be comparable with given key.
* @param {function} [b.compare=utils.defaultCompare] - Compare function.<br>
* If x precede y, compare(key(x), key(y)) < 0<br>
* If y precede x, compare(key(x), key(y)) > 0<br>
* If the order of x and y is the same, compare(key(x), key(y)) == 0
* @param {function} [b.reverse=false] - If true, compare result is inverted.
*/
constructor(a = {}, b = {}) {
// null, null -> iterator: [], key,compare: default
// iterator, null -> iterator: ok, key,compare: default
// option, null -> iterator: [], key,compare: option
// iterator, option -> iterator: ok, key,compare: option
let iterator = null;
let key = null;
let compare = null;
let reverse = null;
if (Utils.isIterable(a)) {
iterator = a;
// If a is an iterable, b will be an option object.(If not given, {})
({ key, compare, reverse } = b);
} else {
iterator = [];
// If a is not an iterable, a will be an option object.(If not given, {})
({ key, compare, reverse } = a);
}
this._root = null;
this._options = {
key: key || Utils.defaultKey,
compare: compare || Utils.defaultCompare,
reverse: reverse || false,
};
this._key = this._options.key;
if (this._options.reverse) {
this._compare = (x, y) => this._options.compare(this._key(y), this._key(x));
} else {
this._compare = (x, y) => this._options.compare(this._key(x), this._key(y));
}
[...iterator].forEach(v => this.add(v));
}
/**
* Add value to the tree.
* @param {*} value - The value to add to the tree.
*/
add(value) {
if (this._root == null) {
this._root = {
left: null,
right: null,
children: 0,
value,
};
return;
}
let parent = null;
let now = this._root;
let direction = null; // 0 if left else 1;
while (now) {
parent = now;
now.children += 1;
if (this._compare(value, now.value) <= 0) {
now = now.left;
direction = 0;
} else {
now = now.right;
direction = 1;
}
}
now = {
left: null,
right: null,
children: 0,
value,
};
if (direction === 0) {
parent.left = now;
} else {
parent.right = now;
}
}
/**
* Add values to the the tree.
* @param {iterable} iterable - The iterable object that contain values to add.
*/
addAll(iterable) {
[...iterable].forEach(v => this.add(v));
}
/**
* Removes the lowest value of the tree and returns the value.
* @returns {*} The lowest value of the tree. If empty, return undefined.
*/
pop() {
if (this._root === null) {
return undefined;
}
let parent = null;
let now = this._root;
while (now.left) {
now.children -= 1;
parent = now;
now = now.left;
}
if (parent !== null) {
parent.left = now.right;
} else {
this._root = now.right;
}
return now.value;
}
/**
* Removes the given value in the tree and returns the value.
* @returns {(*|undefined)} The lowest value of the tree. If empty or not found, return undefined.
*/
remove(v) {
if (this._root === null || !this.includes(v)) {
return undefined;
}
let parent = null;
let now = this._root;
while (now) {
const comp = this._compare(this._key(v), this._key(now.value));
if (comp === 0) {
break;
} else if (comp < 0) {
now.children -= 1;
parent = now;
now = now.left;
} else {
now.children -= 1;
parent = now;
now = now.right;
}
}
// Not found
if (now === null) {
return undefined;
}
// If now has both child, move left rightmost child.
if (now.left && now.right) {
let rightmostParent = now;
let rightmost = now.left;
while (rightmost.right) {
rightmostParent.children -= 1;
rightmostParent = rightmost;
rightmost = rightmost.right;
}
if (rightmostParent !== now) {
// Found rightmost.
rightmostParent.right = rightmost.left;
} else {
// Rightmost is now.left
rightmostParent.left = rightmost.left;
}
const result = now.value;
now.value = rightmost.value;
return result;
}
// If now has left child, remove now.
if (now.left) {
if (now === this._root) {
this._root = now.left;
} else if (parent.left === now) {
parent.left = now.left;
} else {
parent.right = now.left;
}
return now.value;
}
// If now has right child, remove now.
if (now.right) {
if (now === this._root) {
this._root = now.right;
} else if (parent.left === now) {
parent.left = now.right;
} else {
parent.right = now.right;
}
return now.value;
}
// If now is left, remove now from parent.
if (now === this._root) {
this._root = null;
} else if (parent.left === now) {
parent.left = null;
} else {
parent.right = null;
}
return now.value;
}
/**
* Removes a value that matches given predicate f and
* returns value in the linked list.
* @param {Function} f - Predicate
* @returns {(*|undefined)} Found value. If not found, return undefined.
* @throws {TypeError} When the given predicate is not a function.
*/
removeMatch(f) {
if (typeof f !== 'function') {
throw TypeError();
}
if (this.isEmpty()) {
return undefined;
}
function _getMatch(node) {
if (f(node.value)) {
return node.value;
}
return (node.left && _getMatch(node.left))
|| (node.right && _getMatch(node.right));
}
const removeVal = _getMatch(this._root);
this.remove(removeVal);
return removeVal;
}
/**
* Returns the lowest value of the tree without changing the state of the tree.
* @returns {*} The lowest value of the tree. If empty, return undefined.
*/
peek() {
if (this._root === null) {
return undefined;
}
let now = this._root;
while (now) {
if (now.left) {
now = now.left;
}
}
return now.value;
}
/**
* Returns the value of the first element in the binary search tree
* that satisfies the given predicate.<br>
* Searches matching value by dfs order(preorder).
* @param {function} f - Predicate
* @returns {(*|undefined)} The the first value in the binary search tree
* that satisfies the provided testing function.
* When no element in the binary search tree satisfies
* the provided testing function, return undefined.
*/
find(f) {
const nodes = [this._root];
while (nodes.length > 0) {
const now = nodes.pop();
if (now) {
if (f(now.value)) {
return now.value;
}
nodes.push(now.left);
nodes.push(now.right);
}
}
return undefined;
}
/**
* Returns the number of elements in the tree.
* @returns {number} The number of elements in the tree.
*/
size() {
if (this._root === null) {
return 0;
}
return this._root.children + 1;
}
/**
* Returns whether the tree is empty.
* @returns {boolean} True if the tree is empty.
*/
isEmpty() {
return this._root === null;
}
/**
* Removed all elements in the tree.
*/
clear() {
this._root = null;
}
/**
* Execute the given procedure f for each values.
* @param {function} f - Procedure to execute
*/
forEach(f) {
function _forEach(node) {
if (node) {
f(node.value);
_forEach(node.left);
_forEach(node.right);
}
}
_forEach(this._root);
}
/**
* Returns a new BinarySearchTree mapped with given function f.
* @param {function} f - Function
* @param {Object} [options=this._options] - Option object for initialize.<br>
* If not given, inherits from this.
* If only a portion is given, ingerits those that are not given.
* @return {BinarySearchTree} BinarySearchTree([mapped values])
*/
map(f, options) {
const tree = new this.constructor(Utils.mergeOptions(options, this._options));
this.forEach(v => tree.add(f(v)));
return tree;
}
/**
* Returns a new BinarySearchTree whose values are mapped with given function f and flattened.
* @param {function} f - Function (this.value) => iterable
* @param {Object} [options=this._options] - Option object for initialize.<br>
* If not given, inherits from this.
* If only a portion is given, ingerits those that are not given.
* @return {BinarySearchTree} BinarySearchTree([mapped and flattened values])
*/
flatMap(f, options) {
const tree = new this.constructor(Utils.mergeOptions(options, this._options));
this.forEach(v => tree.addAll([...f(v)]));
return tree;
}
/**
* Returns a new BinarySearchTree whose values are filtered with given predicate f.
* @param {function} f - Predicate (this.value) => boolean
* @param {Object} [options=this._options] - Option object for initialize.<br>
* If not given, inherits from this.
* If only a portion is given, ingerits those that are not given.
* @return {BinarySearchTree} BinarySearchTree([filtered values])
*/
filter(f, options) {
const tree = new this.constructor(Utils.mergeOptions(options, this._options));
this.forEach((v) => {
if (f(v)) {
tree.add(v);
}
});
return tree;
}
/**
* Return new tree with same items, but reversed option is inverted from this.
* @return {BinarySearchTree} BinarySearchTree([reversed values])
*/
reversed() {
return new this.constructor(this,
Utils.mergeOptions({ reverse: !this._options.reverse }, this._options));
}
/**
* If any of containing values satisfies given f, return true.
* If none of values satisfy f or not contain any value, return false.
* @param {function} f - Predicate
* @returns {boolean}
*/
some(f) {
function _some(node) {
return f(node.value)
|| Boolean(node.left && _some(node.left))
|| Boolean(node.right && _some(node.right));
}
return Boolean(this._root) && _some(this._root);
}
/**
* If all of containing values satisfies given f or not contain any value, return true.
* If any of value doesn't satisfy f, return false.
* @param {function} f - Predicate
* @returns {boolean}
*/
every(f) {
function _every(node) {
return f(node.value)
&& Boolean(!node.left || _every(node.left))
&& Boolean(!node.right || _every(node.right));
}
return !this._root || _every(this._root);
}
/**
* If contains given value v, return true.
* @param {*} v
* @returns {boolean}
*/
includes(v) {
let now = this._root;
while (now) {
const comp = this._compare(this._key(v), this._key(now.value));
if (comp === 0) {
return true;
}
if (comp < 0) {
now = now.left;
} else {
now = now.right;
}
}
return false;
}
/**
* Returns whether the tree is empty.
* @name Symbol.iterator
* @generator
* @property {generator}
* @returns {boolean} True if the tree is empty.
*/
* [Symbol.iterator]() {
yield* this.inorder();
}
/**
* Returns inorder iterator.
* @param {Function} [f] - If f is given, execute f by inorder.
* @returns {(generator|undefined)} Tree inorder iterator. If f if given, not return.
*/
// eslint-disable-next-line consistent-return
inorder(f) {
if (!f) {
return (function* _inorderIterator(node) {
if (node !== null) {
yield* _inorderIterator(node.left);
yield node.value;
yield* _inorderIterator(node.right);
}
}(this._root));
}
function _inorder(node) {
if (node !== null) {
_inorder(node.left);
f(node.value);
_inorder(node.right);
}
}
_inorder(this._root);
}
/**
* Returns preorder iterator.
* @param {Function} [f] - If f is given, execute f by preorder.
* @returns {(generator|undefined)} Tree preorder iterator. If f if given, not return.
*/
// eslint-disable-next-line consistent-return
preorder(f) {
if (!f) {
return (function* _preorderIterator(node) {
if (node !== null) {
yield node.value;
yield* _preorderIterator(node.left);
yield* _preorderIterator(node.right);
}
}(this._root));
}
function _preorder(node) {
if (node !== null) {
f(node.value);
_preorder(node.left);
_preorder(node.right);
}
}
_preorder(this._root);
}
/**
* Returns postorder iterator.
* @param {Function} [f] - If f is given, execute f by postorder.
* @returns {(generator|undefined)} Tree postorder iterator. If f if given, not return.
*/
// eslint-disable-next-line consistent-return
postorder(f) {
if (!f) {
return (function* _postorderIterator(node) {
if (node !== null) {
yield* _postorderIterator(node.left);
yield* _postorderIterator(node.right);
yield node.value;
}
}(this._root));
}
function _postorder(node) {
if (node !== null) {
_postorder(node.left);
_postorder(node.right);
f(node.value);
}
}
_postorder(this._root);
}
/**
* Returns breadth first iterator.
* @param {Function} [f] - If f is given, execute f by breadth first.
* @returns {(generator|undefined)} Tree breadth first iterator. If f if given, not return.
*/
// eslint-disable-next-line consistent-return
breadthFirst(f) {
if (!f) {
return (function* _breadthFirstIterator(root) {
const queue = new Queue();
queue.enqueue(root);
while (queue.size() > 0) {
const now = queue.dequeue();
if (now !== undefined && now !== null) {
yield now.value;
queue.enqueue(now.left);
queue.enqueue(now.right);
}
}
}(this._root));
}
function _breadthFirst(root) {
const queue = new Queue();
queue.enqueue(root);
while (queue.size() > 0) {
const now = queue.dequeue();
if (now !== undefined && now !== null) {
f(now.value);
queue.enqueue(now.left);
queue.enqueue(now.right);
}
}
}
_breadthFirst(this._root);
}
}
module.exports = BinarySearchTree;
/***/ })
/******/ ]);
});
//# sourceMappingURL=sangja.map