前端面試攻略

全局做用域和函數做用域

var a = 1;
   function changeA() {
       console.log(a);
       var a;
   }
   changeA();
複製代碼

猜猜輸出啥,undefined,由於函數做用域內發生了變量提高,函數內的代碼至關於
var a; console.log(a);html

var a = 1;
   function changeA() {
       a = 2;
       console.log(a);
       var a;
   }
   changeA();
複製代碼

猜猜輸出啥,a=2,由於變量提高是直接到函數做用域頂部,在輸出a以前,a已經賦值2,且函數做用域內a是局部變量web

var a = 1;
   function changeA(a) {
       console.log(a);
       var a;
   }
   changeA(a);
複製代碼

輸出 1,由於a是傳參進來的,至關於在函數做用域內a已經聲明和賦值了 另外:ajax

(function () {
        a=5;
        console.log(window.a) // undefined,發生了變量提高
        var a = 10;
    })() // 這個自執行保證了 `var a` 發生變量提高時,不會污染到全局window.a
複製代碼

函數的聲明優先級低於變量:算法

var sum = function () {
  console.log(1);
}

function sum() {
  console.log(2);
}

sum() // 1
複製代碼

變量提高

函數聲明提高會被後面的覆蓋chrome

foo(); // 3
function foo() {
    console.log( 1 );
}
function foo() {
    console.log( 3 );
}
複製代碼

if-else語句裏面的函數聲明都有效json

foo(); // "b"
var a = true;
if (a) {
    function foo() { console.log("a"); }
} else {
    function foo() { console.log("b"); }
}
複製代碼

引用傳遞和值傳遞

函數調用中,傳遞是一個數值,咱們稱爲 「值傳遞」。 函數調用中,傳遞是對象,通常稱爲 「引用傳遞」。引用類型:Object Array Fucntion;對於傳參而言,傳入的東西是不變的。segmentfault

var a = 1;
   function changeA(a) {
       a++;
   }
   changeA(a);
   console.log(a);
複製代碼

這裏會輸出1,a的值沒有改變跨域

var a = [1, 2, 3];
   function changeA(a) {
       a[0] = 2;
   }
   changeA(a);
   console.log(a);
複製代碼

這裏輸出[2, 2, 3],傳入的是指針,指針沒有改變,而值發生了變化
再看看下面的例子,若是數組以...arr的方式傳遞,會發生什麼數組

var a = [1, 2, 3];
   function changeA(...a) {
       a[0] = 2;
   }
   changeA(a);
   console.log(a); // [1, 2, 3]
複製代碼

嚴格相等(===)的特殊值

引用類型全等於永遠返回false,由於變量存儲的是地址值,好比new Object瀏覽器

NaN === NaN                // false
+0 === -0                  // true
+0 === 0                   // true
-0 === 0                   // true
+Infinity === Infinity     // true
+Infinity === -Infinity    // false
-Infinity === Infinity     // false
null === undefined         // false
[] === []                  // false
{} === {}                  // false
複製代碼

隱式類型轉換

Javascript是弱類型語言,之因此不一樣的數據類型之間能夠作運算,是由於JavaScript引擎在運算以前會悄悄的把他們進行了隱式類型轉換的。
如下假設爲比較 x == y的狀況,Type(x)指的是x的數據類型,Type(y)指的是y的類型,最終返回值只有true或false。

  1. Type(x)與Type(y)相同時,進行嚴格相等比較
  2. x是undefined,而y是null時,返回true
  3. x是null,而y是undefined時,返回true
  4. Type(x)是Number而Type(y)是String時,進行x == ToNumber(y)比較
  5. Type(x)是String而Type(y)是Number時,進行ToNumber(x) == y比較
  6. Type(x)是Boolean時,進行ToNumber(x) == y
  7. Type(y)是Boolean時,進行x == ToNumber(y)
  8. Type(x)是Number或String其中一種,而Type(y)是個Object時,進行x == ToPrimitive(y)比較
  9. Type(x)是個Object,而Type(y)是Number或String其中一種時,進行ToPrimitive(x) == y比較
  10. 其餘狀況,返回false

參考教程

其實第一次讀的時候,仍是有點理解不了。仍是系統的剖析一下吧,簡單點來講,比較x == y這個表達式,當 xy 相同,直接進行值比較。當 xy 不一樣,最終必定會把 xy 轉換爲要麼number、要麼string再作值比較。

