この記事では、基本的なアルゴリズムと高度なデータソートアルゴリズムを記述します。これらのアルゴリズムは、データを格納するための唯一の配列に依存しています。
アレイテストプラットフォーム
まず、私たちはクラステストプラットフォームの配列を作成します
function CArray(numElements) {
this.dataStore = [];
this.numElements = numElements;
this.toString = toString;
this.clear = clear;
this.setData = setData;
this.swap = swap;
}
function setData() {
for (var i = 0; i < this.numElements; ++i) {
this.dataStore[i] = Math.floor(Math.random() * (this.numElements + 1));
}
}
function clear() {
for (var i = 0; i < this.numElements; ++i) {
this.dataStore[i] = 0;
}
}
function toString() {
var restr = "";
for (var i = 0; i < this.numElements; ++i) {
restr += this.dataStore[i] + " ";
if (i > 0 && i % 10 == 0) {
restr += "\n";
}
}
return restr;
}
function swap(arr, index1, index2) {
var temp = arr[index1];
arr[index1] = arr[index2];
arr[index2] = temp;
}
テストプラットフォームのカテゴリを使用します
var numElements = 100;
var myNums = new CArray(numElements);
myNums.setData();
console.log(myNums.toString());
基本的なソートアルゴリズム
これらのアルゴリズムは、実際の生活の中でデータの並べ替え、人間の非常に現実的なシミュレーションです。
バブルソート
これは、最も遅いソートアルゴリズムの一つが、また、ソートアルゴリズムを実装するのが最も簡単なの一つです。
これは、気泡が、アレイの一端から他端に浮くようなソートソートアルゴリズム、同一のデータ値を使用するからであるバブルソートと呼ばれています。小さな値は、アレイの左側に浮遊する一方仮定は、昇順に番号のセット、右フロートアレイに大きな値です。値は、それらが交換可能である右側に左側の値よりも大きい場合、アルゴリズムは、アレイ、隣接するデータと比較して数回移動されるため、この現象の理由があります。
バブルソートコード
function bubbleSort() {
var numElements = this.dataStore.length;
for (var outer = numElements; outer >= 2; --outer) {
for (var inner = 0; inner < outer - 1; ++inner) {
if (this.dataStore[inner] > this.dataStore[inner + 1]) {
this.swap(this.dataStore, inner, inner + 1);
}
}
}
}
ソート処理(手動入力テストデータ)
外层循环限定了未排序的范围(从numElements到2),内层循环从左侧的数据开始逐步比较交换,使得未排序范围中最大的数移动到了最右侧,外层排序范围不断缩小,直到还剩两个未排序元素时再比较交换便完成了排序
選択ソート
选择排序从数组的开头开始,将第一个元素和其他元素进行比较。检查完所有元素后,最小的元素会被放到数组的第一个位置,然后算法会从第二个位置继续。这个过程一直进行,当进行到数组的倒数第二个位置时,所有数据便完成了排序。
function selectionSort() {
var min;
for (var outer = 0; outer <= this.dataStore.length - 2; ++outer) {
min = outer;
for (var inner = outer + 1; inner <= this.dataStore.length - 1; ++inner) {
if (this.dataStore[inner] < this.dataStore[min]) {
min = inner;
}
}
swap(this.dataStore, outer, min);
}
}
注文プロセス
挿入ソート
插入排序有两个循环。外循环将数组元素挨个移动,而内循环则对外循环中选中的元素进行比较。如果外循环中选中的元素比内循环中选中的元素小,那么数组元素会向右移动,为内循环中的这个元素腾出位置。
function insertionSort() {
var temp, inner;
for (var outer = 1; outer <= this.dataStore.length - 1; ++outer) {
temp = this.dataStore[outer];
inner = outer;
while (inner > 0 && (this.dataStore[inner - 1] >= temp)) {
this.dataStore[inner] = this.dataStore[inner - 1];
--inner;
}
this.dataStore[inner] = temp;
}
}
タイミングより基本的なソートアルゴリズム
10000乱数検定
bubbleSort();// 100ms左右
selectionSort();// 50ms左右
insertionSort();// 27ms左右
選択ソートとバブルソートより並べ替え速い挿入は、挿入ソートは、3つのアルゴリズムの中で最速です。
高度なソートアルゴリズム
シェルソート
希尔排序在插入排序的基础上做了很大的改善。它会首先比较距离较远的元素,而非相邻的元素。这样可以使离正确位置很远的元素更快地回到合适的位置。当开始用这个算法遍历数据集时,所有元素之间的距离会不断减小,直到处理到数据集的末尾,这时算法比较的就是相邻元素了。希尔排序的工作原理是,通过定义一个间隔序列来表示排序过程中进行比较的元素之间有多远的间隔。我们可以动态定义间隔序列,不过大部分场景算法要用到的间隔序列可以提前定义好。
701,301,132,57,23,10,4,1:として発表された論文で定義された行進Ciuraスペーサー配列。ここでは、このアルゴリズムは、データの小さなセットで実行されるかを見てみましょう。
function shellsort() {
var temp;
for (var g = 0; g < this.gaps.length; ++g) {
for (var i = this.gaps[g]; i < this.dataStore.length; ++i) {
temp = this.dataStore[i];
for (var j = i; j >= this.gaps[g] && this.dataStore[j-this.gaps[g]] > temp; j -= this.gaps[g]) {
this.dataStore[j] = this.dataStore[j - this.gaps[g]];
}
this.dataStore[j] = temp;
}
}
}
私たちは、CARRAYクラスのスペーサー配列の定義を増やす必要があります。
this.gaps = [5,3,1];
ダイナミックなスペーサー配列の計算
Sedgewickアルゴリズムは、次のコードによって間隔の初期値を決定します。
var N = this.dataStore.length;
var h = 1;
while (h < N/3) {
h = 3 * h + 1;
}
良い値を決定するために間隔をシェルソート、この機能は、以前のように定義することができます()関数は、同じ実行し、唯一の違いはある、その裏に新しい価値の間隔を計算します外側のループ前の最後の文に:
h = (h-1)/3;
動的な計算間隔順序付けられたシーケンスヒル
function shellsort1() {
var N = this.dataStore.length;
var h = 1;
while (h < N/3) {
h = 3 * h + 1;
}
while (h >= 1) {
for (var i = h; i < N; i ++) {
for (var j = i; j >= h && this.dataStore[j] < this.dataStore[j-h]; j -= h) {
this.swap(this.dataStore, j, j - h);
}
}
h = (h-1)/3;
}
}
万回のランダムテストを注文する場合:
myNums.shellsort(); // 20ms左右
myNums.shellsort1(); // 8ms左右
マージソート
归并排序把一系列排好序的子序列合并成一个大的完整有序序列。我们需要两个排好序的子数组,然后通过比较数据大小,从最小的数据开始插入,最后合并得到第三个数组。然而,在实际情况中,归并排序还有一些问题,我们需要更大的空间来合并存储两个子数组。
ボトムアップ自己のソートマージ
ソートの再帰的なアルゴリズムを使用して実装されますマージ、一般的に。再帰の深さが深すぎるのでしかし、JavaScriptでこのように、現実的ではありません。そこで、我々はこのアルゴリズムを実装するために非再帰的な方法を使用して、この戦略は、ボトムアップのマージソートと呼ばれています。
アルゴリズム最初のデータセットは、アレイの一方のみの要素の組に分解されます。そして、ゆっくりとそれらを一緒にマージされます左と右のサブアレイのセットを作成することにより、合併の各部分は、ソートされたデータ、最後に残った完璧なこの配列をソートされるまで、すべてのデータを保存します。
アルゴリズムコード
function mergeSort() {
var arr = this.dataStore;
if (arr.length < 2) {
return;
}
var step = 1;
var left, right;
while (step < arr.length) {
left = 0;
right = step;
while (right + step <= arr.length) {
this.mergeArrays(arr, left, left+step, right, right+step);
left = right + step;
right = left + step;
}
if (right < arr.length) {
this.mergeArrays(arr, left, left+step, right, arr.length);
}
step *= 2;
}
}
function mergeArrays(arr, startLeft, stopLeft, startRight, stopRight) {
var rightArr = new Array(stopRight - startRight + 1);
var leftArr = new Array(stopLeft - startLeft + 1);
k = startRight;
for (var i = 0; i < (rightArr.length-1); ++i) {
rightArr[i] = arr[k];
++k;
}
k = startLeft;
for (var i = 0; i < (leftArr.length-1); ++i) {
leftArr[i] = arr[k];
++k;
}
rightArr[rightArr.length - 1] = Infinity;
leftArr[leftArr.length - 1] = Infinity;
var m = 0;
var n = 0;
for (var k = startLeft; k < stopRight; ++k) {
if (leftArr[m] <= rightArr[n]) {
arr[k] = leftArr[m];
m++;
} else {
arr[k] = rightArr[n];
n++;
}
}
}
クイックソート
快速排序是处理大数据集最快的排序算法之一。它是一种分而治之的算法,通过递归的方法将数据依次分解为包含较小元素和较大元素的不同子序列。该算法不断重复这个步骤直到所有数据都是有序的。
这个算法首先要在列表中选择一个元素作为基准值(pivot)。数据排序围绕基准值进行,将列表中小于基准值的元素移到数组的底部,将大于基准值的元素移到数组的顶部。
擬似コードアルゴリズム
- 基準要素を選択、リスト二つのサブシーケンスに分割されます
- 基準の基準値よりリストを並べ替え、基準値の前に基準値以上のすべての要素を、背面上のすべての要素の価値
- 配列の配列は、それぞれ小さく、大きな要素要素は、ステップ1と2つのを繰り返し
、次の手順を。
function qSort(list) {
var list;
if (list.length == 0) {
return [];
}
var lesser = [];
var greater = [];
var pivot = list[0];
for (var i = 1; i < list.length; i ++) {
if (list[i] < pivot) {
lesser.push(list[i]);
} else {
greater.push(list[i]);
}
}
return this.qSort(lesser).concat(pivot, this.qSort(greater));
}
qsort関数では、出力は、関数が戻る前にプロセスを並べ替え
console.log(lesser.concat(pivot, greater).toString());
テストをソート10000の乱数
qSort(); // 17ms左右
クイックソートアルゴリズムは、大規模なデータセットのために非常に適している。しかし、小規模なデータセットを扱う際のパフォーマンスが低下します。
(添付)テスト・プラットフォーム・コード
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<script>
function CArray(numElements) {
// this.dataStore = [72, 54, 58, 30, 31, 78, 2, 77, 82, 72];
this.dataStore = [];
// this.dataStore = [44, 75, 23, 43, 55, 12, 64, 77 ,33];
this.numElements = numElements;
this.toString = toString;
this.clear = clear;
this.setData = setData;
this.swap = swap;
this.bubbleSort = bubbleSort;
this.selectionSort = selectionSort;
this.insertionSort = insertionSort;
this.shellsort = shellsort;
this.shellsort1 = shellsort1;
this.mergeSort = mergeSort;
this.mergeArrays = mergeArrays;
this.qSort = qSort;
this.gaps = [5, 3, 1];
}
function setData() {
for (var i = 0; i < this.numElements; ++i) {
this.dataStore[i] = Math.floor(Math.random() * (this.numElements + 1));
}
}
function clear() {
for (var i = 0; i < this.numElements; ++i) {
this.dataStore[i] = 0;
}
}
function toString() {
var restr = "";
for (var i = 0; i < this.numElements; ++i) {
restr += this.dataStore[i] + " ";
if (i > 0 && i % 10 == 0) {
restr += "\n";
}
}
return restr;
}
function swap(arr, index1, index2) {
var temp = arr[index1];
arr[index1] = arr[index2];
arr[index2] = temp;
}
function selectionSort() {
var min;
for (var outer = 0; outer <= this.dataStore.length - 2; ++outer) {
min = outer;
for (var inner = outer + 1; inner <= this.dataStore.length - 1; ++inner) {
if (this.dataStore[inner] < this.dataStore[min]) {
min = inner;
}
}
swap(this.dataStore, outer, min);
}
}
function bubbleSort() {
var numElements = this.dataStore.length;
for (var outer = numElements; outer >= 2; --outer) {
for (var inner = 0; inner < outer - 1; ++inner) {
if (this.dataStore[inner] > this.dataStore[inner + 1]) {
this.swap(this.dataStore, inner, inner + 1);
}
}
}
}
function insertionSort() {
var temp, inner;
for (var outer = 1; outer <= this.dataStore.length - 1; ++outer) {
temp = this.dataStore[outer];
inner = outer;
while (inner > 0 && (this.dataStore[inner - 1] >= temp)) {
this.dataStore[inner] = this.dataStore[inner - 1];
--inner;
}
this.dataStore[inner] = temp;
}
}
function shellsort() {
var temp;
for (var g = 0; g < this.gaps.length; ++g) {
for (var i = this.gaps[g]; i < this.dataStore.length; ++i) {
temp = this.dataStore[i];
for (var j = i; j >= this.gaps[g] && this.dataStore[j-this.gaps[g]] > temp; j -= this.gaps[g]) {
this.dataStore[j] = this.dataStore[j - this.gaps[g]];
}
this.dataStore[j] = temp;
}
}
}
function shellsort1() {
var N = this.dataStore.length;
var h = 1;
while (h < N/3) {
h = 3 * h + 1;
}
while (h >= 1) {
for (var i = h; i < N; i ++) {
for (var j = i; j >= h && this.dataStore[j] < this.dataStore[j-h]; j -= h) {
this.swap(this.dataStore, j, j - h);
}
}
h = (h-1)/3;
}
}
function mergeSort() {
var arr = this.dataStore;
if (arr.length < 2) {
return;
}
var step = 1;
var left, right;
while (step < arr.length) {
left = 0;
right = step;
while (right + step <= arr.length) {
this.mergeArrays(arr, left, left+step, right, right+step);
left = right + step;
right = left + step;
}
if (right < arr.length) {
this.mergeArrays(arr, left, left+step, right, arr.length);
}
step *= 2;
}
}
function mergeArrays(arr, startLeft, stopLeft, startRight, stopRight) {
var rightArr = new Array(stopRight - startRight + 1);
var leftArr = new Array(stopLeft - startLeft + 1);
k = startRight;
for (var i = 0; i < (rightArr.length-1); ++i) {
rightArr[i] = arr[k];
++k;
}
k = startLeft;
for (var i = 0; i < (leftArr.length-1); ++i) {
leftArr[i] = arr[k];
++k;
}
rightArr[rightArr.length - 1] = Infinity;
leftArr[leftArr.length - 1] = Infinity;
var m = 0;
var n = 0;
for (var k = startLeft; k < stopRight; ++k) {
if (leftArr[m] <= rightArr[n]) {
arr[k] = leftArr[m];
m++;
} else {
arr[k] = rightArr[n];
n++;
}
}
}
function qSort(list) {
var list;
if (list.length == 0) {
return [];
}
var lesser = [];
var greater = [];
var pivot = list[0];
for (var i = 1; i < list.length; i ++) {
if (list[i] < pivot) {
lesser.push(list[i]);
} else {
greater.push(list[i]);
}
}
return this.qSort(lesser).concat(pivot, this.qSort(greater));
}
var numElements = 200000;
var myNums = new CArray(numElements);
myNums.setData();
// console.log(myNums.toString());
var startTime = new Date().getTime();
// myNums.insertionSort();// 27ms左右
// myNums.bubbleSort();// 100ms左右
// myNums.selectionSort();// 50ms左右
// myNums.shellsort(); // 20ms左右
// myNums.shellsort1(); // 8ms左右
// myNums.mergeSort(); // 9ms左右
myNums.dataStore = myNums.qSort(myNums.dataStore); // 17ms左右
var endTime = new Date().getTime();
console.log('耗时: ' + (endTime - startTime) + '毫秒');
// console.log(myNums.toString());
</script>
</body>
</html>
参照
- 「で説明したJavaScriptのデータ構造とアルゴリズム」