– 冒泡排序(内外循环)
function bubbleSort(arr) {
for(var i=0, n=arr.length;i
双向冒泡排序法
function bubbleTwoWaySort(arr) {
var t, left = 0, right = arr.length - 1
while(left < right) {
for(var j = left;j <= right;j++) {
if(arr[j+1]= right) break
for(var k = right; k >= left;k--) {
if(arr[k-1] > arr[k]) {
t = arr[k-1]
arr[k-1] = arr[k]
arr[k] = t
}
}
right--
}
return arr
}
– 选择排序
function selectSort(arr) {
for(var i = 0, n = arr.length;i < n-1;i++){
var min = i
for(var j = i + 1;j < n;j++){
if(arr[j]
– 插入排序
function insertSort(arr) {
for(var i = 1, n = arr.length; i < n ; i++) {
var j = i - 1
var current = arr[i]
while(current < arr[j] && j >= 0) {
arr[j+1] = arr[j]
j--
}
arr[j+1] = current
}
return arr
}
– 折半插入排序
减少搜索次数,但数据交换次数不变
– 希尔排序(又称缩小增量排序)(本质还是插入排序)
将待排序列按照某种规则分成几个子序列,分别对这几个子序列进行直接插入排序。这个规则的体现就是增量的选取,如果增量是1, 那就是直接插入排序
function shellSort(arr) {
var len = arr.length;
// gap一直到1(直接插入排序)
for (var gap = Math.floor(len / 2); gap > 0; gap = Math.floor(gap / 2)) {
for (var i = gap; i < len; i++) {
var j = i;
var current = arr[i];
while (j - gap >= 0 && current < arr[j - gap]) {
arr[j] = arr[j - gap];
j = j - gap;
}
arr[j] = current;
}
}
return arr;
}
– 归并排序(重点在于合并)
function mergeSort(arr) {
if(arr.length === 1) {
return arr
}
var arr1 = mergeSort(arr.slice(0, arr.length / 2))
var arr2 = mergeSort(arr.slice(arr.length / 2))
return merge(arr1, arr2)
}
function merge(arr1, arr2) {
var result = []
var p1 = 0, p2 = 0
while(p1 < arr1.length && p2 < arr2.length) {
if(arr1[p1] < arr2[p2]){
result.push(arr1[p1])
p1++
} else {
result.push(arr2[p2])
p2++
}
}
return result.concat(arr1.slice(p1).concat(arr2.slice(p2)))
}
空间复杂度为O(1)的归并: 在merge的时候使用插入排序,- > -用时间换取空间(小声哔哔)
– 快速排序
取巧写法
function quickSort(arr) {
if(arr.length <= 1) return arr
var [current] = arr.splice(0,1)
var arr1 = arr.filter(item => item <= current)
var arr2 = arr.filter(item => item > current)
return [
...quickSort(arr1),
current,
...quickSort(arr2)
]
}
常规写法(性能比上面的高)
function quickSort(arr, left, right) {
if(left < right) {
var mid = pritation(arr, left, right)
quickSort(arr, left, mid-1)
quickSort(arr, mid+1, right)
}
}
function pritation(arr, left, right) {
var i = left
var j = right
var temp = arr[left]
while(i < j) {
while(i < j && arr[j]>=temp) j--
if(i
另一种不错的写法
function quickSort2(ary, comparator = (a, b) => a - b) {
return partition(ary, comparator)
}
function partition(ary, comparator, start = 0, end = ary.length - 1, ) {
if (start >= end) {
return
}
var pivotIndex = Math.floor(Math.random() * (end - start + 1) + start)
var pivot = ary[pivotIndex]
swap(ary, pivotIndex, end)
for (var i = start - 1, j = start; j < end; j++) {
if (comparator(ary[j], pivot) < 0) {
i++
swap(ary, i, j)
}
}
swap(ary, i + 1, end)
partition(ary, comparator, start, i)
partition(ary, comparator, i + 2, end)
return ary
}
非递归方法实现快排(使用栈)(函数递归开销大)
function quickSort2(arr, left, right) {
var stack = [] //使用数组的push、pop方法实现栈效果
stack.push(right, left)
while(stack.length > 0) {
var l = stack.pop(), r = stack.pop()
if(l < r) {
var mid = pritation(arr, l, r)
stack.push(mid-1, l, r, mid+1)
}
}
}
– 堆排序(利用递归,反正只要把最大值或者最小值放到根节点就好了)
大顶堆:父亲大孩子小
小顶堆:父亲小孩子大
function heapSort(arr) {
// 建堆
for(var i = Math.floor(arr.length / 2); i >= 0; i--) {
maxHeapify(arr, i, arr.length)
}
// 已经将最大值放在根节点了
// 进行堆排序,将根节点与叶子节点交换,重新建堆
for(var j = arr.length - 1; j>= 0 ; j--) {
var t = arr[0]
arr[0] = arr[j]
arr[j] = t
maxHeapify(arr, 0, j-1) // 排好序的不需参与建堆
}
}
function maxHeapify(arr, i, size) {
// 父亲i, 孩子2i+1和2i+2
var l = 2*i + 1, r = 2*i + 2, largest = i
if (l <= size && arr[l] > arr[largest]) {
largest = l
}
if (r <= size && arr[r] > arr[largest]) {
largest = r
}
if(largest !== i) {
var t = arr[i]
arr[i] = arr[largest]
arr[largest] = t
maxHeapify(arr, largest, size)
}
}
– 计数排序
找到最小值和最大值,建立从最小值到最大值的数的count(数组对象),遍历数组,count[key]++,再遍历count输出排好序的数组。
优点:O(n+k)
缺点:数据量大或者数据跨度大(例如数组[1,100000000,999])的时候,消耗内存空间、时间大
function countingSort(arr) {
if(n <= 1) return arr
var n = arr.length;
var result = [];
// 找到数组最大和最小值
var min = Math.min.apply(null, arr);
var max = Math.max.apply(null, arr);
if(min === max) return arr;
// 创建长度max的数组,填充0
var C = [];
for(var i = min; i <= max; i++){
C[i] = 0;
}
// 遍历输入数组,填充C
for(var j = 0; j < n; j++){
C[arr[j]]++;
}
// 遍历C,输出数组
for(var k = min; k <= max; k++){
// 按顺序将值推入输出数组,并将对应标志位减1
while(C[k]-- > 0){
result.push(k);
}
}
return result;
}
– 桶排序
将数据分组,对每一组内分别排序,再合并
比如对1-100岁人员按照岁数排序,可以分为1-20岁一组,20-40岁一组,内部排好序后合并。
数据输入:数组以及桶的个数bucket
得到每组范围(max-min+1)/bucket
此排序主要适用于均匀分布的数字数组,在这种情况下能够达到最大效率
function bucketSort(arr, bucket) {
var n = arr.length;
var result = [];
if(n <= 1) return arr;
bucket = bucket || 1;
// 找到数组最大和最小值
var min = Math.min.apply(null, arr), max = Math.max.apply(null, arr);
if(min === max) return arr;
// 每一个桶的范围
var f = (max - min + 1) / bucket;
var mybucket = new Array(bucket);
for(var i = 0; i < n; i++) {
var index = Math.floor((arr[i] - min)/f);
mybucket[index] = mybucket[index] || [];
var currbucket = mybucket[index];
currbucket.push(arr[i]);
var k = currbucket.length - 2;
while(k >= 0 && currbucket[k] > arr[i]) {
currbucket[k+1] = currbucket[k];
k--;
}
currbucket[k+1] = arr[i]
}
for(var i = 0; i < bucket; i++) {
if(mybucket[i])
result = result.concat(mybucket[i])
}
return result
}
– 基数排序
基数排序是一种非比较型的整数排序算法。其基本原理是,按照整数的每个位数分组。在分组过程中,对于不足位的数据用0补位。
基数排序按照对位数分组的顺序的不同,可以分为LSD(Least significant digit)基数排序和MSD(Most significant digit)基数排序。
LSD基数排序,是按照从低位到高位的顺序进行分组排序。MSD基数排序,是按照从高位到低位的顺序进行分组排序。上述两种方式不仅仅是对位数分组顺序不同,其实现原理也是不同的。
function lsdSort(arr) {
var n = arr.length;
if(n<=1) return arr;
var bucket = new Array(10)
var result = arr
var max = Math.max.apply(null, arr)
// 根据max的位数确定要进行多少次桶排序
var count = max.toString().length;
for(var i = 0; i < count; i++) {
for(var j = 0; j < n; j++) {
// i=0 -> 个位
// i=1 -> 十位
var curr = Math.floor(result[j]/(Math.pow(10,i))) % 10
bucket[curr] = bucket[curr] || []
bucket[curr].push(result[j])
}
result = []
for(var j = 0; j < 10; j++) {
if(bucket[j]) {
result = result.concat(bucket[j])
}
}
// 重置桶
bucket = new Array(10)
}
return result
}
MSD:最开始时也是遍历所有元素,取最大值,得到最大位数,建立10个桶。这时从百位取起。不足三位,对应位置为0.
function msdSort(arr, times) {
var n = arr.length;
if(n<=1) return arr;
var bucket = new Array(10)
var result = []
var max = Math.max.apply(null, arr)
var min = Math.min.apply(null, arr)
if(max === min) return arr;
// 根据max的位数确定要进行多少次桶排序
var count = times || max.toString().length;
// 只需要取最高位,其他递归
for(var j = 0; j < n; j++) {
var curr = Math.floor(arr[j]/(Math.pow(10,count-1))) % 10
// 取该位数
bucket[curr] = bucket[curr] || []
bucket[curr].push(arr[j])
}
// console.log(bucket)
// 遍历桶,多于一个数的递归排序
for(var j = 0; j < 10; j++) {
if(bucket[j]) {
result = result.concat(msdSort(bucket[j], count - 1))
}
}
return result
}