// 堆疊樹(由下往上)
// (1~n) m 的子節點為 2m, 2m+1
// 階層從 1階 開始
// 每階最多 (2(level-1)次方) 個節點
let data = [26, 5, 19, 1, 61, 11, 59, 15, 48, 77];
// 最後一個有子節點的節點
let lastParentIndex = Math.floor(data.length / 2) - 1;
console.log(JSON.stringify(data));
// 往前拜訪每個有孩子的節點
for (let i = lastParentIndex; i >= 0; i--) {
debugger;
check(i, data);
}
console.log(JSON.stringify(data));
//----------------------------
// 檢查父節點與子節點的大小
function check(parent_index, _data) {
debugger;
// 會不斷往下有子節點的節點探索
while (parent_index <= lastParentIndex) {
let leftIndex = (parent_index + 1) * 2 - 1;
let rightIndex = leftIndex + 1;
// 可能沒有 right 子節點
rightIndex = (rightIndex >= _data.length) ? null : rightIndex;
// console.log('%d = %d', _data[leftIndex], _data[rightIndex]);
let maxIndex = (rightIndex == null || (_data[leftIndex] > _data[rightIndex])) ? leftIndex : rightIndex;
if (_data[parent_index] < _data[maxIndex]) {
// 交換
let temp = _data[maxIndex];
_data[maxIndex] = _data[parent_index];
_data[parent_index] = temp;
}
// 往下層比較
// 確定變動的節點要比他的子節點大
parent_index = maxIndex;
}
}
------------------------------------------------------------------------
// 堆疊樹(由上往下)
// (1~n) m 的子節點為 2m, 2m+1
// 階層從 1階 開始
// 每階最多 (2(level-1)次方) 個節點
let data = [26, 5, 19, 1, 61, 11, 59, 15, 48, 77];
console.log(JSON.stringify(data));
// 往前拜訪每個有孩子的節點
for (let i = 0; i < data.length; i++) {
debugger;
check(i, data);
}
console.log(JSON.stringify(data));
//----------------------------
// 檢查父節點與子節點的大小
function check(parent_index, _data) {
debugger;
let prev_index;
// 會不斷往下有子節點的節點探索
while (parent_index >= 0) {
if (prev_index != null) {
// 回朔 只需比對上一個子節點
if (_data[parent_index] < _data[prev_index]) {
// 交換
let temp = _data[prev_index];
_data[prev_index] = _data[parent_index];
_data[parent_index] = temp;
}
} else {
// 第一次進入
let leftIndex = (parent_index + 1) * 2 - 1;
let rightIndex = leftIndex + 1;
leftIndex = (leftIndex >= _data.length) ? null : leftIndex;
rightIndex = (rightIndex >= _data.length) ? null : rightIndex;
if (leftIndex == null && rightIndex == null) {
// 都沒有子節點
return;
}
console.log('%d(%d,%d)', _data[parent_index], _data[leftIndex], _data[rightIndex]);
let maxIndex = (rightIndex == null || (_data[leftIndex] > _data[rightIndex])) ? leftIndex : rightIndex;
if (_data[parent_index] < _data[maxIndex]) {
// 交換
let temp = _data[maxIndex];
_data[maxIndex] = _data[parent_index];
_data[parent_index] = temp;
}
}
//-----------------------
prev_index = parent_index;
// 往下層比較
// 確定變動的節點要比他的子節點大
let nextCheckIndex = Math.floor((parent_index + 1) / 2) - 1;
if (nextCheckIndex == parent_index && parent_index == 0) {
// 只為了解決無限迴圈
return;
}
// 往上
parent_index = nextCheckIndex;
}
}
2019年3月14日 星期四
2019年3月13日 星期三
DoublyLinkedList
module.exports = DoublyLinkedList;
// 雙向連結
function DoublyLinkedList() {
let head;
let tail;
let length;
this._head = function (node) {
if (node == null) {
return head;
} else {
head = node;
}
};
this._tail = function (node) {
if (node == null) {
return tail;
} else {
tail = node;
}
};
this._length = function (_length) {
if (_length == null) {
return length;
} else {
length = _length;
}
};
}
(function () {
this.append = function (el) {
debugger;
let node = new Node(el);
if (this._head() == null) {
this._head(node);
this._length(1);
this._tail(node);
} else {
let prev_node = this._head();
let count = 0;
while (prev_node.next != null) {
prev_node = prev_node.next;
count++;
}
prev_node.next = node;
node.prev = prev_node;
this._length(++count);
this._tail(prev_node);
}
};
this.insert = function (position, el) {
};
this.remove = function (el) {
};
this.removeAt = function (position) {
};
this.indexOf = function (position) {
};
this.size = function () {
return this._length();
};
this.toJSON = function () {
debugger;
let res = [];
let node = this._head();
do {
if (node == null) {
break;
} else {
res.push(JSON.stringify(node.element));
}
} while ((node = node.next) != null);
return res.join(',');
};
}).call(DoublyLinkedList.prototype);
//==============================================================================
function Node(el) {
this.element = el;
this.prev = null;
this.next = null;
}
// 雙向連結
function DoublyLinkedList() {
let head;
let tail;
let length;
this._head = function (node) {
if (node == null) {
return head;
} else {
head = node;
}
};
this._tail = function (node) {
if (node == null) {
return tail;
} else {
tail = node;
}
};
this._length = function (_length) {
if (_length == null) {
return length;
} else {
length = _length;
}
};
}
(function () {
this.append = function (el) {
debugger;
let node = new Node(el);
if (this._head() == null) {
this._head(node);
this._length(1);
this._tail(node);
} else {
let prev_node = this._head();
let count = 0;
while (prev_node.next != null) {
prev_node = prev_node.next;
count++;
}
prev_node.next = node;
node.prev = prev_node;
this._length(++count);
this._tail(prev_node);
}
};
this.insert = function (position, el) {
};
this.remove = function (el) {
};
this.removeAt = function (position) {
};
this.indexOf = function (position) {
};
this.size = function () {
return this._length();
};
this.toJSON = function () {
debugger;
let res = [];
let node = this._head();
do {
if (node == null) {
break;
} else {
res.push(JSON.stringify(node.element));
}
} while ((node = node.next) != null);
return res.join(',');
};
}).call(DoublyLinkedList.prototype);
//==============================================================================
function Node(el) {
this.element = el;
this.prev = null;
this.next = null;
}
2019年3月8日 星期五
一個 promise 再包裝的例子
'use strict';
/**
* Promise
*
* Inspired by https://gist.github.com/RubaXa/8501359 from RubaXa <trash@rubaxa.org>
*
* @param {Function} handler Called as handler(resolve: Function, reject: Function)
* @param {Promise} [parent] Parent promise for propagation of cancel and timeout
*/
function Promise(handler, parent) {
var me = this;
if (!(this instanceof Promise)) {
throw new SyntaxError('Constructor must be called with the new operator');
}
if (typeof handler !== 'function') {
throw new SyntaxError('Function parameter handler(resolve, reject) missing');
}
var _onSuccess = [];
var _onFail = [];
// status
this.resolved = false;
this.rejected = false;
this.pending = true;
/**
* Process onSuccess and onFail callbacks: add them to the queue.
* Once the promise is resolve, the function _promise is replace.
* @param {Function} onSuccess
* @param {Function} onFail
* @private
*/
var _process = function (onSuccess, onFail) {
_onSuccess.push(onSuccess);
_onFail.push(onFail);
};
/**
* Add an onSuccess callback and optionally an onFail callback to the Promise
* @param {Function} onSuccess
* @param {Function} [onFail]
* @returns {Promise} promise
*/
this.then = function (onSuccess, onFail) {
return new Promise(function (resolve, reject) {
var s = onSuccess ? _then(onSuccess, resolve, reject) : resolve;
var f = onFail ? _then(onFail, resolve, reject) : reject;
_process(s, f);
}, me);
};
/**
* Resolve the promise
* @param {*} result
* @type {Function}
*/
var _resolve = function (result) {
// update status
me.resolved = true;
me.rejected = false;
me.pending = false;
_onSuccess.forEach(function (fn) {
fn(result);
});
_process = function (onSuccess, onFail) {
onSuccess(result);
};
_resolve = _reject = function () { };
return me;
};
/**
* Reject the promise
* @param {Error} error
* @type {Function}
*/
var _reject = function (error) {
// update status
me.resolved = false;
me.rejected = true;
me.pending = false;
_onFail.forEach(function (fn) {
fn(error);
});
_process = function (onSuccess, onFail) {
onFail(error);
};
_resolve = _reject = function () { }
return me;
};
/**
* Cancel te promise. This will reject the promise with a CancellationError
* @returns {Promise} self
*/
this.cancel = function () {
if (parent) {
parent.cancel();
} else {
_reject(new CancellationError());
}
return me;
};
/**
* Set a timeout for the promise. If the promise is not resolved within
* the time, the promise will be cancelled and a TimeoutError is thrown.
* If the promise is resolved in time, the timeout is removed.
* @param {number} delay Delay in milliseconds
* @returns {Promise} self
*/
this.timeout = function (delay) {
if (parent) {
parent.timeout(delay);
} else {
var timer = setTimeout(function () {
_reject(new TimeoutError('Promise timed out after ' + delay + ' ms'));
}, delay);
me.always(function () {
clearTimeout(timer);
});
}
return me;
};
// attach handler passing the resolve and reject functions
handler(function (result) {
_resolve(result);
}, function (error) {
_reject(error);
});
}
/**
* Execute given callback, then call resolve/reject based on the returned result
* @param {Function} callback
* @param {Function} resolve
* @param {Function} reject
* @returns {Function}
* @private
*/
function _then(callback, resolve, reject) {
return function (result) {
try {
var res = callback(result);
if (res && typeof res.then === 'function' && typeof res['catch'] === 'function') {
// method returned a promise
res.then(resolve, reject);
} else {
resolve(res);
}
} catch (error) {
reject(error);
}
}
}
/**
* Add an onFail callback to the Promise
* @param {Function} onFail
* @returns {Promise} promise
*/
Promise.prototype['catch'] = function (onFail) {
return this.then(null, onFail);
};
// TODO: add support for Promise.catch(Error, callback)
// TODO: add support for Promise.catch(Error, Error, callback)
/**
* Execute given callback when the promise either resolves or rejects.
* @param {Function} fn
* @returns {Promise} promise
*/
Promise.prototype.always = function (fn) {
return this.then(fn, fn);
};
/**
* Create a promise which resolves when all provided promises are resolved,
* and fails when any of the promises resolves.
* @param {Promise[]} promises
* @returns {Promise} promise
*/
Promise.all = function (promises) {
return new Promise(function (resolve, reject) {
var remaining = promises.length,
results = [];
if (remaining) {
promises.forEach(function (p, i) {
p.then(function (result) {
results[i] = result;
remaining--;
if (remaining == 0) {
resolve(results);
}
}, function (error) {
remaining = 0;
reject(error);
});
});
} else {
resolve(results);
}
});
};
/**
* Create a promise resolver
* @returns {{promise: Promise, resolve: Function, reject: Function}} resolver
*/
Promise.defer = function () {
var resolver = {};
resolver.promise = new Promise(function (resolve, reject) {
resolver.resolve = resolve;
resolver.reject = reject;
});
return resolver;
};
/**
* Create a cancellation error
* @param {String} [message]
* @extends Error
*/
function CancellationError(message) {
this.message = message || 'promise cancelled';
this.stack = (new Error()).stack;
}
CancellationError.prototype = new Error();
CancellationError.prototype.constructor = Error;
CancellationError.prototype.name = 'CancellationError';
Promise.CancellationError = CancellationError;
/**
* Create a timeout error
* @param {String} [message]
* @extends Error
*/
function TimeoutError(message) {
this.message = message || 'timeout exceeded';
this.stack = (new Error()).stack;
}
TimeoutError.prototype = new Error();
TimeoutError.prototype.constructor = Error;
TimeoutError.prototype.name = 'TimeoutError';
Promise.TimeoutError = TimeoutError;
module.exports = Promise;
2019年3月7日 星期四
worker 環境判定
if(typeof Window !== 'undefined'){
// browser
}else if(typeof WorkerGlobalScope !== 'undefined'){
// browser worker
}else if(typeof module !== 'undefined'){
// node.js
const {isMainThread} = require('worker_threads');
if(isMainThread){
// MainThread
}else{
// worker
}
}
// browser
}else if(typeof WorkerGlobalScope !== 'undefined'){
// browser worker
}else if(typeof module !== 'undefined'){
// node.js
const {isMainThread} = require('worker_threads');
if(isMainThread){
// MainThread
}else{
// worker
}
}
2019年3月5日 星期二
不同系統的換行符號
str.replace(/(\r\n|\n)/, '')
|一、概念:
換行符‘\n’和回車符‘\r’
(1)換行符就是另起一行 — ‘\n‘ 10 換行(newline)
(2)回車符就是回到一行的開頭 — ‘\r‘ 13 回車(return)
所以我們平時編寫檔案的回車符應該確切來說叫做回車換行符
CR: 回車(Carriage Return) \r
LF: 換行(Line Feed) \n
二、應用:
(1)在微軟的MS-DOS和Windows中,使用“回車CR(‘\r’)”和“換行LF(‘\n’)”兩個字元作為換行符;
(2)Windows系統裡面,每行結尾是 回車 換行(CR LF),即“\r\n”;
(3)Unix系統裡,每行結尾只有 換行LF,即“\n”;
(4)Mac系統裡,每行結尾是 回車CR 即’\r’。
Mac OS 9 以及之前的系統的換行符是 CR,從 Mac OS X (後來改名為“OS X”)開始的換行符是 LF即‘\n’,和Unix/Linux統一了。
三、影響:
(1)一個直接後果是,Unix/Mac系統下的檔案在Windows裡開啟的話,所有文字會變成一行;
(2)而Windows裡的檔案在Unix/Mac下開啟的話,在每行的結尾可能會多出一個^M符號。
(3)Linux儲存的檔案在windows上用記事本看的話會出現黑點。
四、可以相互轉換:
在linux下,命令unix2dos 是把linux檔案格式轉換成windows檔案格式,命令dos2unix 是把windows格式轉換成linux檔案格式。
在不同平臺間使用FTP軟體傳送檔案時, 在ascii文字模式傳輸模式下, 一些FTP客戶端程式會自動對換行格式進行轉換. 經過這種傳輸的檔案位元組數可能會發生變化.
如果你不想ftp修改原檔案, 可以使用bin模式(二進位制模式)傳輸文字。
一個程式在windows上執行就生成CR/LF換行格式的文字檔案,而在Linux上執行就生成LF格式換行的文字檔案。
|一、概念:
換行符‘\n’和回車符‘\r’
(1)換行符就是另起一行 — ‘\n‘ 10 換行(newline)
(2)回車符就是回到一行的開頭 — ‘\r‘ 13 回車(return)
所以我們平時編寫檔案的回車符應該確切來說叫做回車換行符
CR: 回車(Carriage Return) \r
LF: 換行(Line Feed) \n
二、應用:
(1)在微軟的MS-DOS和Windows中,使用“回車CR(‘\r’)”和“換行LF(‘\n’)”兩個字元作為換行符;
(2)Windows系統裡面,每行結尾是 回車 換行(CR LF),即“\r\n”;
(3)Unix系統裡,每行結尾只有 換行LF,即“\n”;
(4)Mac系統裡,每行結尾是 回車CR 即’\r’。
Mac OS 9 以及之前的系統的換行符是 CR,從 Mac OS X (後來改名為“OS X”)開始的換行符是 LF即‘\n’,和Unix/Linux統一了。
三、影響:
(1)一個直接後果是,Unix/Mac系統下的檔案在Windows裡開啟的話,所有文字會變成一行;
(2)而Windows裡的檔案在Unix/Mac下開啟的話,在每行的結尾可能會多出一個^M符號。
(3)Linux儲存的檔案在windows上用記事本看的話會出現黑點。
四、可以相互轉換:
在linux下,命令unix2dos 是把linux檔案格式轉換成windows檔案格式,命令dos2unix 是把windows格式轉換成linux檔案格式。
在不同平臺間使用FTP軟體傳送檔案時, 在ascii文字模式傳輸模式下, 一些FTP客戶端程式會自動對換行格式進行轉換. 經過這種傳輸的檔案位元組數可能會發生變化.
如果你不想ftp修改原檔案, 可以使用bin模式(二進位制模式)傳輸文字。
一個程式在windows上執行就生成CR/LF換行格式的文字檔案,而在Linux上執行就生成LF格式換行的文字檔案。
訂閱:
文章 (Atom)