冒泡排序 稳定 o(n^2)
原理: 相邻交换,每轮交换将当前最大放在队尾,下次循环长度-1
function bubbleSort(arr){
for(var i = 0; i<arr.length-1; i++){
for(var j = 0; j<arr.length-i-1; j++){
if(arr[j]>arr[j+1]){
var tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
}
}
}
return arr;
}
var arr = [4,9,3,2,1]
arr = bubbleSort(arr)
console.log(arr)
插入排序 稳定 o(n^2)
原理: 类似于打扑克整理牌,将当前元素插入当前元素前已经排好的序列上
function insertSort(arr){
for(var i = 1; i<arr.length; i++){
var temp = arr[i]
if(arr[i]<arr[i-1]){
var j = 0;
for(j=i-1; arr[j]>temp; j--){
arr[j+1] = arr[j]
}
arr[j+1] = temp;
}
}
return arr;
}
var arr = [4,9,3,2,1]
arr = insertSort(arr)
console.log(arr)
希尔排序 不稳定 仅用于顺序排序 o(n^1.3)
原理: 插入排序改进版,特点是将待排序列按照不同的步长划分为多个序列分别进行插入排序,到最终步长=1时,整个序列已经基本有序,再使用插入排序可以有效减少元素移动次数,使得算法时间复杂度降低。
function shellSort(arr){
for(var step = parseInt(arr.length/2); step>0; step=parseInt(step/2)){
for(var i = step; i<arr.length; i+=step){
if(arr[i]<arr[i-step]){
var temp = arr[i];
var j = 0;
for(j= i-step; arr[j]>temp&&j>=0; j-=step){
arr[j+step] = arr[j];
}
arr[j+step] = temp;
}
}
}
return arr;
}
var arr = [4,9,3,2,1]
arr = shellSort(arr)
console.log(arr)
选择排序 不稳定 o(n^2)
function selectSort(arr){
for(var i = 0; i<arr.length-1; i++){
var maxIndex = 0;
for(var j = 1; j<arr.length-i; j++){
if(arr[j]>arr[maxIndex]){
maxIndex = j;
}
}
var temp = arr[j-1];
arr[j-1] = arr[maxIndex];
arr[maxIndex] = temp;
}
return arr;
}
var arr = [4,9,3,2,1]
arr = selectSort(arr)
console.log(arr)
快速排序 不稳定 o(nlog^n)
原理: 寻找一个基准值【这个选择直接影响算法效率,这里使用最差的选最左位置为基准值】,
在它左侧全部<=它,右侧>它
完成一轮后在分别对基准值左右两边分别进行以上操作
function quickSort(arr, left, right){
if(left>=right){
return;
}
var middle = partition(arr,left,right);
console.log(middle)
quickSort(arr, left, middle-1);
quickSort(arr, middle+1, right);
}
function partition(arr,left,right){
var stand = arr[left];
while(left<right){
while(left<right && arr[right]>stand) right--;
if(left<right){
arr[left++] = arr[right];
}
while(left<right && arr[left]<=stand) left++;
if(left<right){
arr[right--] = arr[left]
}
}
arr[left] = stand;
return left;
}
var arr = [4,9,3,2,1]
quickSort(arr,0 ,arr.length-1)
console.log(arr)
归并 稳定 o(nlog^n)
原理: 采用分治法思想,将待排序列划分为若干子序列,在一一合并
function mergeSort(arr){
if(arr.length < 2){
return arr;
}
var middle = parseInt(arr.length/2);
return merge(mergeSort(arr.splice(0, middle)), mergeSort(arr));
}
function merge(arr1, arr2){
var tempArr = [];
while(arr1.length && arr2.length){
if(arr1[0]>arr2[0]){
tempArr.push(arr2.shift());
}else{
tempArr.push(arr1.shift());
}
}
return [...tempArr, ...arr1, ...arr2];
}
var arr = [4,9,3,2,1]
arr = mergeSort(arr, 0, arr.length-1)
console.log(arr)
堆排序 不稳定 o(nlog^n)
原理: 使用二叉树维护一个大顶堆或小顶堆【根节点值<=孩子节点值】
function heapSort(arr){
arr = createHeap(arr)
console.log(arr)
var tempArr = [];
while(arr.length){
tempArr.push(arr[0]);
arr[0] = arr[arr.length-1];
arr.pop();
if(arr.length>0){
adjust(arr,0);
}
}
return tempArr;
}
function createHeap(arr){
var len = arr.length;
for(var i=parseInt(len/2)-1; i>=0; i--){
arr = adjust(arr,i);
}
return arr;
}
function adjust(arr,i){
var len = arr.length;
var temp = arr[i];
var k = i;
var j = 0;
for(j=2*i+1; j<len; j=(j*2)+1){
if(j<len-1 && arr[j]>arr[j+1]){
j++;
}
if(arr[j]>=temp){
break;
}else{
arr[k] = arr[j];
k = j;
}
}
arr[k] = temp;
return arr;
}
var arr = [1,5,3,0,7,5]
arr = heapSort(arr)
console.log(arr)
基数排序 稳定 o(n*k) k=位数
原理: 按位对应的值作为排序比较依据
function baseSort(arr){
var max = Math.max(arr);
var bits = 1;
while(max/10){
bits++;
max = max/10;
}
for(var i = 1; i<=bits; i++){
var base = []
for(var i = 1; i<=10; i++){
// 0-9
base.push([])
}
for(var j = 0; j<arr.length; j++){
base[arr[j]%(10*i)].push(arr[j]);
}
arr = []
for(var j = 0; j<base.length; j++){
arr = arr.concat(base[j]);
}
}
return arr;
}
var arr = [4,9,3,2,1]
arr = baseSort(arr)
console.log(arr)
桶排序 稳定 o(n+k)
原理: 准备几个桶【即数组】,每个桶转一定范围的元素,在分别对桶内元素进行插入排序。
当然通越多每次插入排序的时间就越少,只不过空间复杂度会提高,如果每个元素一个桶就变为计数排序
function bucketSort(arr){
var bucketsCount = 10;
var buckets = new Array(bucketsCount);
for(var i=0; i<bucketsCount; i++){
buckets[i] = [];
}
var max = Math.max.apply(null,arr);
var min = Math.min.apply(null,arr);
console.log(min)
var gap = (max-min+1)/10;
for(var i = 0; i<arr.length; i++){
buckets[parseInt((arr[i]-min)/gap)].push(arr[i]);
}
for(var i = 0; i<bucketsCount; i++){
half_insert_sort(buckets[i]);
}
arr = []
for(var i = 0; i<bucketsCount; i++){
arr = arr.concat(buckets[i]);
}
return arr;
}
//折半插入
function half_insert_sort(arr){
for(var i=1; i<arr.length; i++){
if(arr[i]<arr[i-1]){
var temp = arr[i];
var j = 0;
var left = 0;
var right = i-1;
while(left<right){
var middle = (left+middle)/2;
if(arr[middle]<temp){
left = middle+1;
}else if(arr[middle]>temp){
right = middle-1;
}else{
break;
}
}
for(j=i-1; j>=left; j--){
arr[j+1] = arr[j];
}
arr[j+1] = temp
}
}
}
var arr = [4,9,3,2,1,15,154,47,1],
arr = bucketSort(arr)
console.log(arr)
计数排序 稳定 o(n+k)
原理: 为每个元素都准备一个对应的桶存放
function countingSort(arr){
var max = Math.max.apply(null,arr);
var min = Math.min.apply(null,arr);
var temp = new Array(max-min+1);
for(var i = 0; i<temp.length; i++){
temp[i] = [];
}
for(var i=0; i<arr.length; i++){
temp[arr[i]-min].push(arr[i]);
}
arr = [];
for(var i=0; i<temp.length; i++){
if(temp[i].length){
arr = arr.concat(temp[i]);
}
}
return arr;
}
var arr = [4,9,3,2,1]
arr = countingSort(arr)
console.log(arr)