xy 都是 基礎類型 時,會轉化爲相同的基礎類型再比較,boolean類型會轉化爲Number類型再作比較,當有一方是Number時,最終會轉化爲Number類型再比較,Number類型的優先級是最高的,因此須要熟悉一下Number(x)這個函數,Number(x)+x效果是同樣的,枚舉一下可能碰見的狀況吧:

  • Number('1.5') //1.5
  • Number('1,2') //NaN
  • Number({}) //NaN
  • Number([]) //0
  • Number([2]) //2
  • Number(true) //1
  • Number(null) //0
  • Number(undefined) //NaN

xy 兩個都是引用類型,好比數組、對象、Function,會直接返回false,由於 xy 儲存的是地址。

xy 一方是引用類型時,會進行 ToPrimitive(x || y) 的轉化。若是 x.valueOf 能返回基礎數據類型,則會優先調用 valueOf 方法,若是不能返回基礎數據類型,則會調用 toString 方法。toString 必定會返回基礎數據類型。

找幾個例子說說:

true == true
Number(true) == true => 1 == Number(true) => 1 == 1
左值 true 先轉化爲數字,右值 true 再轉化爲數字,而後進行值比較
答案:true


true == '123'
Number(true) == '123' => 1 == Number('123') => 1 == 123
true先轉化爲數字,再把'123'轉化爲數字123,再比較左值和右值
答案:false


'123' == 2
Number('123') == 2 => 123 == 2
'123'先轉化爲數字,再比較左值和右值
答案:false


[1,2] == 2
toToPrimitive([1,2]) == 2 => '1,2' == 2 => Number('1,2') == 2 => NaN == 2
只解析一項,NaN也是Number類型的一種,NaN與任何數字比較,返回false
答案:false

數組類型

[1,2,3].valueOf() //[1,2,3] 不是基礎數據類型  
[1,2,3].toString() //1,2,3,數組類型toPrimitive會調用這個方法
複製代碼

對象類型

var c = {a:1}; //必須賦值,{a:1}.valueOf()會報錯
c.valueOf() //{a:1}不是基礎數據類型
c.toString() //[object Object],toPrimitive會調用這個方法
c == '[object Object]' //true
複製代碼

解釋一下爲啥 c == '[object Object]' 返回true

toPrimitive(c) == '[object Object]' => '[object Object]' == '[object Object]'

函數類型

function b() { return 2;}
b.valueOf() //返回函數自己,即function b() { return 2;}  
b.toString() //返回字符串,即'function b() { return 2;}',toPrimitive採用這個

b == 'function b() { return 2;}' //true
複製代碼

狀態碼

不介紹常見的狀態碼,主要針對1XX到5XX能加分的詳細說明
100 - Continue 初始的請求已經接受,客戶應當繼續發送請求的其他部分

  • 用於客戶端在發送 post 數據給服務器時,看服務器是否處理 post 的數據,若是不處理,客戶端則不上傳 post 是數據,反之則上傳。在實際應用中,經過 post 上傳大數據時,纔會使用到 100-continue 協議
  • 若是客戶端有 post 數據要上傳,能夠考慮使用 100-continue 協議。在請求頭中加入 {「Expect」:」100-continue」}
  • 若是在發送 100-continue 前收到了 post 數據(客戶端提早發送 post 數據),則不發送 100 響應碼

101 - 服務器已經理解了客戶端的請求,並將經過Upgrade消息頭通知客戶端採用不一樣的協議來完成這個請求

  • 好比請求使用了webSocket協議

202 - 接受和處理、但處理未完成

204 - 服務器成功處理了請求,但沒有返回任何內容

206 - 服務器已經完成了部分用戶的GET請求

  • 在請求mp4文件的時候會返回這個,緣由是這個東西會一部分一部分返回

303 - 臨時重定向,和302狀態碼有着相同的功能,可是303明確表示客戶端應當採用get方式請求資源

307 - 臨時重定向,和302狀態碼有着相同的功能,當30一、30二、303響應狀態碼返回時,幾乎全部瀏覽器都會把post改爲get,並刪除請求報文內的主體,以後請求會自動再次發送。307會遵守瀏覽器標準,不會從post變爲get。可是對於處理響應時的行爲,各類瀏覽器有可能出現不一樣的狀況。

400 - 語義有誤,當前請求沒法被服務器理解。除非進行修改,不然客戶端不該該重複提交這個請求

  • 好比應該用https協議
  • 好比上傳的json數據語法錯誤

