排序算法命题
- 没有任何基于比较的算法能够保证使用少于lg(N!)~NlgN次比较长度为N的数组排序。
排序算法模板
class Sort {
less (v, w) {//比较大小,v比w小返回true。
let re = (v-w < 0);
return re;
}
exch (arr, i, j) {//交换
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
show (arr) {//打印
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
}
isSorted (arr) { //是否排序完成。
for (let i = 0; i < arr.length; i++){
if (this.less(arr[i] ,arr[i-1])) return false;
}
return true;
}
}
Sort.prototype.sort=sort;
选择排序
按顺序选出,最小,次小到最大。
时间复杂度O(n^2),不需要额外空间
function sort (arr) {
for (let i = 0; i < arr.length; i++){
let min = i;
for (let j = i+1; j < arr.length; j++) {
if (this.less(arr[j], arr[min])) {
min=j;
}
}
this.exch(arr, i, min);
}
return arr;
}
插入排序
插入排序所需的时间取决于输入中元素的初始顺序。有序数组比无序数组快的多。
ave:比较和交换各N^2 /4次。
bad:比较与交换各N^2 /2次
best : 比较N-1,交换0次。
function sort (arr) {
for (let i = 1; i < arr.length; i++){
for (let j = i; j >= 0 && this.less(arr[j], arr[j-1]); j--){
this.exch(arr, j, j-1);
}
}
return arr;
}
希尔排序
思想: 一个数组中任意间隔为h的元素都是有序的。
性能不能确定
//希尔排序
//使用希尔增量
function sort (arr) {
let h = Math.floor(arr.length / 2);
while (h >= 1){
for(let i = h; i < arr.length; i++){
for(let j = i; j >= 0 && this.less(arr[j], arr[j-h]); j = j-h){
this.exch(arr, j, j-h);
}
}
h=Math.floor(h / 2);
}
return arr;
}
归并排序
function merge (arr, lo, mid, hi) {
let i = lo;
let j = mid+1;
let aux=arr.slice();
for (let k = lo;k <= hi; k++){
if (i > mid) arr[k] = aux[j++];
else if (j > hi) arr[k] = aux[i++];
else if (aux[i] > aux[j]) arr[k] = aux[j++];
else arr[k] = aux[i++];
}
return arr;
}
自顶向下的归并排序.
- 对于长度为N的任意数组,自顶向下的归并排序需要N/2*lgN至NlgN次比较
- 主要缺点数组所使用的额外空间和N的大小成正比。
function sort (arr, lo, hi) {
if (hi <= lo) return;
let mid = Math.floor ((lo + hi) / 2);
sort(arr, lo, mid);
sort(arr, mid+1, hi);
merge(arr, lo, mid, hi);
return arr;
}
自低向上的归并排序。
function sort (arr) {
let N = arr.length;
for (let sz = 1; sz < N; sz+=sz) {
for (let i = 0; i < N; i+=2*sz) {
merge(arr, i, i+sz-1, Math.min(i+2*sz-1, N));
}
}
return arr;
}
差别
当数组长度为2的幂时, 自顶向下和自底向上的归并排序的比较次数和数组访问次数相同,顺序不同。其他时候,两种方法的比较和数组访问的次序都有不同。适用
自底向上的归并排序比较适合用链表组织的数据。只需要重新组织链表的链接就能实现原地排序。
快速排序
长度为N的无重复数组排序,快速排序平均需要2NlgN次比较
快速排序最多需要N^2/2次比较
function sort (arr, lo, hi){
let exch=this.exch;
if(lo >= hi){return arr};
let mid = partition (arr, lo, hi);
this.sort(arr, lo, mid-1);
this.sort(arr, mid+1, hi);
function partition (arr, lo, hi) {
let i = lo+1;
let j = hi;
while (i <= j) {
while (arr[lo] > arr[i] && i <= hi) { i++ ;}
while (arr[lo] <= arr[j] && j >= i) { j--;}
if(i >= j){ break };
exch(arr, i, j);
}
exch(arr, lo, j);
return j;
}
return arr;
}
三向切分的快速排序
* a[i] 小于v,将a[lt]和a[i]交换,lt++,i++;
* a[i] 大于v,将a[gt]和a[i]交换,gt–
* a[i] 等于v , i++;
function sort (arr, lo, hi){
console.log(arr, lo, hi);
if(hi <= lo){
return arr;
}
let gt = hi;
let i = lo;
let lt = lo;
let v = arr [lo];
while (gt >= i) {
console.log(arr,i,lt,gt);
if (arr[i] < v) {
this.exch(arr, lt, i);
i++;
lt++;
}else if (arr[i] > v) {
this.exch(arr, i, gt);
gt--;
}else if (arr[i] === v){
i++;
}
}
this.sort(arr, lo, lt-1);;
this.sort(arr, gt+1, hi);
return arr;
}