比較排序算法通常有三個指標程序員
如下的排序都爲升序面試
冒泡排序是面試官最喜歡問新手程序員的.冒泡排序就像名字同樣,冒泡排序第一次冒出最大的,第二次冒出第二大的,第三次冒出第三大的.....直到冒出倒數第二大的.算法
const array = [12, 2, 3, 10, 8, 8, 9, 21]
function BubbleSort(array){
let len = array.length;
if (len == 0 || len == 1) {
return array;
}
for (let i = 0; i < len-1; i++) {
for (let j = 0; j < len-1-i; j++) { // 減i是由於第0到第i大已經冒出來了 不須要再比較了
if (array[j] > array[j+1]) {
[array[j], array[j+1]] = [array[j+1], array[j]];
}
}
}
return array
}
BubbleSort(array) //[2, 3, 8, 8, 9, 10, 12, 21]
複製代碼
時間複雜度爲O(n^2),空間複雜度爲O(1),穩定瀏覽器
僅僅面試考察,實際運用是不會用到的,由於冒泡排序是很是沒效率的,由於不只時間複雜度高並且有O(n^2)的交換,交換所耗的性能遠大於比較bash
選擇排序是第一位找到最小的,第二位找到第二小的,第三位找到第三小的.....post
const array = [12, 2, 3, 10, 8, 8, 9, 21]
function SelectionSort(array){
let len = array.length;
if (len == 0 || len == 1) {
return array;
}
for (let i = 0; i < len-1; i++) {
let min = i;
for (let j = i+1; j < len-1-i; j++) {
if (array[j] < array[min]) {
min = j
}
}
[array[i], array[min]] = [array[min], array[i]];
}
return array
}
SelectionSort(array) //[2, 3, 8, 8, 9, 10, 12, 21]
複製代碼
時間複雜度爲O(n^2),空間複雜度爲O(1),穩定性能
僅僅面試考察,實際運用跟冒泡同樣,也不會用到,由於效率也很是低. 可是比冒泡好點,由於元素若是再正確的位置上不會交換。ui
就是,對於未排序數據,在已排序序列中從後向前掃描,找到相應位置並插入this
const array = [12, 2, 3, 10, 8, 8, 9, 21]
function InsertionSort(array){
let len = array.length;
if (len == 0 || len == 1) {
return array;
}
for (let i = 1; i < len; i++) {
for (let j = 0; j < i; j++) { // 查找的部分能夠使用二分查找
if (array[j] > array[i]) {
this.splice(j, 0, array[i]); // 插入進來
this.splice(i+1, 1); // 刪除已插入的元素
break;
}
}
}
return array;
}
InsertionSort(array) //[2, 3, 8, 8, 9, 10, 12, 21]
複製代碼
時間複雜度爲O(n^2),空間複雜度爲O(1),不穩定spa
效率也不高,一般也不會使用,可是若是數據接近線性排列.那麼使用二分查找插入排序是一個很是好的選擇
這個也是常常被問到,是遞歸算法的經典使用場景
const array = [12, 2, 3, 10, 8, 8, 9, 21]
function quickSort(array){
let len = array.length;
if (len == 0 || len == 1) {
return array;
}
let mid = array[0],
left =[],
right = [];
for (let i = 1; i < len; i++) {
if (array[i] < mid) {
left.push(array[i])
} else {
right.push(array[i])
}
}
return quickSort(left).concat(mid, quickSort(right))
}
quickSort(array) //[2, 3, 8, 8, 9, 10, 12, 21]
複製代碼
時間複雜度爲O(nlogn),空間複雜度爲O(n),不穩定
平均時間複雜度低 ,佔用空間小,快速排序是使用得最多得排序算法
歸併排序是分治算法得經典應用,歸併算法得核心是將兩個已經排序的序列合併成一個序列.
const array = [12, 2, 3, 10, 8, 8, 9, 21]
function mergeSort(array){
let len = array.length;
if (len == 0 || len == 1) {
return array;
}
function merge(left, right) {
let final = [];
while (left.length && right.length) {
final.push(left[0] <= right[0] ? left.shift() : right.shift());
}
return final.concat(left.concat(right));
}
let mid = Math.floor(len-1/2);
let left = array.slice(0, mid)
let right = array.slice(mid);
return merge(mergeSort(left), mergeSort(right))
}
mergeSort(array) //[2, 3, 8, 8, 9, 10, 12, 21]
複製代碼
時間複雜度爲O(nlogn),空間複雜度爲O(n),不穩定
時間複雜度和空間複雜度與快速排序是同樣的,其實二個性能是至關的,畢竟二種排序都出如今瀏覽器內核中。爲何要快速排序使用較大,可能快速排序在各類數據量下表現得更爲穩定吧. 可是若是數據呈分段有序時,使用歸併排序效率更高
具體如何實現,在堆這一章已經講過,我直接貼上代碼了
// 最大堆調整
function maxHeapfiy(array, i, heapSize){
let left = 2*i+1,
right = 2*i+2,
mid = i;
if (left < heapSize && array[left] > array[mid]) {
mid = left;
}
if (right < heapSize && array[right] > array[mid]) {
mid = right;
}
if (mid != i) {
[array[i], array[mid]] = [array[mid], array[i]]
maxHeapfiy(array, mid, heapSize)
}
}
// 構建最大堆
const buildMaxHeapfiy = (array, heapSize) => {
let parent = Math.floor(heapSize/2)
for (parent; parent >= 0; parent--) {
maxHeapfiy(array, parent, heapSize)
}
}
// 堆排序
const array = [12, 2, 3, 10, 8, 8, 9, 21];
let heapSize = array.length;
buildMaxHeapfiy(array, heapSize)
for (let i = heapSize-1; i >=0; i--) {
[array[0], array[i]] = [array[i], array[0]];
this.maxHeapfiy(array, 0, i);
}
// [2, 3, 8, 8, 9, 10, 12, 21]
複製代碼
時間複雜度爲O(nlogn),空間複雜度爲O(n),不穩定
堆排序雖然,時間複雜度和空間複雜度都較低,可是堆排序的有個缺點在於當堆中的一個數據發生改變,都須要進行堆調整來維護最大堆(最小堆),須要額外的維護開銷,因爲在實際運用中,數據變更是很頻繁的,因此實際上堆排序不是很適合實際的運用。