一:冒泡排序
动图理解
代码实现
function bubbleSort ( arr) {
for ( let i= 0 ; i< arr. length- 1 ; i++ ) {
let didSwap = false ;
for ( let j= 0 ; j< arr. length- i- 1 ; j++ ) {
if ( arr[ j] > arr[ j+ 1 ] ) {
let temp = arr[ j] ;
arr[ j] = arr[ j+ 1 ] ;
arr[ j+ 1 ] = temp;
didSwap = true ;
}
}
if ( ! didSwap) {
break ;
}
}
}
算法分析
平均时间复杂度【时间】:O(n2 )
最好情况【时间】:O(n),发生在数组本身有序的情况下。
最坏情况【时间】:O(n2 ) ,发生在数组本身反序的情况下。
空间复杂度【空间】:O(1) ,仅在原数组空间下进行元素交换。
排序方式【空间】:内排序
稳定性【空间】:稳定
二:选择排序
动图理解
代码实现
function selectSort ( arr) {
for ( let i= 0 ; i< arr. length- 1 ; i++ ) {
for ( let j= i+ 1 ; j< arr. length; j++ ) {
if ( arr[ i] > arr[ j] ) {
let temp = arr[ i] ;
arr[ i] = arr[ j] ;
arr[ j] = temp;
}
}
}
}
算法分析
平均时间复杂度【时间】:O(n2 )
最好情况【时间】:O(n2 )
最坏情况【时间】:O(n2 )
空间复杂度【空间】:O(1),仅在原数组空间下进行元素交换。
排序方式【空间】:内排序
稳定性【空间】:不稳定(如 [5a ,8,5b ,2,9],第一轮选择交换后为[2,8,5b ,5a ,9],两个5前后顺序变化了)。
三:插入排序
动图理解
代码实现
function insertSort ( arr) {
for ( let i= 1 ; i< arr. length; i++ ) {
let insert_index = i;
let insert_ele = arr[ i] ;
for ( let j= i- 1 ; j>= 0 ; j-- ) {
if ( insert_ele< arr[ j] ) {
insert_index = j;
} else {
break ;
}
}
for ( let z= i- 1 ; z>= insert_index; z-- ) {
arr[ z+ 1 ] = arr[ z] ;
}
arr[ insert_index] = insert_ele;
}
}
算法分析
平均时间复杂度【时间】:O(n2 )
最好情况【时间】:O(n),发生在数组本身有序情况下,每个元素(除第一个元素外)都比一次挪一次插一次。
最坏情况【时间】:O(n2 ),发生在数组本身无序情况下。
空间复杂度【空间】:O(1),仅在原数组空间下进行元素交换。
排序方式【空间】:内排序
稳定性【空间】:稳定
四:希尔排序
动图理解
代码实现
function shellSort ( arr) {
let gap = Math. floor ( arr. length/ 2 ) ;
while ( gap>= 1 ) {
for ( let i= gap; i< arr. length; i++ ) {
shellSortHelp ( arr, i, gap) ;
}
gap = Math. floor ( gap/ 2 ) ;
}
}
function shellSortHelp ( arr, i, gap) {
let insert_index = i;
let insert_ele = arr[ i] ;
for ( let j= i- gap; j>= 0 ; j= j- gap) {
if ( insert_ele< arr[ j] ) {
insert_index = j;
} else {
break
}
}
for ( let z= i- gap; z>= insert_index; z= z- gap) {
arr[ z+ gap] = arr[ z] ;
}
arr[ insert_index] = insert_ele;
}
算法分析
平均时间复杂度【时间】:O(nlog2 n)
最好情况【时间】:O(nlog2 n)
最坏情况【时间】:O(nlog2 n)
空间复杂度【空间】:O(1),仅在原数组空间下进行元素交换。
排序方式【空间】:内排序
稳定性【空间】:不稳定(如 [5a ,5b ,2,9],第一次分组交换后为[2,5b ,5a ,9],第二次分组顺序不变,两个5前后顺序变化了)
五:归并排序
动图理解
代码实现
function mergeSort ( arr, left, right) {
if ( left< right) {
let center = Math. floor ( ( left+ right) / 2 )
mergeSort ( arr, left, center)
mergeSort ( arr, center+ 1 , right)
mergeSortHelp ( arr, left, right, center)
}
}
function mergeSortHelp ( arr, left, right, center) {
let pointer_left = left
let pointer_right = center+ 1
let arr_copy = arr. slice ( )
for ( let i= left; i<= right; i++ ) {
if ( pointer_left=== center+ 1 ) {
for ( let j= i; j<= right; j++ ) {
arr[ j] = arr_copy[ pointer_right++ ]
}
break
}
else if ( pointer_right=== right+ 1 ) {
for ( let j= i; j<= right; j++ ) {
arr[ j] = arr_copy[ pointer_left++ ]
}
break
}
else if ( arr_copy[ pointer_left] <= arr_copy[ pointer_right] ) {
arr[ i] = arr_copy[ pointer_left++ ]
}
else {
arr[ i] = arr_copy[ pointer_right++ ]
}
}
}
算法分析
平均时间复杂度【时间】:O(nlogn)
最好情况【时间】:O(nlogn)
最坏情况【时间】:O(nlogn)
空间复杂度【空间】:O(n),会使用到拷贝数组。
排序方式【空间】:外排序
稳定性【空间】:稳定。
六:快速排序
动图理解
代码实现
function quickSort ( arr, left, right) {
if ( left< right) {
let loginMid = arrAdjust ( arr, left, right) ;
quickSort ( arr, left, loginMid- 1 ) ;
quickSort ( arr, loginMid+ 1 , right) ;
}
}
function arrAdjust ( arr, left, right) {
let pointerLeft = left;
let pointerRight = right;
let referNum = arr[ pointerLeft] ;
while ( pointerLeft< pointerRight) {
while ( pointerLeft< pointerRight && arr[ pointerRight] > referNum) {
pointerRight-- ;
}
if ( pointerLeft< pointerRight) {
arr[ pointerLeft] = arr[ pointerRight] ;
}
while ( pointerLeft< pointerRight && arr[ pointerLeft] < referNum) {
pointerLeft++ ;
}
if ( pointerLeft< pointerRight) {
arr[ pointerRight] = arr[ pointerLeft] ;
}
}
arr[ pointerLeft] = referNum;
return pointerLeft;
}
算法分析
平均时间复杂度【时间】:O(nlogn)
最好情况【时间】:O(nlogn)
最坏情况【时间】:O(n2 )
空间复杂度【空间】:O(nlogn)
排序方式【空间】:内排序
稳定性【空间】:不稳定(索引逻辑中值二分)
七:堆排序
动图理解
代码实现
let len = 0
function heapSort ( arr) {
buildMaxHelp ( arr)
for ( let i= arr. length- 1 ; i> 0 ; i-- ) {
swap ( arr, 0 , i)
len--
heapAdjust ( arr, 0 )
}
}
function buildMaxHelp ( arr) {
len = arr. length
for ( let i= Math. floor ( arr. length/ 2 ) - 1 ; i>= 0 ; i-- ) {
heapAdjust ( arr, i)
}
}
function heapAdjust ( arr, i) {
let left = 2 * i+ 1
let right = 2 * i+ 2
let largest = i
if ( right< len && arr[ right] > arr[ largest] ) {
largest = right
}
if ( left< len && arr[ left] > arr[ largest] ) {
largest = left
}
if ( largest!= i) {
swap ( arr, i, largest)
heapAdjust ( arr, largest)
}
}
function swap ( arr, i, j) {
let temp = arr[ i]
arr[ i] = arr[ j]
arr[ j] = temp
}
腾讯笔试题:无序不重复的数字,取出第K大的数字(取出第k小的数字用小顶堆)。
function heapsort2 ( arr, k) {
buildMaxHeap ( arr)
for ( let i= arr. length- 1 ; i>= arr. length- k; i-- ) {
swap ( arr, 0 , i)
len--
heapify ( arr, 0 )
}
return arr[ arr. length- k]
}
算法分析
平均时间复杂度【时间】:O(nlogn)
最好情况【时间】:O(nlogn)
最坏情况【时间】:O(nlogn)
空间复杂度【空间】:O(1)
排序方式【空间】:内排序
稳定性【稳定性】:不稳定
八:计数排序
动图理解
代码实现
function countingSort ( arr, max = Math. max ( ... arr) ) {
let bucketArr = new Array ( max+ 1 )
for ( let i= 0 ; i< arr. length; i++ ) {
if ( ! bucketArr[ arr[ i] ] ) {
bucketArr[ arr[ i] ] = 0
}
bucketArr[ arr[ i] ] += 1
}
let pointer = 0
for ( let j= 0 ; j< bucketArr. length; j++ ) {
while ( bucketArr[ j] -- > 0 ) {
arr[ pointer++ ] = j
}
}
}
算法分析
平均时间复杂度【时间】:O(n+k)。(n=arr.length,k=bucket.length)
最好情况【时间】:O(n+k)
最坏情况【时间】:O(n+k)
空间复杂度【空间】:O(k)
排序方式【空间】:外排序
稳定性【空间】:稳定(计数排序不基于元素的比较,此处稳定不指上述未优化的计数排序代码)。
九:桶排序
十:基数排序