开发 算法 排序算法 决明 2024-01-05 2024-01-05 排序算法是面试及笔试中必考点,本文通过动画方式演示,通过实例讲解,最后给出 JavaScript 版的排序算法
1. 冒泡排序
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素作同样的工作,从头到尾,最后的元素应该会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
编程思路:外循环控制需要比较的元素,比如第一次排序后,最后一个元素就不需要比较了,内循环则负责两两元素比较,将元素放到正确位置上
function bubbleSort (arr ) { var len = arr.length for (var i = len - 1 ; i > 0 ; i--) { for (var j = 0 ; j < i; j++) { if (arr[j] > arr[j + 1 ]) { var tmp = arr[j] arr[j] = arr[j + 1 ] arr[j + 1 ] = tmp } } } return arr }
2. 选择排序 选择排序是从数组的开头开始,将第一个元素和其他元素作比较,检查完所有的元素后,最小 (大) 的放在第一个位置,接下来再开始从第二个元素开始,重复以上一直到最后。
编程思路:两个循环,外循环不断递减至结尾,内循环负责找出最小的值给外层循环交换位置
function selectSort (array ) { var length = array.length , i, j, minIndex, minValue, temp for (i = 0 ; i < length - 1 ; i++) { minIndex = i minValue = array[minIndex] for (j = i + 1 ; j < length; j++) { if (array[j] < minValue) { minIndex = j minValue = array[minIndex] } } temp = array[i] array[i] = minValue array[minIndex] = temp } return array }
3. 插入排序 插入排序核心——扑克牌思想: 就像自己在打扑克牌,接起来一张,放哪里无所谓,再接起来一张,比第一张小,放左边,继续接,可能是中间数,就插在中间….依次类推
function insertSort (arr ) { for (let i = 1 ; i < arr.length ; i++) { for (let j = i; j > 0 ; j--) { if (arr[j] < arr[j - 1 ]) { ;[arr[j], arr[j - 1 ]] = [arr[j - 1 ], arr[j]] } else { break } } } return arr }
4. 快速排序 快速排序是分治策略的经典实现,分治的策略如下:
分解(Divide)步骤:将问题划分未一些子问题,子问题的形式与原问题一样,只是规模更小
解决(Conquer)步骤:递归地求解出子问题。如果子问题的规模足够小,则停止递归,直接求解
合并(Combine)步骤:将子问题的解组合成原问题的解
快速排序函数,我们需要将排序问题划分为一些子问题进行排序,然后通过递归求解,我们的终止条件就是,当 array.length > 1 不再生效时返回数组
function swap (array, a, b ) { ;[array[a], array[b]] = [array[b], array[a]] } function partition (array, left, right ) { const pivot = array[Math .floor ((right + left) / 2 )] let i = left let j = right while (i <= j) { while (compare (array[i], pivot) === -1 ) { i++ } while (compare (array[j], pivot) === 1 ) { j-- } if (i <= j) { swap (array, i, j) i++ j-- } } return i } function compare (a, b ) { if (a === b) { return 0 } return a < b ? -1 : 1 } function quick (array, left, right ) { let index if (array.length > 1 ) { index = partition (array, left, right) if (left < index - 1 ) { quick (array, left, index - 1 ) } if (index < right) { quick (array, index, right) } } return array } function quickSort (array ) { return quick (array, 0 , array.length - 1 ) }
5. 希尔排序 希尔排序是插入排序的改良算法,但是核心理念与插入算法又不同,它会先比较距离较远的元素,而非相邻的元素。
function shellSort (arr, gap ) { console .log (arr) for (let i = 0 ; i < gap.length ; i++) { let n = gap[i] for (let j = i + n; j < arr.length ; j++) { for (let k = j; k > 0 ; k -= n) { if (arr[k] < arr[k - n]) { ;[arr[k], arr[k - n]] = [arr[k - n], arr[k]] console .log (`当前序列为[${arr} ] \n 交换了${arr[k]} 和${arr[k - n]} ` ) } else { continue } } } } return arr } var arr = [3 , 2 , 45 , 6 , 55 , 23 , 5 , 4 , 8 , 9 , 19 , 0 ]var gap = [3 , 2 , 1 ]console .log (shellSort (arr, gap))
6. 归并排序 归并排序的核心思想是分治,分治是通过递归地将问题分解成相同或者类型相关的两个或者多个子问题,直到问题简单到足以解决,然后将子问题的解决方案结合起来,解决原始方案的一种思想
归并排序通过将复杂的数组分解成足够小的数组(只包含一个元素),然后通过合并两个有序数组(单元素数组可认为是有序数组)来达到综合子问题解决方案的目的。所以归并排序的核心在于如何整合两个有序数组,拆分数组只是一个辅助过程。
var arr = [8 ,7 ,6 ,5 ];[8 ,7 ]和[6 ,5 ] [8 ]、[7 ]、[6 ]、[5 ] [7 ,8 ]和[5 ,6 ] [5 ,6 ,7 ,8 ]
function mergeSort (arr ) { function main (arr ) { if (arr.length === 1 ) return arr let mid = Math .floor (arr.length / 2 ) let left = arr.slice (0 , mid) let right = arr.slice (mid) return merge (arguments .callee (left), arguments .callee (right)) } function merge (left, right ) { let il = 0 , rl = 0 , result = [] while (il < left.length && rl < right.length ) { if (left[il] < right[rl]) { result.push (left[il++]) } else { result.push (right[rl++]) } } return result.concat (left.slice (il)).concat (right.slice (rl)) } return main (arr) }
7. 堆排序 堆排序也是一种很高效的排序方法,因为它把数组作为二叉树排序而得名,可以认为是归并排序的改良方案,它是一种原地排序方法,但是不够稳定,其时间复杂度为 O(nlogn)。
var arr = [1 ,2 ,3 ,4 ,5 ,6 ,7 ]; 1 / \ 2 3 / \ / \ 4 5 6 7
堆排序示意图如下:
function heapSort (arr ) { buildHeap (arr) for (let i = arr.length - 1 ; i > 0 ; i--) { ;[arr[i], arr[0 ]] = [arr[0 ], arr[i]] heapify (arr, i, 0 ) } return arr function buildHeap (arr ) { let mid = Math .floor (arr.length / 2 ) for (let i = mid; i >= 0 ; i--) { heapify (arr, arr.length , i) } return arr } function heapify (arr, heapSize, i ) { let left = 2 * i + 1 , right = 2 * i + 2 , largest = i if (left < heapSize && arr[left] > arr[largest]) { largest = left } if (right < heapSize && arr[right] > arr[largest]) { largest = right } if (largest !== i) { ;[arr[largest], arr[i]] = [arr[i], arr[largest]] arguments .callee (arr, heapSize, largest) } return arr } }
决明
While the world sleeps, you dream.
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 揽星河 !