「Big Front-end Private Kitchen」のWeChat公式アカウントをフォローし、パスワード[面接ガイド]を入力すると、フロントエンド面接の質問107ページを無料で受け取ることができます。
配列のソート
ソートは、順序付けされていない配列を順序付けられた配列にアルゴリズム的に処理するプロセスです。今日は、一般的に使用される 2 つの並べ替えアルゴリズム、バブル ソートと選択ソートを紹介します。
バブルソート
基本的な考え方は次のとおりです。
配列を繰り返し走査し、隣接する要素を比較します。前の要素が次の要素より大きい場合は、それらを交換します。最初のパスの後、最大の要素が配列の最後の位置に「フロート」されます。2 番目のパスの後、最後に、 2 番目に大きい要素は最後から 2 番目の位置に「フローティング」され、交換する必要のある要素がなくなるまでこのプロセスが繰り返されます。そして最後に、配列全体がソートされます。
1. まず不規則な配列を準備しましょう
var arr = [3, 1, 5, 6, 4, 9, 7, 2, 8]
次に、コードを使用して配列を並べ替えます
2. 今はループすることを心配しないで、配列の内容を見て、その位置を変更してみましょう。
// 假定我现在要让数组中的第 0 项和第 1 项换个位置
// 需要借助第三个变量
var tmp = arr[0]
arr[0] = arr[1]
arr[1] = tmp
2 つの場所でデータを交換する方法を学習したら、次の作業を続けることができます。
3. 初めて配列を走査し、最大のものを最後に置きます。
for (var i = 0; i < arr.length; i++) {
// 判断,如果数组中的当前一个比后一个大,那么两个交换一下位置
if (arr[i] > arr[i + 1]) {
var tmp = arr[i]
arr[i] = arr[i + 1]
arr[i + 1] = tmp
}
}
// 遍历完毕以后,数组就会变成 [3, 1, 5, 6, 4, 7, 2, 8, 9]
1 回目以降は、配列の最後のものが最大の数値となり、上記のコードを複数回実行します。配列内の項目の数だけ実行します
4. 配列の長さに応じた走査回数
for (var j = 0; j < arr.length; j++) {
for (var i = 0; i < arr.length; i++) {
// 判断,如果数组中的当前一个比后一个大,那么两个交换一下位置
if (arr[i] > arr[i + 1]) {
var tmp = arr[i]
arr[i] = arr[i + 1]
arr[i + 1] = tmp
}
}
}
// 结束以后,数组就排序好了
5. いくつかの最適化を行う
長さ 9 の配列をバブルソートするプロセスで、8 回目のソートの後、配列の最後の 8 要素が順番にソートされたと想像してください。このとき、配列の最後にある最小の要素が先頭に浮いている必要があります。したがって、最小の要素はすでに正しい位置にあり、位置の交換は発生しないため、9 番目のソートされたトラバースは無意味です。
したがって、この場合、9 番目のソート トラバーサルを省略して、アルゴリズムを直接終了できます。これは最適化として使用でき、特定のソート後、配列の末尾がすでにソートされている場合は、配列全体の走査を続行せずにソートを直接終了できます。
for (var j = 0; j < arr.length - 1; j++) {
for (var i = 0; i < arr.length; i++) {
// 判断,如果数组中的当前一个比后一个大,那么两个交换一下位置
if (arr[i] > arr[i + 1]) {
var tmp = arr[i]
arr[i] = arr[i + 1]
arr[i + 1] = tmp
}
}
}
最初の並べ替えパスの後、配列の最大の要素はすでに最後にあります。2 番目の並べ替えパスでは、位置の交換が発生しないため、配列の最後の 2 つの要素 (最大の要素と 2 番目に大きい要素) を比較する必要はありません。
ソートの 3 回目のパスでは、配列の最後の 3 つの要素 (最大の要素から 3 番目に大きい要素まで) を比較する必要はありません。最大の要素から 3 番目に大きな要素までの位置はすでに正確であり、再度変更されることはないためです。類推すると、n 回目の並べ替えパスでは、配列の最初の n-1 要素を比較するだけで済みます。配列の最後の n-1 個の要素の位置はすでに正しいため、それ以上の比較は必要ありません。
for (var j = 0; j < arr.length - 1; j++) {
for (var i = 0; i < arr.length - 1 - j; i++) {
// 判断,如果数组中的当前一个比后一个大,那么两个交换一下位置
if (arr[i] > arr[i + 1]) {
var tmp = arr[i]
arr[i] = arr[i + 1]
arr[i + 1] = tmp
}
}
}
6. この時点でバブルソートは完了です
選択ソートは
、まず配列内の 0 番目の数値が最小の数値のインデックスであると想定し、次に配列を走査します。私の数値より小さい数値がある限り、以前に記録されたインデックスを置き換えます。配列の走査が完了したら、最小のインデックスが見つかります。次に、最小のインデックスを 0 番目の位置に変更し、2 回目の走査を実行します。1 番目が最小の数値のインデックスであると仮定します。配列を 1 回走査した後、小さい数値のインデックスを見つけます。私のものよりも変更し、走査が完了した後にそれを変更します。位置など、配列をソートすることもできます。
1. アレイを準備する
var arr = [3, 1, 5, 6, 4, 9, 7, 2, 8]
2. 配列内の 0 番目の数値が最小の数値のインデックスであると仮定します。
var minIndex = 0
3. 配列を走査し、その数値が私のものより小さいかどうかを判断し、元のレコードのインデックスを置き換えます。
var minIndex = 0
for (var i = 0; i < arr.length; i++) {
if (arr[i] < arr[minIndex]) {
minIndex = i
}
}
// 遍历结束后找到最小的索引
// 让第 minIndex 个和第 0 个交换
var tmp = arr[minIndex]
arr[minIndex] = arr[0]
arr[0] = tmp
4. 配列の長さに応じて上記のコードを繰り返します。
for (var j = 0; j < arr.length; j++) {
// 因为第一遍的时候假定第 0 个,第二遍的时候假定第 1 个
// 所以我们要假定第 j 个就行
var minIndex = j
// 因为之前已经把最小的放在最前面了,后面的循环就不需要判断前面的了
// 直接从 j + 1 开始
for (var i = j + 1; i < arr.length; i++) {
if (arr[i] < arr[minIndex]) {
minIndex = i
}
}
// 遍历结束后找到最小的索引
// 第一堂的时候是和第 0 个交换,第二趟的时候是和第 1 个交换
// 我们直接和第 j 个交换就行
var tmp = arr[minIndex]
arr[minIndex] = arr[j]
arr[j] = tmp
}
5. いくつかの最適化.
以前と同様に、最後から 2 番目のソートが完了するとソートされます。
for (var j = 0; j < arr.length - 1; j++) {
var minIndex = j
for (var i = j + 1; i < arr.length; i++) {
if (arr[i] < arr[minIndex]) {
minIndex = i
}
}
var tmp = arr[minIndex]
arr[minIndex] = arr[j]
arr[j] = tmp
}
変数を交換する前に判断することができます。トラバース後に取得したインデックスが現在のインデックスと一致する場合、現在のインデックスが現時点で最小であることが証明されるため、交換する必要はありません。最小のインデックスが現在のインデックスと異なると判断する場合のみ
for (var j = 0; j < arr.length - 1; j++) {
var minIndex = j
for (var i = j + 1; i < arr.length; i++) {
if (arr[i] < arr[minIndex]) {
minIndex = i
}
}
if (minIndex !== j) {
var tmp = arr[minIndex]
arr[minIndex] = arr[j]
arr[j] = tmp
}
}
この時点で選択範囲の並べ替えは完了です