フロントエンドエンジニアのためのアルゴリズムは常に謎の層、探検するあなたとソースコードのV8を読み取ることで、この記事でArray.prototype.sort
実現するためのアルゴリズムの機能を。
あなたが聞いたとアルゴリズムをソート使用しました、さあが最初にリストされています:
- クイックソート
- バブルソート
- 挿入ソート
- マージソート
- ヒープソート
- シェルソート
- 選択ソート
- ソートカウント
- バケットソート
- 基数ソート
- ...
セッションに答えるために、上記の機能のどれをソートするためのアルゴリズムを使用していますか?
あなたは、インターネット上でソート元の記事を検索する場合、それはそうでないクイックソートを使用して、挿入ソートで配列の長さが10未満であるあなたを伝えることがあります。
私はそう思うようになったが、私はGitHubには発見がそうではありません検証答えるために時間がかかったとき。
まず、私は(記事はjsのロジックが書かれている達成するためにと言った)対応するソースコードのJSを見つけられませんでしたが、ソースコードの新しいV8バージョンが有利に変更されているのでV8 Torque
。V8 Torque
V8が開発した言語、構文と同様の活字体を作成するために設計され、そのコンパイラが使用します(もう一度、活字体の価値を証明した)CodeStubAssembler
高効率のアセンブリコードに変換します。
理解するのは簡単では、この言語のファイル拡張子があり、効率的な高級言語と同様の活字体を作成することですtq
。
私たちは感謝すべきjustjavac〜偉大な神のポインティングを
第二に、ときに私は、ソースコードを読み始め、そして我々は、配列の長さの値を決定するが、見つけることができなかった多くの場合10、クイックソートを使用してコードを見つけることができませんでした。
すべての証拠は、ソースコードが解釈される前に、物品が古くなってもよいことを示しています。
そして、ソートアルゴリズムは何をすべきかとV8の最新バージョン?
解釈アルゴリズム
それは安定したソートアルゴリズムではありませんので、XXのV8エンジンのバージョンの後、最悪の場合には、時間の複雑さはO(nは^ 2)に格下げされ、クイックソートを放棄します。
TimSort:代わりに、アルゴリズムのハイブリッド並べ替えを使用しての。
:もともとはPython言語で使用されるこの関数アルゴリズムは、tは厳密にはハイブリッド順序付けアルゴリズムに属する10以上のソートアルゴリズムのいずれにも属さない話す
サブアレイで使用される少量のデータ挿入ソート、その後、使用はマージソート部分配列を注文することになるソート、時間計算量はO(nlogn)で合流します。
V8バインディングソース、次のように、具体的な実施手順は次のとおりです。
- 配列の長さは、2未満の直接的なリターンを決定する、ソートされません。
- サイクルを開始します。
- 私たちは、長さcurrentRunLength、「実行」を呼び出すサブアレイを、見つけるために命じました。
- (この値は動的に32〜64の間、配列の長さに応じて変化する)minRunLength合成最小系列長を算出します。
- 比較currentRunLengthとminRunLengthは、currentRunLength> = minRunLength場合、または配列minRunLengthの長さを補うために挿入ソートを使用して、pendingRunsにスタックに実行されます。
- それは満足pendingRunsに押されるまで、下からいずれかの保証実行三つの連続実行(RUN0、RUN1、RUN2)の新しいスタックがRUN0> RUN1 + RUN2 && RUN1を満たすたびに> RUN2、ない、調整することができます。
- 残りのサブ配列が0の場合、ループは終了します。
- 組み合わせたスタックは、すべてのエンドを注文、実行します。
ソースを読みます
ソースパス
/thrid_party/v8/builtins/array-sort.tq
コールスタック
1386 ArrayPrototypeSort
1403 ArrayTimSort
1369 ArrayTimSortImpl
1260 ComputeMinRunLength // 计算 minRunLength
// while循环
1262 CountAndMakeRun // 计算当前 run 的长度
1267 BinaryInsertionSort // 用插入排序补足 run 长度
1274 MergeCollapse // 放入 pendingRuns 并根据需要进行调整
// 循环结束
1281 MergeForceCollapse // 合并 pendingRuns 中所有 run
コアソース
いくつかのTQ言語は同じではありませんが、活字体根拠がある場合、それを読んだことは問題ではないはずですが。
主なソースは、次の3つの機能を解釈します:
// 在while循环之前调用,每次排序只调用一次,用来计算 minRunLength
macro ComputeMinRunLength(nArg: Smi): Smi {
let n: Smi = nArg;
let r: Smi = 0;
assert(n >= 0);
// 不断除以2,得到结果在 32~64 之间
while (n >= 64) {
r = r | (n & 1);
n = n >> 1;
}
const minRunLength: Smi = n + r;
assert(nArg < 64 || (32 <= minRunLength && minRunLength <= 64));
return minRunLength;
}
// 计算第一个 run 的长度
macro CountAndMakeRun(implicit context: Context, sortState: SortState)(
lowArg: Smi, high: Smi): Smi {
assert(lowArg < high);
// 这里保存的才是我们传入的数组数据
const workArray = sortState.workArray;
const low: Smi = lowArg + 1;
if (low == high) return 1;
let runLength: Smi = 2;
const elementLow = UnsafeCast<JSAny>(workArray.objects[low]);
const elementLowPred = UnsafeCast<JSAny>(workArray.objects[low - 1]);
// 调用比对函数来比对数据
let order = sortState.Compare(elementLow, elementLowPred);
const isDescending: bool = order < 0 ? true : false;
let previousElement: JSAny = elementLow;
// 遍历子数组并计算 run 的长度
for (let idx: Smi = low + 1; idx < high; ++idx) {
const currentElement = UnsafeCast<JSAny>(workArray.objects[idx]);
order = sortState.Compare(currentElement, previousElement);
if (isDescending) {
if (order >= 0) break;
} else {
if (order < 0) break;
}
previousElement = currentElement;
++runLength;
}
if (isDescending) {
ReverseRange(workArray, lowArg, lowArg + runLength);
}
return runLength;
}
// 调整 pendingRuns ,使栈长度大于3时,所有 run 都满足 run[n]>run[n+1]+run[n+2] 且 run[n+1]>run2[n+2]
transitioning macro MergeCollapse(context: Context, sortState: SortState) {
const pendingRuns: FixedArray = sortState.pendingRuns;
while (GetPendingRunsSize(sortState) > 1) {
let n: Smi = GetPendingRunsSize(sortState) - 2;
if (!RunInvariantEstablished(pendingRuns, n + 1) ||
!RunInvariantEstablished(pendingRuns, n)) {
if (GetPendingRunLength(pendingRuns, n - 1) <
GetPendingRunLength(pendingRuns, n + 1)) {
--n;
}
MergeAt(n); // 将第 n 个 run 和第 n+1 个 run 进行合并
} else if (
GetPendingRunLength(pendingRuns, n) <=
GetPendingRunLength(pendingRuns, n + 1)) {
MergeAt(n); // 将第 n 个 run 和第 n+1 个 run 进行合并
} else {
break;
}
}
}
概要
:あなたは、アルゴリズムの問題、あなたは微笑ん可能と彼女/彼に尋ねた場合インタビュアーが尋ねる次の就職の面接のフロントエンド
配列関数は、一種のあなたが使用しているもののアルゴリズムを知っていますか?調べるためではないTimSort?
もちろん、インタビュアーがゆえ恥ずかしとの非難につながる可能性のオファーを取得しない場合は〜
参考:
これは、完全な能力とグローバルビジョンエンジニアと高度な武器になるための技術的な専門家の数が推奨する- 「グレートJavaScriptのエンジニアは」、Jingdongは、详细にヒットする準備ができ淘宝網の主要プラットフォーム-
下のリンクをクリックして、すぐにそれを進めてあなたに属している道に乗り出します!