401 - 當前請求須要用戶驗證。該響應必須包含一個適用於被請求資源的 WWW-Authenticate 信息頭用以詢問用戶信息,瀏覽器據此顯示用戶名字/密碼對話框,而後在填寫合適的Authorization頭後再次發出請求

403 - Forbidden,服務器已經理解請求,可是拒絕執行它

405 - 請求行中指定的請求方法不能被用於請求相應的資源。該響應必須返回一個Allow 頭信息用以表示出當前資源可以接受的請求方法的列表

410 - Gone,被請求的資源在服務器上已經再也不可用,並且沒有任何已知的轉發地址。這樣的情況應當被認爲是永久性的

414 - Request-URI Too Long,請求的URI 長度超過了服務器可以解釋的長度,所以服務器拒絕對該請求提供服務

415 - Unsupported Media Type,對於當前請求的方法和所請求的資源,請求中提交的實體並非服務器中所支持的格式,所以請求被拒絕

421 - too many connections,從當前客戶端所在的IP地址到服務器的鏈接數超過了服務器許可的最大範圍。一般,這裏的IP地址指的是從服務器上看到的客戶端地址(好比用戶的網關或者代理服務器地址)

500 - Internal Server Error,做爲網關或者代理工做的服務器嘗試執行請求時,從上游服務器接收到無效的響應

502 - Bad Gateway,做爲網關或者代理工做的服務器嘗試執行請求時,從上游服務器接收到無效的響應

503 - Service Unavailable,因爲臨時的服務器維護或者過載,服務器當前沒法處理請求

504 - Gateway Timeout,做爲網關或者代理工做的服務器嘗試執行請求時,未能及時從上游服務器(URI標識出的服務器,例如HTTP、FTP、LDAP)或者輔助服務器(例如DNS)收到響應

DNS解析

一個域名的DNS記錄會在本地有兩種緩存:瀏覽器緩存和操做系統(OS)緩存,會優先訪問瀏覽器緩存,若是未命中則訪問OS緩存,最後再訪問DNS服務器(通常是ISP提供),而後DNS服務器會遞歸式的查找域名記錄,而後返回。
DNS記錄會有一個ttl值(time to live),單位是秒,意思是這個記錄最大有效期是多少。通過實驗,OS緩存會參考ttl值,可是不徹底等於ttl值,而瀏覽器DNS緩存的時間跟ttl值無關,每種瀏覽器都使用一個固定值。 修改hosts文件以後,爲啥有時會馬上生效,有時卻一直不生效呢?在修改hosts文件後,全部OS中DNS緩存會被清空,而瀏覽器緩存則不發生變化,在 chrome://net-internals/#dns 中點擊 Clear Host Cache 會清空OS緩存。若是發現DNS更改不成功,能夠靜待幾十秒。

查找瀏覽器緩存的DNS服務器

瀏覽器在獲取網站域名的實際IP地址後會對其IP進行緩存,減小網絡請求的損耗。每種瀏覽器都有一個固定的DNS緩存時間,其中Chrome的過時時間是1分鐘,在這個期限內不會從新請求DNS。chrome://net-internals/#dns

OS DNS緩存

OS緩存會參考DNS服務器響應的TTL值,可是不徹底等於TTL值

ISP DNS服務器

先檢查一下本身的緩存中有沒有這個地址,有的話就直接返回,沒有的話就去根域找,從根域開始遞歸查詢IP

根域遞歸

根域的地址是寫死在ISP DNS服務器上的,根域便是/;好比www.a.com這樣的域名,先去根域找.com的服務器對應IP,而後.com的服務器對應IP找到a.com的服務器IP...

正則

先通關正則,打好基礎,不然會看不明白,戳我。在正則優化的狀況下,使用new RegExp會比較快。緣由是new RegExp會在代碼執行的過程當中編譯正則,編譯就是在內存中開闢一個空間存放變量或函數,字面量有個廢棄的compile方法也能夠作到這個事情。

騰訊QQ

騰訊QQ號從10000開始,最少5位

[1-9][0-9]{4,}
複製代碼

匹配先後空格

