排序算法
简单排序算法
冒泡排序
像可乐里面的气泡一样,每一个数都自行的向上比较,如果符合就停下,不符合就继续冒泡
对未排序的元素从头到尾依次与相邻元素比较,如果不符合条件则调换位置,符合则进行下一个元素比较
时间复杂度
n
2
n^2
n2空间复杂度
1
1
1
稳定
function bubbleSort (arr) {
for(let i = 0;i<arr.length;i++) {
for(let j = 0;j<arr.length;j++) {
if(arr[j-1] > arr[j]) {
let curren = arr[j-1]
arr[j-1] = arr[j]
arr[j] = curren
} else {
}
}
}
}
效率:10万数组
选择排序
每次循环找到最小(大)值,放到最前面的位置,依次类推
对于冒泡排序比较,减少交换次数,每次找到最值,避免多余的交换次数
时间复杂度 n 2 n^2 n2,空间复杂度 1 1 1,不稳定
function selectSort(arr) {
let len = arr.length
for(let i = 0; i< len; i++) {
let curren = i
for(let j = 0; j< len; j++ ) {
if(arr[j] < arr[i]) {
curren = j
}
}
if(curren!= i) {
let item = arr[i]
arr[i] = arr[curren]
arr[curren] = item
}
}
return arr
}
效率测试:10万数组
插入排序
简单排序中效率最高
从头到尾开始遍历,每一个元素都需要与左边的所有元素注意比较,如果符合条件就插入,不符合继续向前遍历
时间复杂度 n 2 n^2 n2,空间复杂度 1 1 1稳定
function insetSort(arr) {
let index = 0
for(var i = 1; i < arr.length; i++) {
index = i-1
let curren = arr[index + 1]
while(index >= 0&& arr[index] > curren ) {
// 每次判断左边所有元素是否符合条件,不符合就调换位置
arr[index +1] = arr[index]
index--
}
arr[index + 1] = curren
}
return arr
}
效率测试:10万数组
高级排序
希尔排序
插入排序高配版,只不过插入排序是对整个数组直接排序,而希尔是通过间隔而不是相邻元素插入排序
时间复杂度 n 1.25 n^{1.25} n1.25,空间复杂度 1 1 1,不稳定
选择适合的增量:
HIBBARD
增量:奇数增量sedgewick
增量: 9 4 i − 9 ∗ 2 i + 1 或 者 4 i − 3 2 i + 1 94^i -9*2^i +1或者4^i-32^i +1 94i−9∗2i+1或者4i−32i+1
function shellSort(arr) {
let gap = Math.floor(arr.length /2)
let temp ;
while(gap >= 1) {
// 这里对每一个分组进行插入排序
for(var i = gap;i<arr.length;i++) {
let j = i
temp = arr[i]
while(arr[j - gap] > temp && j > gap -1) {
arr[j] = arr[j-gap]
j -= gap
}
}
arr[j] = temp
gap = Math.floor(gap/2)
}
}
效率测试:100万的长度数组
快速排序
冒泡的高配版
选择一个标记,将所有大于这个标记放在左边.所有大于这个标记放在右边
时间复杂度 n l g n nlgn nlgn,空间复杂度 n l g n nlgn nlgn,不稳定
function quickSort(arr){
if(arr.length <=1) return arr
let right =[]
let left = []
let point = arr.shift()
for(var i = 0; i < arr.length;i++) {
if(arr[i] > point ) {
right.push(arr[i])
} else {
left.push(arr[i])
}
}
return quickSort(left).concat([point],quickSort(right))
}
效率测试:1千万的长度
堆排序
选择排序的高配版
将数据分成一个无序的二叉树,从底层开始搜索,将最大的移动的父节点,重复知道到根节点获取到最大值,然后调换位置,将根节点换到最后子节点,并且去除连接,重复上述过程
时间复杂度 n l o g 2 n nlog_2n nlog2n
空间复杂度
1
1
1
不稳定
var len = 0
function heapSort(arr) {
// 建立大顶堆
len = arr.length
for(var i = Math.floor(len/2);i>=0;i--)// 排序
{
heapFy(arr,i)
}
for(var i = arr.length-1; i > 0; i--) {
let temp = arr[0]
arr[0] = arr[i]
arr[i] = temp
len--
// 调换之后,0对应的位置是比较小的,所有需要从0位置开始判断
heapFy(arr, 0)
}
return arr
}
function heapFy(arr, i) {
// 二叉树的对应的位置index
var left = 2 * i + 1
var right = 2 * i + 2
var largest = i
// 跳过最下层的节点
if(left < len && arr[left] > arr[largest]) {
largest = left
}
if(right < len && arr[right] > arr[largest]) {
largest = right
}
// 排除根节点
if(largest != i) {
// 如果子节点最大,则调换位置
let temp = arr[i]
arr[i] = arr[largest]
arr[largest] = temp
// largest 变为子节点
heapFy(arr, largest)
}
}
效率测试:千万数组
归并排序算法
通过递归,将每一个传入的数组依次分成2个子序表,这2个子序表分别比较大小,并按照比较结果保存到新的数组里面,最后归并
有点将数组拆分成2个单位的数组进行比较,分成最小的模块最后再一起重新合并比较
function mergeSort(arr) {
let length = arr.length
if(length<2) return arr
var middle = Math.floor(length / 2)
// 一分为2
var left = arr.slice(0,middle)
var right = arr.slice(middle)
return merge(mergeSort(left),mergeSort(right))
}
function merge(left, right) {
// 保存结果
var result = []
while(left.length > 0 && right.length > 0) {
if (left[0] <= right[0]) {
// 保存left[0]
result.push(left.shift())
} else {
result.push(right.shift())
}
}
// 多余的left或者right直接合并
if(left.length) {
result= result.concat(left)
}
if(right.length) {
result = result.concat(right)
}
return result
}
效率测试:1百万数组