javascript 排序(Sorting)算法與說明

排序的介紹

排序是算法最常用的一種運算之一,數據記錄到數據庫,都需要經過排序輸出到客戶端上。不然亂輸出不規整的數據,是難以閱讀的。

本文章介紹幾種最常用見的排序方法:冒泡排序,選擇排序,插入排序,歸併排序和快速排序。

冒泡排序

冒泡排序是從運行時間的角度上來看,最差的一個。因爲冒泡排序回比較任何兩週相鄰的項,如果第一個比第二個大,則交換它們。


選擇排序

選擇排序的思路是找到數據結構中的最小值並將其放置在第一位,接着找到第二小的值放在第二位,以此類推。


插入排序

插入排序每次排一個數組項,以此方式構建最後的排序數組。假定第一項已經排序了,接着,它和第二項進行比較,第二項是應該待在原位還是插到第一項之前呢?這樣,頭兩就已正常排序,接着和第三項比較(它是該插入到第一、第二還是第三位置呢?)以此類推。


歸併排序

歸併排序是第一個可以被實際使用的排序算法。而javascript中的array類的sort在firefox瀏覽器上 就是用這種排序的。歸併排序是一種分治算法。其思想是將原始數組切分成較小的數組,知道每個小數組只有一個位置,接着將小數組歸併成較大的數組,直到最後只有一個排序完畢的大數組。


快速排序

快速排序也許是最常用的排序算法。和歸併排序一樣,快速排序也使用分治的方法,將原始數組分位較小的數組(但它沒有像歸併排序那樣將它們分割開)。這個重點說下過程。

  1. 首先,從數組中選擇中間一項作爲主元。
  2. 創建兩個指針,左邊一個指向數組第一個項,右邊一個指向數組最後一個項。移動左指針直到我們找到一個比主元大的元素,接着,移動右指針直到找到一個比主元小的元素,然後交換它們,重複這個過程,直到左指針超過了右指針。這個過程將使得比主元小的值都排在主元之前,而比主元大的值都排在主元之後。這一步叫作劃分操作。
  3. 接着,算法對劃分後的小數組(較主元小的值組成的子數組,以及較主元大的值組成的子數組)重複之前的兩個步驟,直至數組已完全排序。


排序的算法實例

function createNonSortedArray(size){
    var array = new ArrayList();

    for (var i = size; i> 0; i--){
        array.insert(i);
    }

    return array;
}

function createRandomNonSortedArray(){
    var array = new ArrayList();

    array.insert(3);
    array.insert(5);
    array.insert(1);
    array.insert(6);
    array.insert(4);
    array.insert(7);
    array.insert(2);

    return array;
}

function printArray(array){
    console.log(array.toString());
}

function createNonSortedArrayAndPrint(size){
    var array = createNonSortedArray(size);
    printArray(array);

    return array;
}


var array = createNonSortedArrayAndPrint(5);
array.bubbleSort();//5,4,3,2,1

array = createNonSortedArrayAndPrint(5);
array.modifiedBubbleSort();//5,4,3,2,1

array = createNonSortedArrayAndPrint(5);
array.selectionSort();//5,4,3,2,1

array = createNonSortedArrayAndPrint(5);
array.insertionSort();//5,4,3,2,1

array = createNonSortedArrayAndPrint(8);
array.mergeSort();//8,7,6,5,4,3,2,1

array = createRandomNonSortedArray();
array.quickSort();//1,2,3,4,5,6,7

ES6排序完整實現代碼:

let ArrayList = (function() {
    class ArrayList {
        constructor() {
            this.array = [];
        }

        insert(item) {
            this.array.push(item);
        }

        swap(array, index1, index2) {
            var aux = this.array[index1];
            this.array[index1] = this.array[index2];
            this.array[index2] = aux;
        }

        toString() {
            return this.array.join();
        }

        array() {
            return this.array;
        }

        bubbleSort() {
            var length = this.array.length;

            for(var i = 0; i < length; i++) {
                console.log('--- ');
                for(var j = 0; j < length - 1; j++) {
                    console.log('compare ' + this.array[j] + ' with ' + this.array[j + 1]);
                    if(this.array[j] > this.array[j + 1]) {
                        console.log('swap ' + this.array[j] + ' with ' + this.array[j + 1]);
                        this.swap(this.array, j, j + 1);
                    }
                }
            }
        };

        modifiedBubbleSort() {
            var length = this.array.length;

            for(var i = 0; i < length; i++) {
                console.log('--- ');
                for(var j = 0; j < length - 1 - i; j++) {
                    console.log('compare ' + this.array[j] + ' with ' + this.array[j + 1]);
                    if(this.array[j] > this.array[j + 1]) {
                        console.log('swap ' + this.array[j] + ' with ' + this.array[j + 1]);
                        this.swap(j, j + 1);
                    }
                }
            }

        };

        selectionSort() {
            var length = this.array.length,
                indexMin;

            for(var i = 0; i < length - 1; i++) {
                indexMin = i;
                console.log('index ' + this.array[i]);
                for(var j = i; j < length; j++) {
                    if(this.array[indexMin] > this.array[j]) {
                        console.log('new index min ' + this.array[j]);
                        indexMin = j;
                    }
                }
                if(i !== indexMin) {
                    console.log('swap ' + this.array[i] + ' with ' + this.array[indexMin]);
                    this.swap(i, indexMin);
                }
            }
        };

        insertionSort() {
            var length = this.array.length,
                j, temp;
            for(var i = 1; i < this.length; i++) {
                j = i;
                temp = this.array[i];
                console.log('to be inserted ' + temp);
                while(j > 0 && this.array[j - 1] > temp) {
                    console.log('shift ' + this.array[j - 1]);
                    this.array[j] = this.array[j - 1];
                    j--;
                }
                console.log('insert ' + temp);
                this.array[j] = temp;
            }
        };

        insertionSort_(array) {
            var length = array.length,
                j, temp;
            for(var i = 1; i < length; i++) {
                j = i;
                temp = array[i];
                while(j > 0 && array[j - 1] > temp) {
                    array[j] = array[j - 1];
                    j--;
                }
                this.array[j] = temp;
            }
        };

        mergeSort() {
            this.array = this.mergeSortRec(this.array);
        };

        mergeSortRec(array) {

            var length = array.length;

            if(length === 1) {
                console.log(array);
                return array;
            }

            var mid = Math.floor(length / 2),
                left = array.slice(0, mid),
                right = array.slice(mid, length);

            return this.merge(this.mergeSortRec(left), this.mergeSortRec(right));
        };

        merge(left, right) {
            var result = [],
                il = 0,
                ir = 0;

            while(il < left.length && ir < right.length) {

                if(left[il] < right[ir]) {
                    result.push(left[il++]);
                } else {
                    result.push(right[ir++]);
                }
            }

            while(il < left.length) {
                result.push(left[il++]);
            }

            while(ir < right.length) {
                result.push(right[ir++]);
            }

            console.log(result);

            return result;
        };

        quickSort() {
            this.quick(this.array, 0, this.array.length - 1);
        };

        partition(array, left, right) {

            var pivot = array[Math.floor((right + left) / 2)],
                i = left,
                j = right;

            console.log('pivot is ' + pivot + '; left is ' + left + '; right is ' + right);

            while(i <= j) {
                while(array[i] < pivot) {
                    i++;
                    console.log('i = ' + i);
                }

                while(array[j] > pivot) {
                    j--;
                    console.log('j = ' + j);
                }

                if(i <= j) {
                    console.log('swap ' + array[i] + ' with ' + array[j]);
                    this.swap(array, i, j);
                    i++;
                    j--;
                }
            }

            return i;
        };

        quick(array, left, right) {

            var index;

            if(array.length > 1) {

                index = this.partition(array, left, right);

                if(left < index - 1) {
                    this.quick(array, left, index - 1);
                }

                if(index < right) {
                    this.quick(array, index, right);
                }
            }
            return array;
        };

        heapSort() {
            var heapSize = this.array.length;

            this.buildHeap(array);

            while(heapSize > 1) {
                heapSize--;
                console.log('swap (' + +array[0] + ',' + array[heapSize] + ')');
                this.swap(array, 0, heapSize);
                console.log('heapify ' + this.array.join());
                this.heapify(array, heapSize, 0);
            }
        };

        buildHeap(array) {
            console.log('building heap');
            var heapSize = array.length;
            for(var i = Math.floor(array.length / 2); i >= 0; i--) {
                this.heapify(array, heapSize, i);
            }
            console.log('heap created: ' + this.array.join());
        };

        heapify(array, heapSize, i) {
            var left = i * 2 + 1,
                right = i * 2 + 2,
                largest = i;

            if(left < heapSize && array[left] > array[largest]) {
                largest = left;
            }

            if(right < heapSize && array[right] > array[largest]) {
                largest = right;
            }

            console.log('Heapify Index = ' + i + ' and Heap Size = ' + heapSize);

            if(largest !== i) {
                console.log('swap index ' + i + ' with ' + largest + ' (' + +array[i] + ',' + array[largest] + ')');
                this.swap(array, i, largest);
                console.log('heapify ' + array.join());
                this.heapify(array, heapSize, largest);
            }
        };

        countingSort() {

            var i,
                maxValue = this.findMaxValue(),
                sortedIndex = 0,
                counts = new Array(maxValue + 1);

            for(i = 0; i < array.length; i++) {
                if(!counts[array[i]]) {
                    counts[array[i]] = 0;
                }
                counts[array[i]]++;
            }

            console.log('Frequencies: ' + counts.join());

            for(i = 0; i < counts.length; i++) {
                while(counts[i] > 0) {
                    array[sortedIndex++] = i;
                    counts[i]--;
                }
            }
        };

        bucketSort(bucketSize) {

            var i,
                minValue = this.findMinValue(),
                maxValue = this.findMaxValue(),
                BUCKET_SIZE = 5;

            console.log('minValue ' + minValue);
            console.log('maxValue ' + maxValue);

            bucketSize = bucketSize || BUCKET_SIZE;
            var bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1;
            var buckets = new Array(bucketCount);
            console.log('bucketSize = ' + bucketCount);
            for(i = 0; i < buckets.length; i++) {
                buckets[i] = [];
            }

            for(i = 0; i < this.array.length; i++) {
                buckets[Math.floor((this.array[i] - minValue) / bucketSize)].push(this.array[i]);
                console.log('pushing item ' + this.array[i] + ' to bucket index ' + Math.floor((this.array[i] - minValue) / bucketSize));
            }

            this.array = [];
            for(i = 0; i < buckets.length; i++) {
                this.insertionSort_(buckets[i]);

                console.log('bucket sorted ' + i + ': ' + buckets[i].join());

                for(var j = 0; j < buckets[i].length; j++) {
                    this.array.push(buckets[i][j]);
                }
            }
        };

        radixSort(radixBase) {

            var i,
                minValue = this.findMinValue(),
                maxValue = this.findMaxValue(),
                radixBase = radixBase || 10;

            // Perform counting sort for each significant digit), starting at 1
            var significantDigit = 1;
            while(((maxValue - minValue) / significantDigit) >= 1) {
                console.log('radix sort for digit ' + significantDigit);
                this.array = this.countingSortForRadix(this.array, radixBase, significantDigit, minValue);
                console.log(this.array.join());
                significantDigit *= radixBase;
            }
        };

        countingSortForRadix(array, radixBase, significantDigit, minValue) {
            var i, countsIndex,
                counts = new Array(radixBase),
                aux = new Array(radixBase);

            for(i = 0; i < radixBase; i++) {
                counts[i] = 0;
            }

            for(i = 0; i < array.length; i++) {
                countsIndex = Math.floor(((array[i] - minValue) / significantDigit) % radixBase);
                counts[countsIndex]++;
            }

            for(i = 1; i < radixBase; i++) {
                counts[i] += counts[i - 1];
            }

            for(i = array.length - 1; i >= 0; i--) {
                countsIndex = Math.floor(((array[i] - minValue) / significantDigit) % radixBase);
                aux[--counts[countsIndex]] = array[i];
            }

            for(i = 0; i < array.length; i++) {
                array[i] = aux[i];
            }

            return array;
        };

        sequentialSearch(item) {

            for(var i = 0; i < this.array.length; i++) {
                if(item === array[i]) {
                    return i;
                }
            }

            return -1;
        };

        findMaxValue() {
            var max = this.array[0];
            for(var i = 1; i < this.array.length; i++) {
                if(max < this.array[i]) {
                    max = this.array[i];
                }
            }

            return max;
        };

        findMinValue() {
            var min = this.array[0];
            for(var i = 1; i < this.array.length; i++) {
                if(min > this.array[i]) {
                    min = this.array[i];
                }
            }

            return min;
        };

        binarySearch(item) {
            this.quickSort();

            var low = 0,
                high = array.length - 1,
                mid, element;

            while(low <= high) {
                mid = Math.floor((low + high) / 2);
                element = this.array[mid];
                console.log('mid element is ' + element);
                if(element < item) {
                    low = mid + 1;
                    console.log('low is ' + low);
                } else if(element > item) {
                    high = mid - 1;
                    console.log('high is ' + high);
                } else {
                    console.log('found it');
                    return mid;
                }
            }
            return -1;
        };

    }
    return ArrayList;
})()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章