1つは、ソートアルゴリズムです。
多くのソートアルゴリズムがありますが、最も代表的なものについてのみ説明します:バブルソート、ヒルソート、マージソート、クイックソート。
1.バブルソート(バブルソート)
実現のアイデア:
- 隣接する要素を比較し、最初の要素が2番目の要素より大きい場合は、2つを交換します。
- 隣接する各要素について、最初の最初のペアから最後の最後のペアまで同じ比較を行います。比較後、最大の要素が配列の最後のビットに配置されます(バブル)。
- 比較が完了するたびに、次の比較のための配列の長さが1つ短くなります。1回のパスで配列を比較した後、後ろの最後の要素が前の要素の最大値であるため、次の比較ラウンドは無意味です。
- 比較する数値のペアがなくなるまで、毎回、要素の数を減らして上記の手順を繰り返します。
成し遂げる:
function bubbleSort(arr){
var len = arr.length;
for(let i=0; i<len; i++){
for(let j=0; j<len-1-i; j++){
if(arr[j]>arr[j+1]){
var temp = arr[j+1];
arr[j+1] = arr[j];
arr[j] = temp;
}
}
return arr;
}
改善1:各パスの最後のビット交換の位置を記録するために使用されるフラグ変数posを設定します。pos位置の後のレコードはすべて所定の位置で交換されるため、次のパスがソートされるときにpos位置までスキャンするだけで十分です。
function bubbleSort(arr) {
console.time("改进后冒泡排序耗时");
while(i>0) {
var pos = 0;//每趟开始时,无记录交换
for(let j=0; j<i; j++){
if(arr[j]>arr[j+1]) {
pos=j;//记录交换的位置
var temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
i=pos;//为下一趟排序准备
}
console.timeEnd('改进后冒泡排序耗时');
return arr;
}
改善2:従来のバブルソートでは、各ソート操作で最大値または最小値を1つしか見つけることができません。各ソートで順方向および逆方向のダブルバブリングの方法を使用して、2つの最終値(最大値と最小値)を取得することを検討します。ソートパスは一般的にほとんど削減されます。
function bublleSort(arr) {
var low = 0;
var high = arr.length-1;//设置变量的初始值
var temp, j;
console.time('2.改进后冒泡排序耗时');
while(low<high) {
for(j=low; j<high; j++) {
if (arr[j]> arr[j+1]) {
tmp = arr[j];
arr[j]=arr[j+1];
arr[j+1]=tmp;
}
--high; //修改high值, 前移⼀位
}
for (j=high; j>low; --j) {
//反向冒泡,找到最⼩者
if (arr[j]<arr[j-1]) {
tmp = arr[j];
arr[j]=arr[j-1];
arr[j-1]=tmp;
}
++low; //修改low值,后移⼀位
}
}
console.timeEnd('2.改进后冒泡排序耗时');
return arr3;
}
2.ヒルソート(シェルソート)
1959年に提案されたシェル;最初の画期的なO(n ^ 2)ソートアルゴリズム;単純な挿入ソートの改良版です;挿入ソートとの違いは、最初に離れている要素を比較することです。ヒルソートとも呼ばれます増分ソートの削減。
アルゴリズムの紹介:ヒルソートのコアは、間隔シーケンスの設定です。インターバルシーケンスは事前に設定することも、インターバルシーケンスを動的に定義することもできます。
実現のアイデア:
最初に、直接挿入ソートのために、ソートされるレコードのシーケンス全体をサブシーケンスに分割します。具体的なアルゴリズムの説明は次のとおりです。
- インクリメンタルシーケンスt1、t2、...、tkを選択します。ここでti> tj、tk = 1;
- インクリメンタルシーケンスの数kに従ってシーケンスをk回ソートします。
- ソートごとに、対応する増分tiに従って、ソートされるシーケンスが次数mのサブシーケンスに分割され、各サブテーブルが直接挿入されてソートされます。増分係数のみが1の場合、シーケンス全体がテーブルとして扱われ、表現の程度はシーケンス全体の長さです。
コード:
function shellSort(arr) {
var len = arr.length, temp, gap = 1;
console.time('希尔排序耗时:');
while(gap < len/5) {
//动态定义间隔序列
gap =gap*5+1;
}
for (gap; gap > 0; gap = Math.floor(gap/5)) {
for (var i = gap; i < len; i++) {
temp = arr[i];
for (var j = i-gap; j >= 0 && arr[j] > temp; j-=gap) {
arr[j+gap] = arr[j];
}
arr[j+gap] = temp;
}
}
console.timeEnd('希尔排序耗时:');
return arr;
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(shellSort(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
3.マージソート(マージソート)
選択ソートと同様に、マージソートのパフォーマンスは入力データの影響を受けませんが、常にO(n log n)の時間計算量であるため、選択ソートよりもはるかに優れたパフォーマンスを発揮します。価格は、追加のメモリスペースの必要性です。
マージソートは、マージ操作に基づいて構築された効果的なソートアルゴリズムです。このアルゴリズムは、分割統治法の非常に典型的なアプリケーションです。マージソートは安定したソート方法です。既存の順序付けられたサブシーケンスを組み合わせて、完全に順序付けられたシーケンスを取得します。つまり、最初に各サブシーケンスを順番に作成し、次にサブシーケンスを順番に作成します。2つの順序付きリストが1つの順序付きリストにマージされる場合、それは双方向マージと呼ばれます。
実現のアイデア:
- 次数nの入力シーケンスを次数n / 2の2つのサブシーケンスに分割します。
- これらの2つのサブシーケンスにはマージソートを使用します。
- 2つのソートされたサブシーケンスを組み合わせて、最終的なソートされたシーケンスにします。
コード:
function mergeSort(arr) {
//采⽤⾃上⽽下的递归⽅法
var len = arr.length;
if(len < 2) {
return arr; }
var middle = Math.floor(len / 2), left = arr.slice(0, middle), right = arr.slice(middle);
return merge(mergeSort(left), mergeSort(right));
}
function merge(left, right) {
var result = [];
console.time('归并排序耗时');
while (left.length && right.length) {
if (left[0] <= right[0]) {
result.push(left.shift());
} else {
result.push(right.shift());
}
}
while (left.length) result.push(left.shift());
while (right.length) result.push(right.shift());
console.timeEnd('归并排序耗时');
return result;
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(mergeSort(arr));
4.クイックソート(クイックソート)
クイックソートの基本的な考え方:ソートパスを使用して、ソートするレコードを2つの別々の部分に分離します。レコードの一方の部分のキーワードは、もう一方の部分のキーワードよりも小さく、引き続き2つを実行できます。レコードの一部を個別に並べ替えて、シーケンス全体の順序を実現します。
実現のアイデア:
- 配列から中央のアイテムをピボットとして選択します。
- 2つのポインターを作成します。左側のポインターは配列の最初の項目を指し、右側のポインターは配列の最後の項目を指します。ピボットサイズよりも小さい要素が見つかるまで左ポインターを移動し、次にピボットサイズよりも小さい要素が見つかるまで右ポインターを移動します。次に、それらを交換し、左のポインターが右のポインターを超えるまでプロセスを繰り返します。このプロセスでは、ピボットサイズの値はすべてピボットの前に配置され、ピボットサイズの値はすべてピボットの後に配置されます。このステップは、分割操作と呼ばれます。
- 次に、アルゴリズムは、配列が完全に並べ替えられるまで、分割された小さな配列(小さなピボット値で構成されるサブ配列と大きなピボット値で構成されるサブ配列)に対して前の2つの手順を繰り返します。
// 快速排序
const quickSort = (function() {
// 默认状态下的⽐较函数
function compare(a, b) {
if (a === b) {
return 0 }
return a < b ? -1 : 1
}
function swap(array, a, b) {
[array[a], array[b]] = [array[b], array[a]]
}
// 分治函数
function partition(array, left, right) {
// ⽤index取中间值⽽⾮splice
const pivot = array[Math.floor((right + left) / 2)]
let i = left
let j = right
while (i <= j) {
while (compare(array[i], pivot) === -1) {
i++
}
while (compare(array[j], pivot) === 1) {
j--
}
if (i <= j) {
swap(array, i, j)
i++
j--
}
}
return i
}
// 快排函数
function quick(array, left, right) {
let index
if (array.length > 1) {
index = partition(array, left, right)
if (left < index - 1) {
quick(array, left, index - 1)
}
if (index < right) {
quick(array, index, right)
}
}
return array
}
return function quickSort(array) {
return quick(array, 0, array.length - 1) }