\s表示匹配一個空白符,包括空格、製表符、換頁符、換行符和其餘 Unicode 空格,具體點就是[ \f\n\r\t\v​\u00a0\u1680​\u180e\u2000​\u2001\u2002​\u2003\u2004​ \u2005\u2006​\u2007\u2008​\u2009\u200a​\u2028\u2029​​\u202f\u205f​ \u3000

/(^\s+)|(\s+$)/g
複製代碼

數字分隔

將阿拉伯數字每三位一逗號分隔,如:15000000轉化爲15,000,000

'1500000000000'.replace(/\B(?=(\d{3})+$)/g,',')
複製代碼

匹配中文字符

[\u4e00-\u9fa5]
複製代碼

匹配一個域名

DNS規定,域名中的標號都由英文字母和數字組成,每個標號不超過63個字符,也不區分大小寫字母。標號中除連字符(-)外不能使用其餘的標點符號。級別最低的域名寫在最左邊,而級別最高的域名寫在最右邊。由多個標號組成的完整域名總共不超過255個字符。

/[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/
複製代碼

查找英文句子中全部的單詞

分析:第一,不區分大小寫;第二,帶'的也算在裏面,好比don't;第三,帶-的也算在裏面,好比x-ray

var str = "When you are old and grey and full of sleep, don't make me think. And hid his face amid a crowd of stars.";

str.match(/[a-z]+([-'][a-z]+)?/ig);
複製代碼

獲取url上某個參數名爲name的正則

分析:參數名=值,不一樣參數間用&分隔開

var name= 'rqlang';
    reg = new RegExp('[&?]'+name+'=([^& ]+)')
    str = 'https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=%E6%AD%A3%E5%88%99%E8%8E%B7%E5%8F%96%E6%9F%90%E4%B8%AA%E5%8F%82%E6%95%B0&oq=%25E6%25AD%25A3%25E5%2588%2599%25E8%258E%25B7%25E5%258F%2596%25E6%259F%2590%25E4%25B8%25AA%25E5%258F%2582%25E6%2595%25B0&rsv_pq=baac736e00031a97&rsv_t=515dwC%2Bf5ZRACPl1sr7KbYkxhUwe9G1VxfTPLWRBaQ9vh4Oa8jc6nfh0pQg&rqlang=cn&rsv_enter=1&inputT=2550&rsv_sug3=107&rsv_sug1=103&rsv_sug7=100&rsv_sug2=0&rsv_sug4=3469'
    
val = str.match(reg)[1];
複製代碼

升級一下,獲取url中全部的參數名

var propReg = /([?&][^=]+)/g,
    str = location.search,
    arr = str.match(propReg);

arr.forEach(function(val, index, arr) {
    arr[index] = arr[index].replace(/^(&|\?)/, '');
});  

console.log(arr); // 全部的參數名
複製代碼

再升級一下,獲取url中全部參數對鍵值,以對象的方式展示

var reg = /([&\?][^=]+)=([^& ]+)/g,
    str = location.search,
    arr = str.match(reg);
    
    arr.reduce(function(obj, val, index, arr) { 
        var reg = /[&?]([^=]+)=([^& ]+)/, 
            tmpArr = val.match(reg); 
        
        obj[tmpArr[1]] = tmpArr[2]; 
        return obj;
    }, {});
複製代碼

經常使用的函數

獲取cookie值

cookie的特徵,以';'爲分隔,末字段也許不帶';',prop值前面匹配一個或0個空格

function getCookie(name) {
    var arr,reg=new RegExp("(^| )"+name+"=([^;]*)(;|$)");

    if(arr=document.cookie.match(reg))
        return unescape(arr[2]);
    else
        return null;
}
複製代碼

手寫一個ajax請求

readyState各類值,記不住不要緊,記住這幾個狀態都是圍繞着XMLHttpRequest對象自己,且最後一個狀態是4就能夠了:

  • 0,未初始化,(XMLHttpRequest)對象已經建立,但尚未調用open()方法
  • 1,載入/正在發送請求,即調用open方法
  • 2,載入完成/數據接收,即send()方法執行完成
  • 3,loading,交互/解析數據,此階段解析接收到的服務器端響應數據
  • 4,響應內容解析完成,能夠在客戶端調用了

var xmlHttp = new XMLHttpRequest();

xmlHttp.onreadystatechange = function () {
  // readyState
  if (this.readyState == 4 && this.status == 200) {
    console.log(1);
  } 
}
xmlHttp.open('GET', 'https://www.afea.com', false);
xmlHttp.setRequestHeader('X-Requested-With');
xmlHttp.withCredentials = true; // 跨域請求攜帶cookie
xmlHttp.send(null);
複製代碼

簡單實現雙向數據綁定

var data = {};

object.defineProperty(data, 'text', {
   set(value) {
       $input.value = value;
       this.value = value;
   } 
});

$input.onChange = function () {
    data.text = e.target.value; 
}
複製代碼

實現一個累加器

形如sum(1,2)(3)(4,5)的樣子:

sum(1,2)         // 返回3
sum(3)(1,2)      // 返回6
sum(1,3)(5)(2)   // 返回11
複製代碼

思路是利用閉包,改寫toString方法。

function add () {
  var total = 0;
  var args1 = [...arguments];

  var sum = function (...args) {
    total = args1.concat(args).reduce((total, a) => total += a, total)
    return sum;
  }

  sum.toString = function() { // sum方法調用,return必然會調用toString方法
    return total;
  }

  return sum;
}
複製代碼

重寫bind功能

bind原是Function.prototype上的方法,能夠修改函數的this指向

Function.prototype.bind = function (context) {
    // this指向調用函數
    if (typeof this !== 'function') {
        throw new TypeError('not a function');
    }
    var args = Array.prototype.slice.call(arguments, 1);
  
    return function () {
        return this.apply(context, args.concat(Array.prototype.slice.call(arguments)))
    }
}
複製代碼

實現一個對象或者數組的深拷貝

淺拷貝只複製指向某個對象的引用地址,而不復制對象自己,新舊對象仍是共享同一塊內存。但深拷貝會另外創造一個如出一轍的對象,新對象跟原對象不共享內存,修改新對象不會改到原對象。淺複製只複製一層對象的屬性,而深複製則遞歸複製了全部層級。

function deepClone(target) {
    if (typeof target !== 'object' ) return target;
    
    var arr_tmp = target instanceof Array ? [] : {};
  
    for (var i in target) {
        arr_tmp[i] = typeof target[i] !== 'object' ? target[i] : deepClone(target[i]);
    }
  
    return arr_tmp;
}
複製代碼

實現數組的扁平化

遞歸實現,若是當前元素是數組,則繼續遞歸,不然加入最終返回的扁平化數組

const flattern = (arr) => arr.reduce((a, item) => Array.isArray(item) ? a.concat(flattern(item)) : a.concat(item), [])
複製代碼

循環利用隊列

const flattern  = (arr) => {
  var finalArray = [];

  if (!Array.isArray(arr)) return;

  while(arr.length) {
    var target = arr.shift();

    if (Array.isArray(target)) {
      arr = target.concat(arr);
    } else {
      finalArray.push(target)
    }
  }
  return finalArray;
}
複製代碼

防抖(debounce)

防抖主要是爲了限制函數的執行頻次,以優化函數執行頻次太高致使的響應速度跟不上觸發頻率的問題。若是倒計時沒有結束,則清空倒計時,再從新計時。有個弊端,若是事件不斷循環觸發,而且小於等待時間,則不可能執行回調事件,因此後來又催生了節流。

function debounce(fn, wait, immediate) {
    var timer;
  
    return function() {
        var that = this, args = arguments;
        
        if (immediate) {
            fn.apply(that, args);
            immediate = false;
        }
        
        clearTimeout(timer);
        
        timer = setTimeout(function() {
            fn.apply(that, args);
        }, wait);
    }
}
複製代碼

節流(Throttle)

節流主要是爲了限制函數的執行頻次,以優化函數執行頻次太高致使的響應速度跟不上觸發頻率的問題。要記住這個概念,能夠聯想水龍頭滴水,水的必定量的,會一滴一滴的流出去,可是不必定會流光,時間間隔是必定的。直接上代碼:

function throttle(fn, wait, immediate) {
    var timer, previous = new Date().getTime();
  
    return function() {
        var that = this, args = arguments, now = new Date().getTime();
        
        if (immediate) {
            fn.apply(that, args);
            immediate = false;
        }
        
        if (wait >= now-previous) { // 到必定時間必定執行一次
            previous = now;
            fn.apply(that, args);
            clearTimeout(timer);
        } else {
            timer = setTimeout(function() {
                previous = new Date().getTime();
                fn.apply(that, args);
            }, wait);
        }
    }
}
複製代碼

異步調用鏈

要求:寫一個對象,實現調用a.work().sleep(20).lunch(),會輸出

work
sleep 20 seconds
(wait 20 seconds)
lunch
複製代碼

用隊列實現鏈式調用,當調用鏈很長的時候遞歸,實際上是會報棧溢出的,最好在run里加個setTimeout 0

let a = {
    query: [],
    status: false, 
    run: function () { // 關鍵點,遞歸執行函數
        setTimeout(() => {
            if (this.status) return;    // 若是隊列還在運行中,則返回
    
            if (this.query.length > 0) {
                this.query.shift()(this.run.bind(this))
            }
        }, 0)
    },
    work: function () {
        this.query.push((fn) => {
            console.log('work');
            fn();
        });
        this.run();
        return this;
    },
    lunch: function () {
        this.query.push((fn) => {
            console.log('lunch');
            fn();
        });
        this.run();
        return this;
    },
    sleep: function (time) {
        this.query.push((fn) => {
        this.status = true;  // 只有異步會阻塞隊列執行而已,因此status的更新放在這裏
            console.log(`sleep ${time} seconds`);
            setTimeout(() => {
                this.status = false;
                fn();
            }, time * 1000);
        });
        this.run();
        return this;
    }
}
複製代碼

數據結構和算法

二分查找

假設有一個有序數組,須要查找一個數值爲3的元素,若是存在,返回第一個元素的下標,不然返回-1。

function binarySearch(arr, target) {
    var low = 0, high = arr.length-1, mid;
  
    while(low < high) {
        mid = ~~((low + high)/2);
    
        if(arr[mid] < target) {
            low = mid+1;
        } else {
            high = mid;
        }
    }
  
    if (arr[low] === target) return low;
        else return -1;
}
複製代碼

插入排序

相似整理撲克牌,將每一張牌插到其餘已經有序的牌中適當的位置。冒泡和選擇就不用說了,一個正方向一個反方向,兩個for循環搞定的。

for (var i = 1; i < arr.length; i++) {
    for(var j=i;j > 0 && arr[j] < arr[j-1]; j--;) {
       [arr[j], arr[j-1]] = [arr[j-1], arr[j]]
    }
}
複製代碼

希爾排序

原理戳這,插入排序的晉級版,以gap爲界限分爲一組,每一組進行插入排序計算,一開始時,通常來講gap=length/2,因此穩定的複雜度爲nlogn

function heerSort(arr) {
    var gap = ~~(arr.length/2); // 取整居然比/優先級高,只能用括號補了
  
    for (var i=gap;i>0;i=~~(i/2))
        for (var j=i;j<arr.length;j+=i)
            for(var k=j;k>=i&&arr[k]<arr[k-i];k-=i)
                [arr[k],arr[k-i]]=[arr[k-i],arr[k]];
}
複製代碼

歸併排序

原理戳這,是利用歸併的思想實現的排序方法,該算法採用經典的分治(divide-and-conquer)策略(分治法將問題分(divide)成一些小的問題而後遞歸求解,而治(conquer)的階段則將分的階段獲得的各答案"修補"在一塊兒,即分而治之)。

function mergeSort(arr, low, high, temp) {
    if (low < high) {
        var mid = parseInt((low+high)/2);
        
        mergeSort(arr, low, mid, temp);
        mergeSort(arr, mid+1, high, temp);
        merge(arr, low, high, temp);
    }
}

function merge(arr, low, high, temp) {
    var mid = parseInt((low+high)/2),
        i   = low,
        j   = mid+1,
        k   = 0;
  
    while (i<=mid&&j<=high) {
        if (a[i] < a[j]) {
            temp[k++] = a[i++];
        } else {
            temp[k++] = a[j++];
        }
    }
    
    while(i<=mid) {
        temp[k++] = a[i++];
    }
  
    while(j<=high) {
        temp[k++] = a[j++]
    }
  
    for (var i=0;i<k;i++) {
        a[low+i] = temp[i];
    }
}
複製代碼

快速排序

簡單點來講,就是以一個數爲基準(一般是最左邊的數),把這個序列小於這個數的數放在這個數的左邊,若是大於這個數,則放在右邊。平均性能O(nlogn),最壞性能是O(n2)至關於插入排序,在正序和逆序的時候出現,遞歸劃分爲有一邊爲0個

function quickSort(arr, low, high) {
    var i = low,
        j = high,
        temp = arr[i];
  
    if(i>=j) return;
  
    while(i<j) {
        while(i<j&&arr[j]>=temp)
            j--;
            
        if(i<j)
            arr[i]=arr[j];

        while(i<j&&arr[i]<=temp)
            i++;
        if(i<j)
            arr[j]=arr[i];
    }
    
    arr[i]=temp;
  
    quickSort(arr, low,i-1);
    quickSort(arr, i+1, high);
}複製代碼
相關文章
相關標籤/搜索