一:你必須知道的
1> JS原型
2> 排序中的有序區和無序區
3> 二叉樹的基本知識
如果你不知道上面三個東西,還是去復習一下吧,否則,看下面的東西有點吃力。
二:封裝丑陋的原型方法
Function.prototype.method = function(name, func){ this.prototype[name] = func; return this; };
在下面的排序中都要用到這個方法。
三:9種排序算法的思路和實現
1> 插入排序
基本思路:
從無序區的第一個元素開始和它前面有序區的元素進行比較,如果比前面的元素小,那么前面的元素向后移動,否則就將此元素插入到相應的位置。
Array.method('insertSort', function(){ var len = this.length, i, j, tmp; for(i=1; i<len; i++){ tmp = this[i]; j = i - 1; while(j>=0 && tmp < this[j]){ this[j+1] = this[j]; j--; } this[j+1] = tmp; } return this; });
2> 二分插入排序
二分插入排序思路:
先在有序區通過二分查找的方法找到移動元素的起始位置,然后通過這個起始位置將后面所有的元素后移。
Array.method('bInsertSort', function(){ var len = this.length, i, j, tmp, low, high, mid; for(i=1; i<len; i++){ tmp = this[i]; low = 0; high = i - 1; while(low <= high){ mid = (low+high)/2; if(tmp < this[mid]) high = mid - 1; else low = mid + 1; } for(j=i-1; j>=high+1; j--){ this[j+1] = this[j]; } this[j+1] = tmp; } return this; });
3> 希爾排序
希爾排序思路:
我們在第 i 次時取gap = n/(2的i次方),然后將數組分為gap組(從下標0開始,每相鄰的gap個元素為一組),接下來我們對每一組進行直接插入排序。
Array.method('shellSort', function(){ var len = this.length, gap = parseInt(len/2), i, j, tmp; while(gap > 0){ for(i=gap; i<len; i++){ tmp = this[i]; j = i - gap; while(j>=0 && tmp < this[j]){ this[j+gap] = this[j]; j = j - gap; } this[j + gap] = tmp; } gap = parseInt(gap/2); } return this; });
4> 冒泡排序
冒泡排序思想:
通過在無序區的相鄰元素的比較和替換,使較小的元素浮到最上面。
Array.method('bubbleSort', function(){ var len = this.lenght, i, j, tmp; for(i=0; i<len; i++){ for(j=len-1; j>i; j--){ if(this[j] > this[j-1]){ tmp = this[j-1]; this[j-1] = this[j]; this[j] = tmp; } } } return this; });
5> 改進的冒泡排序
基本思路:
如果在某次的排序中沒有出現交換的情況,那么說明在無序的元素現在已經是有序了,就可以直接返回了。
Array.method('rBubbleSort', function(){ var len = this.length, i, j, tmp, exchange; for(i=0; i<len; i++){ exchange = 0; for(j=len-1; j>i; j--){ if(this[j] < this[j-1]){ tmp = this[j]; this[j] = this[j-1]; this[j-1] = tmp; exchange = 1; } } if(!exchange) return this; } return this; });
6> 快速排序
快速排序思路:
1) 假設第一個元素為基准元素
2) 把所有比基准元素小的記錄放置在前一部分,把所有比基准元素大的記錄放置在后一部分,並把基准元素放在這兩部分的中間(i=j的位置)
Array.method('quickSort', function(s, t){ var i=s, j=t, tmp; if(s < t){ tmp = this[s]; while(i!=j){ while(j>i && this[j]>tmp) j--;//右—>左 R[i] = R[j]; while(i<j && this[j]<tmp) i++;//左—>右 R[j] = R[i]; } R[i] = tmp; this.quickSort(s, i-1); this.quickSort(i+1, t); } return this; });
7> 選擇排序
選擇排序思路:
在無序區中選出最小的元素,然后將它和無序區的第一個元素交換位置。
Array.method('selectSort', function(){ var len = this.length, i, j, k, tmp; for(i=0; i<len; i++){ k = i; for(j=i+1; j<len; j++){ if(this[j] < this[k]) k = j; } if(k!=i){ tmp = this[k]; this[k] = this[i]; this[i] = tmp; } } return this; });
8> 堆排序
堆排序是一種樹形選擇排序方法(注意下標是從1開始的,也就是R[1...n])。
堆排序思路:
1) 初始堆:
將原始數組調整成大根堆的方法——篩選算法:
比較R[2i]、R[2i+1]和R[i],將最大者放在R[i]的位置上(遞歸調用此方法到結束)
2) 堆排序:
每次將堆頂元素與數組最后面的且沒有被置換的元素互換。
Array.method('createHeap', function(low, high){ var i=low, j=2*i, tmp=this[i]; while(j<=high){ if(j< high && this[j]<this[j+1]) j++; //從左右子節點中選出較大的節點 if(tmp < this[j]){ //根節點(tmp)<較大的節點 this[i] = this[j]; i = j; j = 2*i; }else break; } this[i] = tmp; //被篩選的元素放在最終的位置上 return this; }); Array.method('heapSort', function(){ var i, tmp, len=this.length-1; for(i=parseInt(len/2); i>=1; i--) this.createHeap(i, len); for(i=len; i>=2; i--){ tmp = this[1]; this[1] = this[i]; this[i] = tmp; this.createHeap(1, i-1); } return this; });
9> 歸並排序
歸並排序思路:
1) 歸並
從兩個有序表R[low...mid]和R[mid+1...high],每次從左邊依次取出一個數進行比較,將較小者放入tmp數組中,最后將兩段中剩下的部分直接復制到tmp中。
這樣tmp是一個有序表,再將它復制加R中。(其中要考慮最后一個子表的長度不足length的情況)
2) 排序
自底向上的歸並,第一回:length=1;第二回:length=2*length ...
Array.method('merge', function(low, mid, high){ var tmp = new Array(), i = low, j=mid+1, k=0; while(i<=mid && j<=high){ if(this[i] <= this[j]){//比較第一部分和第二部分,取較小者 tmp[k] = this[i]; i++; k++; }else{ tmp[k] = this[j]; j++; k++; } } while(i<=mid){ tmp[k] = this[i]; i++; k++; } while(j<=high){ tmp[k] = this[j]; j++; k++; } for(k=0,i=low; i<=high; k++,i++) this[i] = tmp[k]; return this; }); Array.method('mergePass', function(length, n){ var i; for(i=0; i+2*length-1<n; i=i+2*length) this.merge(i, i+length-1, i+2*length-1); if(i+length-1 < n) this.merge(i, i+length-1, n-1); //考慮到最后一個子表的長度可能小於length,所以要特殊處理一下 return this; }); Array.method('mergeSort', function(){ var len = this.length, length; for(length=1; length<len; length=2*length) this.mergePass(length, len); return this; });
四:測試
var out = function(){ console.log(arguments); } var test = [0,1,7,6,3,4,9,8]; out(test.insertSort(), 'insertSort'); var test = [0,1,7,6,3,4,9,8]; out(test.bInsertSort(), 'bInsertSort'); var test = [0,1,7,6,3,4,9,8]; out(test.shellSort(), 'shellSort'); var test = [0,1,7,6,3,4,9,8]; out(test.bubbleSort(), 'bubbleSort'); var test = [0,1,7,6,3,4,9,8]; out(test.rBubbleSort(), 'rBubbleSort'); var test = [0,1,7,6,3,4,9,8]; out(test.quickSort(0, test.length-1), 'quickSort'); var test = [0,1,7,6,3,4,9,8]; out(test.selectSort(), 'selectSort'); var test = [0,1,7,6,3,4,9,8]; out(test.heapSort(), 'heapSort'); var test = [0,1,7,6,3,4,9,8]; out(test.mergeSort(), 'mergeSort');