国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频

一次搞定九大排序策略

共 40333字,需瀏覽 81分鐘

 ·

2021-08-20 06:47


點(diǎn)擊上方 三分鐘學(xué)前端,關(guān)注公眾號(hào)

回復(fù)交流,加入前端編程面試算法每日一題群


面試官也在看的前端面試資料

14.1 冒泡排序

原理:

從左到右,相鄰元素進(jìn)行比較,如果前一個(gè)元素值大于后一個(gè)元素值(正序),則交換,這樣一輪下來(lái),將最大的數(shù)在最右邊冒泡出來(lái)。這樣一輪一輪下來(lái),最后實(shí)現(xiàn)從小到大排序。

動(dòng)圖演示:

代碼實(shí)現(xiàn):

function bubbleSort(arr{
    for (let i = 0; i < arr.length; i++) {
        for (let j = 0; j < arr.length - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                const temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

// 改進(jìn)冒泡排序
function bubbleSort1(arr{
    for (let i = 0; i < arr.length; i++) {
        // 提前退出冒泡循環(huán)的標(biāo)識(shí)位
        let flag = false;
        for (let j = 0; j < arr.length - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                const temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
                flag = true;
                // 表示發(fā)生了數(shù)據(jù)交換
            }
        }
        // 沒(méi)有數(shù)據(jù)交換
        if(!flag) break
    }
}


// 測(cè)試
let arr = [13254]
bubbleSort(arr)
console.log(arr) // [1, 2, 3, 4, 5]

let arr1 = [13254]
bubbleSort1(arr1)
console.log(arr1) // [1, 2, 3, 4, 5]

復(fù)雜度分析:

  • 時(shí)間復(fù)雜度:最好時(shí)間復(fù)雜度 O(n),平均時(shí)間復(fù)雜度 O(n^2^)
  • 空間復(fù)雜度:O(1)

14.2 選擇排序

原理

從未排序的序列中找到最大(或最小的)放在已排序序列的末尾(為空則放在起始位置),重復(fù)該操作,知道所有數(shù)據(jù)都已放入已排序序列中。

動(dòng)態(tài)演示

代碼實(shí)現(xiàn)

function selectionSort(arr{
  let length = arr.length,
      indexMin
  for(let i = 0; i < length - 1; i++) {
    indexMin = i
    for(let j = i; j < length; j++) {
      if(arr[indexMin] > arr[j]) {
        indexMin = j
      }
    }
    if(i !== indexMin) {
      let temp = arr[i]
      arr[i] = arr[indexMin]
      arr[indexMin] = temp
    }
  }
}

// 測(cè)試
let arr = [13254]
selectionSort(arr)
console.log(arr) // [1, 2, 3, 4, 5]

復(fù)雜度分析

**時(shí)間復(fù)雜度:**O(n^2^)

**空間復(fù)雜度:**O(1)

14.3 歸并排序

原理

它采用了分治策略,將數(shù)組分成2個(gè)較小的數(shù)組,然后每個(gè)數(shù)組再分成兩個(gè)更小的數(shù)組,直至每個(gè)數(shù)組里只包含一個(gè)元素,然后將小數(shù)組不斷的合并成較大的數(shù)組,直至只剩下一個(gè)數(shù)組,就是排序完成后的數(shù)組序列。

實(shí)現(xiàn)步驟:

  • 將原始序列平分成兩個(gè)小數(shù)組
  • 判斷小數(shù)組長(zhǎng)度是否為1,不為1則繼續(xù)分裂
  • 原始數(shù)組被分稱(chēng)了長(zhǎng)度為1的多個(gè)小數(shù)組,然后合并相鄰小數(shù)組(有序合并)
  • 不斷合并小數(shù)組,直到合并稱(chēng)一個(gè)數(shù)組,則為排序后的數(shù)組序列

動(dòng)圖演示

代碼實(shí)現(xiàn)

function mergeSort(arr{
  let array = mergeSortRec(arr)
  return array
}

// 若分裂后的兩個(gè)數(shù)組長(zhǎng)度不為 1,則繼續(xù)分裂
// 直到分裂后的數(shù)組長(zhǎng)度都為 1,
// 然后合并小數(shù)組
function mergeSortRec(arr{
  let length = arr.length
  if(length === 1) {
    return arr
  }
  let mid = Math.floor(length / 2),
      left = arr.slice(0, mid),
      right = arr.slice(mid, length)
  return merge(mergeSortRec(left), mergeSortRec(right))
}

// 順序合并兩個(gè)小數(shù)組left、right 到 result
function merge(left, right{
  let result = [],
      ileft = 0,
      iright = 0
  while(ileft < left.length && iright < right.length) {
    if(left[ileft] < right[iright]){
      result.push(left[ileft ++])
    } else {
      result.push(right[iright ++])
    }
  }
  while(ileft < left.length) {
    result.push(left[ileft ++])
  }
  while(iright < right.length) {
    result.push(right[iright ++])
  }
  return result
}

// 測(cè)試
let arr = [13254]
console.log(mergeSort(arr)) // [1, 2, 3, 4, 5]

復(fù)雜度分析

**時(shí)間復(fù)雜度:**O(nlog~2~n)

**空間復(fù)雜度:**O(n)

14.4 快速排序

原理

和歸并排序一致,它也使用了分治策略的思想,它也將數(shù)組分成一個(gè)個(gè)小數(shù)組,但與歸并不同的是,它實(shí)際上并沒(méi)有將它們分隔開(kāi)。

快排使用了分治策略的思想,所謂分治,顧名思義,就是分而治之,將一個(gè)復(fù)雜的問(wèn)題,分成兩個(gè)或多個(gè)相似的子問(wèn)題,在把子問(wèn)題分成更小的子問(wèn)題,直到更小的子問(wèn)題可以簡(jiǎn)單求解,求解子問(wèn)題,則原問(wèn)題的解則為子問(wèn)題解的合并。

快排的過(guò)程簡(jiǎn)單的說(shuō)只有三步:

  • 首先從序列中選取一個(gè)數(shù)作為基準(zhǔn)數(shù)
  • 將比這個(gè)數(shù)大的數(shù)全部放到它的右邊,把小于或者等于它的數(shù)全部放到它的左邊 (一次快排 partition
  • 然后分別對(duì)基準(zhǔn)的左右兩邊重復(fù)以上的操作,直到數(shù)組完全排序

具體按以下步驟實(shí)現(xiàn):

  • 1,創(chuàng)建兩個(gè)指針?lè)謩e指向數(shù)組的最左端以及最右端
  • 2,在數(shù)組中任意取出一個(gè)元素作為基準(zhǔn)
  • 3,左指針開(kāi)始向右移動(dòng),遇到比基準(zhǔn)大的停止
  • 4,右指針開(kāi)始向左移動(dòng),遇到比基準(zhǔn)小的元素停止,交換左右指針?biāo)赶虻脑?
  • 5,重復(fù)3,4,直到左指針超過(guò)右指針,此時(shí),比基準(zhǔn)小的值就都會(huì)放在基準(zhǔn)的左邊,比基準(zhǔn)大的值會(huì)出現(xiàn)在基準(zhǔn)的右邊
  • 6,然后分別對(duì)基準(zhǔn)的左右兩邊重復(fù)以上的操作,直到數(shù)組完全排序

注意這里的基準(zhǔn)該如何選擇喃?最簡(jiǎn)單的一種做法是每次都是選擇最左邊的元素作為基準(zhǔn):

但這對(duì)幾乎已經(jīng)有序的序列來(lái)說(shuō),并不是最好的選擇,它將會(huì)導(dǎo)致算法的最壞表現(xiàn)。還有一種做法,就是選擇中間的數(shù)或通過(guò) Math.random() 來(lái)隨機(jī)選取一個(gè)數(shù)作為基準(zhǔn),下面的代碼實(shí)現(xiàn)就是以隨機(jī)數(shù)作為基準(zhǔn)。

代碼實(shí)現(xiàn)

let quickSort = (arr) => {
  quick(arr, 0 , arr.length - 1)
}

let quick = (arr, left, right) => {
  let index
  if(left < right) {
    // 劃分?jǐn)?shù)組
    index = partition(arr, left, right)
    if(left < index - 1) {
      quick(arr, left, index - 1)
    }
    if(index < right) {
      quick(arr, index, right)
    }
  }
}

// 一次快排
let partition = (arr, left, right) => {
  // 取中間項(xiàng)為基準(zhǔn)
  var datum = arr[Math.floor(Math.random() * (right - left + 1)) + left],
      i = left,
      j = right
  // 開(kāi)始調(diào)整
  while(i <= j) {
    
    // 左指針右移
    while(arr[i] < datum) {
      i++
    }
    
    // 右指針左移
    while(arr[j] > datum) {
      j--
    }
    
    // 交換
    if(i <= j) {
      swap(arr, i, j)
      i += 1
      j -= 1
    }
  }
  return i
}

// 交換
let swap = (arr, i , j) => {
    let temp = arr[i]
    arr[i] = arr[j]
    arr[j] = temp
}

// 測(cè)試
let arr = [13254]
quickSort(arr)
console.log(arr) // [1, 2, 3, 4, 5]
// 第 2 個(gè)最大值
console.log(arr[arr.length - 2])  // 4

快排是從小到大排序,所以第 k 個(gè)最大值在 n-k 位置上

復(fù)雜度分析

  • 時(shí)間復(fù)雜度:O(nlog~2~n)
  • 空間復(fù)雜度:O(nlog~2~n)

14.5 希爾排序

1959年Shell發(fā)明,第一個(gè)突破 O(n^2^) 的排序算法,是簡(jiǎn)單插入排序的改進(jìn)版。它與插入排序的不同之處在于,它會(huì)優(yōu)先比較距離較遠(yuǎn)的元素。

插入排序

插入排序的工作原理是通過(guò)構(gòu)建有序序列,對(duì)于未排序數(shù)據(jù),在已排序序列中從后向前掃描,找到相應(yīng)位置并插入

代碼實(shí)現(xiàn):

function insertionSort(arr{
    let n = arr.length;
    let preIndex, current;
    for (let i = 1; i < n; i++) {
        preIndex = i - 1;
        current = arr[i];
        while (preIndex >= 0 && arr[preIndex] > current) {
            arr[preIndex + 1] = arr[preIndex];
            preIndex--;
        }
        arr[preIndex + 1] = current;
    }
    return arr;
}

插入算法的核心思想是取未排序區(qū)間中的元素,在已排序區(qū)間中找到合適的插入位置將其插入,并保證已排序區(qū)間數(shù)據(jù)一直有序。重復(fù)這個(gè)過(guò)程,直到未排序區(qū)間中元素為空,算法結(jié)束。

復(fù)雜度分析:

  • 時(shí)間復(fù)雜度:O(n^2^)
  • 空間復(fù)雜度:O(1)

希爾排序

回顧一下上面的插入排序:

  • 第一趟插入排序后,我們得到的有效序列長(zhǎng)度為 2
  • 第二趟插入排序后,我們得到的有效序列長(zhǎng)度為 3
  • ...
  • 直到這個(gè)序列有序

所以,如果序列足夠亂的話(huà),時(shí)間復(fù)雜度為 O(n^2^)

希爾排序又是如何優(yōu)化的喃?

希爾排序又叫縮小增量排序,就是把數(shù)列進(jìn)行分組(組內(nèi)不停使用插入排序),直至從宏觀上看起來(lái)有序,最后插入排序起來(lái)就容易了(無(wú)須多次移位或交換)。

其中組的數(shù)量稱(chēng)為 增量 ,顯然的是,增量是不斷遞減的(直到增量為1)

那我們有是如何進(jìn)行分組喃?

**往往的:**如果一個(gè)數(shù)列有 8 個(gè)元素,我們第一趟的增量是 4 ,第二趟的增量是 2 ,第三趟的增量是 1 。如果一個(gè)數(shù)列有 18 個(gè)元素,我們第一趟的增量是 9 ,第二趟的增量是 4 ,第三趟的增量是2 ,第四趟的增量是 1

很明顯我們可以用一個(gè)序列來(lái)表示增量:n/2、(n/2)/2、...、1,每次增量都/2

例如:

let arr = [415873]

排序前:

  • 將該數(shù)組看成三組( Math.floor(arr.length/2) ),分別是: [4, 1] , [5, 8] , [7, 3]

第一趟排序:

  • 對(duì)三組數(shù)據(jù)分別進(jìn)行插入排序,因此我們?nèi)齻€(gè)數(shù)組得到的結(jié)果為: [1, 4] , [5, 8] , [3, 7]

此時(shí)數(shù)組是這樣子的:[1, 4, 5, 8, 3, 7]

第二趟排序:

  • 增量減少了,上面增量是 3 ,此時(shí)增量應(yīng)該為 1 了,因此把 [1, 4, 5, 8, 3, 7] 看成一個(gè)數(shù)組(從宏觀上是有序的了),對(duì)其進(jìn)行插入排序,直至有序

代碼實(shí)現(xiàn):

function shellSort(arr{
    let n = arr.length;
    for (let gap = Math.floor(n / 2); gap > 0; gap = Math.floor(gap / 2)) {
        for (let i = gap; i < n; i++) {
            let j = i;
            let current = arr[i];
            while (j - gap >= 0 && current < arr[j - gap]) {
                 arr[j] = arr[j - gap];
                 j = j - gap;
            }
            arr[j] = current;
        }
    }
    return arr;
}

復(fù)雜度分析:

  • 時(shí)間復(fù)雜度:O(nlogn)
  • 空間復(fù)雜度:O(1)

14.6 計(jì)數(shù)排序

原理

計(jì)數(shù)排序不是基于比較的排序算法,其核心在于將輸入的數(shù)據(jù)值轉(zhuǎn)化為鍵存儲(chǔ)在額外開(kāi)辟的數(shù)組空間中。

作為一種線(xiàn)性時(shí)間復(fù)雜度的排序,計(jì)數(shù)排序要求輸入的數(shù)據(jù)必須是有確定范圍的整數(shù)。它是一種典型的拿空間換時(shí)間的排序算法

代碼實(shí)現(xiàn)

function countingSort(arr, maxValue) => {
    // 開(kāi)辟的新的數(shù)組,用于將輸入的數(shù)據(jù)值轉(zhuǎn)化為鍵存儲(chǔ)
    var bucket = new Array(maxValue + 1),
        sortedIndex = 0,
        arrLen = arr.length,
        bucketLen = maxValue + 1

    // 存儲(chǔ)
    for (var i = 0; i < arrLen; i++) {
        if (!bucket[arr[i]]) {
            bucket[arr[i]] = 0
        }
        bucket[arr[i]]++
    }

    // 將數(shù)據(jù)從bucket按順序?qū)懭隺rr中
    for (var j = 0; j < bucketLen; j++) {
        while(bucket[j]-- > 0) {
            arr[sortedIndex++] = j
        }
    }
    return arr
}

復(fù)雜度分析

  • 時(shí)間復(fù)雜度:O(n+k)
  • 空間復(fù)雜度:O(n+k)

14.7 桶排序

原理

桶排序是計(jì)數(shù)排序的升級(jí)版。它也是利用函數(shù)的映射關(guān)系。

桶排序 (Bucket sort)的工作的原理:假設(shè)輸入數(shù)據(jù)服從均勻分布,將數(shù)據(jù)分到有限數(shù)量的桶里,每個(gè)桶再分別排序(有可能再使用別的排序算法或是以遞歸方式繼續(xù)使用桶排序進(jìn)行排)。

完整步驟:

  • 首先使用 arr 來(lái)存儲(chǔ)頻率
  • 然后創(chuàng)建一個(gè)數(shù)組(有數(shù)量的桶),將頻率作為數(shù)組下標(biāo),對(duì)于出現(xiàn)頻率不同的數(shù)字集合,存入對(duì)應(yīng)的數(shù)組下標(biāo)(桶內(nèi))即可。
// 桶排序
let bucketSort = (arr) => {
    let bucket = [], res = []
    arr.forEach((value, key) => {
        // 利用映射關(guān)系(出現(xiàn)頻率作為下標(biāo))將數(shù)據(jù)分配到各個(gè)桶中
        if(!bucket[value]) {
            bucket[value] = [key]
        } else {
            bucket[value].push(key)
        }
    })
    // 遍歷獲取出現(xiàn)頻率
    for(let i = 0;i <= bucket.length - 1;i++){
        if(bucket[i]) {
            res.push(...bucket[i])
        }
 }
 return res
}

復(fù)雜度分析:

  • 時(shí)間復(fù)雜度:O(n)
  • 空間復(fù)雜度:O(n)

14.8 基數(shù)排序

原理

基數(shù)排序是一種非比較型整數(shù)排序算法,其原理是將整數(shù)按位數(shù)切割成不同的數(shù)字,然后按每個(gè)位數(shù)分別比較。由于整數(shù)也可以表達(dá)字符串(比如名字或日期)和特定格式的浮點(diǎn)數(shù),所以基數(shù)排序也不是只能使用于整數(shù)。

完整步驟:

  • 取得數(shù)組中的最大數(shù),并取得位數(shù);
  • arr為原始數(shù)組,從最低位開(kāi)始取每個(gè)位組成radix數(shù)組;
  • 對(duì)radix進(jìn)行計(jì)數(shù)排序(利用計(jì)數(shù)排序適用于小范圍數(shù)的特點(diǎn));

動(dòng)圖演示

代碼實(shí)現(xiàn)

//LSD Radix Sort
var counter = [];
function radixSort(arr, maxDigit{
    var mod = 10;
    var dev = 1;
    for (var i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
        for(var j = 0; j < arr.length; j++) {
            var bucket = parseInt((arr[j] % mod) / dev);
            if(counter[bucket]==null) {
                counter[bucket] = [];
            }
            counter[bucket].push(arr[j]);
        }
        var pos = 0;
        for(var j = 0; j < counter.length; j++) {
            var value = null;
            if(counter[j]!=null) {
                while ((value = counter[j].shift()) != null) {
                      arr[pos++] = value;
                }
          }
        }
    }
    return arr;
}

復(fù)雜度分析

  • 時(shí)間復(fù)雜度:基數(shù)排序基于分別排序,分別收集,所以是穩(wěn)定的。但基數(shù)排序的性能比桶排序要略差,每一次關(guān)鍵字的桶分配都需要O(n)的時(shí)間復(fù)雜度,而且分配之后得到新的關(guān)鍵字序列又需要O(n)的時(shí)間復(fù)雜度。假如待排數(shù)據(jù)可以分為d個(gè)關(guān)鍵字,則基數(shù)排序的時(shí)間復(fù)雜度將是O(d*2n) ,當(dāng)然d要遠(yuǎn)遠(yuǎn)小于n,因此基本上還是線(xiàn)性級(jí)別的
  • 空間復(fù)雜度:O(n+k),其中k為桶的數(shù)量。一般來(lái)說(shuō)n>>k,因此額外空間需要大概n個(gè)左右

基數(shù)排序 vs 計(jì)數(shù)排序 vs 桶排序

這三種排序算法都利用了桶的概念,但對(duì)桶的使用方法上有明顯差異:

  • 基數(shù)排序:根據(jù)鍵值的每位數(shù)字來(lái)分配桶;
  • 計(jì)數(shù)排序:每個(gè)桶只存儲(chǔ)單一鍵值;
  • 桶排序:每個(gè)桶存儲(chǔ)一定范圍的數(shù)值;

14.9 堆排序

原理

堆是一棵完全二叉樹(shù),它可以使用數(shù)組存儲(chǔ),并且大頂堆的最大值存儲(chǔ)在根節(jié)點(diǎn)(i=1),所以我們可以每次取大頂堆的根結(jié)點(diǎn)與堆的最后一個(gè)節(jié)點(diǎn)交換,此時(shí)最大值放入了有效序列的最后一位,并且有效序列減1,有效堆依然保持完全二叉樹(shù)的結(jié)構(gòu),然后堆化,成為新的大頂堆,重復(fù)此操作,知道有效堆的長(zhǎng)度為 0,排序完成。

完整步驟為:

  • 將原序列(n個(gè))轉(zhuǎn)化成一個(gè)大頂堆
  • 設(shè)置堆的有效序列長(zhǎng)度為 n
  • 將堆頂元素(第一個(gè)有效序列)與最后一個(gè)子元素(最后一個(gè)有效序列)交換,并有效序列長(zhǎng)度減1
  • 堆化有效序列,使有效序列重新稱(chēng)為一個(gè)大頂堆
  • 重復(fù)以上2步,直到有效序列的長(zhǎng)度為 1,排序完成

動(dòng)圖演示

代碼實(shí)現(xiàn)

function heapSort(items{
    // 構(gòu)建大頂堆
    buildHeap(items, items.length-1)
    // 設(shè)置堆的初始有效序列長(zhǎng)度為 items.length - 1
    let heapSize = items.length - 1
    for (var i = items.length - 1; i > 1; i--) {
        // 交換堆頂元素與最后一個(gè)有效子元素
        swap(items, 1, i);
        // 有效序列長(zhǎng)度減 1
        heapSize --;
        // 堆化有效序列(有效序列長(zhǎng)度為 currentHeapSize,拋除了最后一個(gè)元素)
        heapify(items, heapSize, 1);
    }
    return items;
}

// 原地建堆
// items: 原始序列
// heapSize: 有效序列長(zhǎng)度
function buildHeap(items, heapSize{
    // 從最后一個(gè)非葉子節(jié)點(diǎn)開(kāi)始,自上而下式堆化
    for (let i = Math.floor(heapSize/2); i >= 1; --i) {    
        heapify(items, heapSize, i);  
    }
}
function heapify(items, heapSize, i{
    // 自上而下式堆化
    while (true) {
        var maxIndex = i;
        if(2*i <= heapSize && items[i] < items[i*2] ) {
            maxIndex = i*2;
        }
        if(2*i+1 <= heapSize && items[maxIndex] < items[i*2+1] ) {
            maxIndex = i*2+1;
        }
        if (maxIndex === i) break;
        swap(items, i, maxIndex); // 交換 
        i = maxIndex; 
    }
}  
function swap(items, i, j{
    let temp = items[i]
    items[i] = items[j]
    items[j] = temp
}

// 測(cè)試
var items = [,192837465]
heapSort(items)
// [empty, 1, 2, 3, 4, 5, 6, 7, 8, 9]

測(cè)試成功

復(fù)雜度分析

  • **時(shí)間復(fù)雜度:**建堆過(guò)程的時(shí)間復(fù)雜度是 O(n) ,排序過(guò)程的時(shí)間復(fù)雜度是 O(nlogn) ,整體時(shí)間復(fù)雜度是 O(nlogn)
  • 空間復(fù)雜度: O(1)

14.10 加深

14.10.1 介紹一下快排原理以及時(shí)間復(fù)雜度,并實(shí)現(xiàn)一個(gè)快排

快排使用了分治策略的思想,所謂分治,顧名思義,就是分而治之,將一個(gè)復(fù)雜的問(wèn)題,分成兩個(gè)或多個(gè)相似的子問(wèn)題,在把子問(wèn)題分成更小的子問(wèn)題,直到更小的子問(wèn)題可以簡(jiǎn)單求解,求解子問(wèn)題,則原問(wèn)題的解則為子問(wèn)題解的合并。

快排的過(guò)程簡(jiǎn)單的說(shuō)只有三步:

  • 首先從序列中選取一個(gè)數(shù)作為基準(zhǔn)數(shù)
  • 將比這個(gè)數(shù)大的數(shù)全部放到它的右邊,把小于或者等于它的數(shù)全部放到它的左邊 (一次快排 partition
  • 然后分別對(duì)基準(zhǔn)的左右兩邊重復(fù)以上的操作,直到數(shù)組完全排序

具體按以下步驟實(shí)現(xiàn):

  • 1,創(chuàng)建兩個(gè)指針?lè)謩e指向數(shù)組的最左端以及最右端
  • 2,在數(shù)組中任意取出一個(gè)元素作為基準(zhǔn)
  • 3,左指針開(kāi)始向右移動(dòng),遇到比基準(zhǔn)大的停止
  • 4,右指針開(kāi)始向左移動(dòng),遇到比基準(zhǔn)小的元素停止,交換左右指針?biāo)赶虻脑?
  • 5,重復(fù)3,4,直到左指針超過(guò)右指針,此時(shí),比基準(zhǔn)小的值就都會(huì)放在基準(zhǔn)的左邊,比基準(zhǔn)大的值會(huì)出現(xiàn)在基準(zhǔn)的右邊
  • 6,然后分別對(duì)基準(zhǔn)的左右兩邊重復(fù)以上的操作,直到數(shù)組完全排序

注意這里的基準(zhǔn)該如何選擇喃?最簡(jiǎn)單的一種做法是每次都是選擇最左邊的元素作為基準(zhǔn):

但這對(duì)幾乎已經(jīng)有序的序列來(lái)說(shuō),并不是最好的選擇,它將會(huì)導(dǎo)致算法的最壞表現(xiàn)。還有一種做法,就是選擇中間的數(shù)或通過(guò) Math.random() 來(lái)隨機(jī)選取一個(gè)數(shù)作為基準(zhǔn),下面的代碼實(shí)現(xiàn)就是以隨機(jī)數(shù)作為基準(zhǔn)。

代碼實(shí)現(xiàn)

let quickSort = (arr) => {
  quick(arr, 0 , arr.length - 1)
}

let quick = (arr, left, right) => {
  let index
  if(left < right) {
    // 劃分?jǐn)?shù)組
    index = partition(arr, left, right)
    if(left < index - 1) {
      quick(arr, left, index - 1)
    }
    if(index < right) {
      quick(arr, index, right)
    }
  }
}

// 一次快排
let partition = (arr, left, right) => {
  // 取中間項(xiàng)為基準(zhǔn)
  var datum = arr[Math.floor(Math.random() * (right - left + 1)) + left],
      i = left,
      j = right
  // 開(kāi)始調(diào)整
  while(i <= j) {
    
    // 左指針右移
    while(arr[i] < datum) {
      i++
    }
    
    // 右指針左移
    while(arr[j] > datum) {
      j--
    }
    
    // 交換
    if(i <= j) {
      swap(arr, i, j)
      i += 1
      j -= 1
    }
  }
  return i
}

// 交換
let swap = (arr, i , j) => {
    let temp = arr[i]
    arr[i] = arr[j]
    arr[j] = temp
}

// 測(cè)試
let arr = [13254]
quickSort(arr)
console.log(arr) // [1, 2, 3, 4, 5]
// 第 2 個(gè)最大值
console.log(arr[arr.length - 2])  // 4

快排是從小到大排序,所以第 k 個(gè)最大值在 n-k 位置上

復(fù)雜度分析

  • 時(shí)間復(fù)雜度:O(nlogn)
  • 空間復(fù)雜度:O(nlogn)

更多解答

14.10.2 打亂數(shù)組(洗牌算法)

打亂一個(gè)沒(méi)有重復(fù)元素的數(shù)組。

示例:

// 以數(shù)字集合 1, 2 和 3 初始化數(shù)組。
int[] nums = {1,2,3};
Solution solution = new Solution(nums);

// 打亂數(shù)組 [1,2,3] 并返回結(jié)果。任何 [1,2,3]的排列返回的概率應(yīng)該相同。
solution.shuffle();

// 重設(shè)數(shù)組到它的初始狀態(tài)[1,2,3]。
solution.reset();

// 隨機(jī)返回?cái)?shù)組[1,2,3]打亂后的結(jié)果。
solution.shuffle();

解答:Fisher-Yates 洗牌算法

let Solution = function(nums{
    this.nums = nums
};

Solution.prototype.reset = function({
    return this.nums
};

Solution.prototype.shuffle = function({
    let res = [...this.nums]
    let n = res.length
    for(let i = n-1; i >= 0; i--) {
        let randIndex = Math.floor(Math.random() * (i + 1))
        swap(res, randIndex, i)
    }
    return res
};

let swap = function(arr, i, j{
    const temp = arr[i]
    arr[i] = arr[j]
    arr[j] = temp
}

復(fù)雜度分析:

  • 時(shí)間復(fù)雜度:O(n)
  • 空間復(fù)雜度:O(n),需要實(shí)現(xiàn) reset 功能,原始數(shù)組必須得保存一份

更多解答

14.10.3 阿里五面:說(shuō)下希爾排序的過(guò)程?希爾排序的時(shí)間復(fù)雜度和空間復(fù)雜度又是多少?

1959年Shell發(fā)明,第一個(gè)突破 O(n^2^) 的排序算法,是簡(jiǎn)單插入排序的改進(jìn)版。它與插入排序的不同之處在于,它會(huì)優(yōu)先比較距離較遠(yuǎn)的元素。

插入排序

插入排序的工作原理是通過(guò)構(gòu)建有序序列,對(duì)于未排序數(shù)據(jù),在已排序序列中從后向前掃描,找到相應(yīng)位置并插入

代碼實(shí)現(xiàn):

function insertionSort(arr{
    let n = arr.length;
    let preIndex, current;
    for (let i = 1; i < n; i++) {
        preIndex = i - 1;
        current = arr[i];
        while (preIndex >= 0 && arr[preIndex] > current) {
            arr[preIndex + 1] = arr[preIndex];
            preIndex--;
        }
        arr[preIndex + 1] = current;
    }
    return arr;
}

插入算法的核心思想是取未排序區(qū)間中的元素,在已排序區(qū)間中找到合適的插入位置將其插入,并保證已排序區(qū)間數(shù)據(jù)一直有序。重復(fù)這個(gè)過(guò)程,直到未排序區(qū)間中元素為空,算法結(jié)束。

復(fù)雜度分析:

  • 時(shí)間復(fù)雜度:O(n^2^)
  • 空間復(fù)雜度:O(1)

希爾排序

回顧一下上面的插入排序:

  • 第一趟插入排序后,我們得到的有效序列長(zhǎng)度為 2
  • 第二趟插入排序后,我們得到的有效序列長(zhǎng)度為 3
  • ...
  • 直到這個(gè)序列有序

所以,如果序列足夠亂的話(huà),時(shí)間復(fù)雜度為 O(n^2^)

希爾排序又是如何優(yōu)化的喃?

希爾排序又叫縮小增量排序,就是把數(shù)列進(jìn)行分組(組內(nèi)不停使用插入排序),直至從宏觀上看起來(lái)有序,最后插入排序起來(lái)就容易了(無(wú)須多次移位或交換)。

其中組的數(shù)量稱(chēng)為 增量 ,顯然的是,增量是不斷遞減的(直到增量為1)

那我們有是如何進(jìn)行分組喃?

往往的: 如果一個(gè)數(shù)列有 8 個(gè)元素,我們第一趟的增量是 4 ,第二趟的增量是 2 ,第三趟的增量是 1 。如果一個(gè)數(shù)列有 18 個(gè)元素,我們第一趟的增量是 9 ,第二趟的增量是 4 ,第三趟的增量是2 ,第四趟的增量是 1

很明顯我們可以用一個(gè)序列來(lái)表示增量:n/2、(n/2)/2、...、1,每次增量都/2

例如:

let arr = [415873]

排序前:

  • 將該數(shù)組看成三組( Math.floor(arr.length/2) ),分別是: [4, 1] , [5, 8] , [7, 3]

第一趟排序:

  • 對(duì)三組數(shù)據(jù)分別進(jìn)行插入排序,因此我們?nèi)齻€(gè)數(shù)組得到的結(jié)果為: [1, 4] , [5, 8] , [3, 7]

此時(shí)數(shù)組是這樣子的:[1, 4, 5, 8, 3, 7]

第二趟排序:

  • 增量減少了,上面增量是 3 ,此時(shí)增量應(yīng)該為 1 了,因此把 [1, 4, 5, 8, 3, 7] 看成一個(gè)數(shù)組(從宏觀上是有序的了),對(duì)其進(jìn)行插入排序,直至有序

代碼實(shí)現(xiàn):

function shellSort(arr{
    let n = arr.length;
    for (let gap = Math.floor(n / 2); gap > 0; gap = Math.floor(gap / 2)) {
        for (let i = gap; i < n; i++) {
            let j = i;
            let current = arr[i];
            while (j - gap >= 0 && current < arr[j - gap]) {
                 arr[j] = arr[j - gap];
                 j = j - gap;
            }
            arr[j] = current;
        }
    }
    return arr;
}

復(fù)雜度分析:

  • 時(shí)間復(fù)雜度:O(nlogn)
  • 空間復(fù)雜度:O(1)

更多解答

14.10.4 排序鏈表

在 O(n log n) 時(shí)間復(fù)雜度和常數(shù)級(jí)空間復(fù)雜度下,對(duì)鏈表進(jìn)行排序。

示例 1:

輸入: 4->2->1->3
輸出: 1->2->3->4

示例 2:

輸入: -1->5->3->4->0
輸出: -1->0->3->4->5

解答:采用歸并排序

歸并排序采用了分治策略,將數(shù)組分成2個(gè)較小的數(shù)組,然后每個(gè)數(shù)組再分成兩個(gè)更小的數(shù)組,直至每個(gè)數(shù)組里只包含一個(gè)元素,然后將小數(shù)組不斷的合并成較大的數(shù)組,直至只剩下一個(gè)數(shù)組,就是排序完成后的數(shù)組序列。

對(duì)應(yīng)于鏈表喃?

4->2->1->3

第一步:分割

  • 使用快慢指針(雙指針?lè)ǎ?,獲取鏈表的中間節(jié)點(diǎn)
  • 根據(jù)中間節(jié)點(diǎn),分割成兩個(gè)小鏈表
  • 遞歸執(zhí)行上一步,直到小鏈表中只有一個(gè)節(jié)點(diǎn)

第二步:歸并(合并有序鏈表)

代碼實(shí)現(xiàn)

let sortList = function(head{
    return mergeSortRec(head)
}

// 歸并排序
// 若分裂后的兩個(gè)鏈表長(zhǎng)度不為 1,則繼續(xù)分裂
// 直到分裂后的鏈表長(zhǎng)度都為 1,
// 然后合并小鏈表
let mergeSortRec = function (head{
    if(!head || !head.next) {
        return head
    }

    // 獲取中間節(jié)點(diǎn)
    let middle = middleNode(head)
    // 分裂成兩個(gè)鏈表
    let temp = middle.next
    middle.next = null
    let left = head, right = temp
    // 繼續(xù)分裂(遞歸分裂)
    left = mergeSortRec(left)
    right = mergeSortRec(right)
    // 合并兩個(gè)有序鏈表
    return mergeTwoLists(left, right)
}

// 獲取中間節(jié)點(diǎn)
// - 如果鏈表長(zhǎng)度為奇數(shù),則返回中間節(jié)點(diǎn)
// - 如果鏈表長(zhǎng)度為偶數(shù),則有兩個(gè)中間節(jié)點(diǎn),這里返回第一個(gè)
let middleNode = function(head{
    let fast = head, slow = head
    while(fast && fast.next && fast.next.next) {
        slow = slow.next
        fast = fast.next.next
    }
    return slow
}

// 合并兩個(gè)有序鏈表
let mergeTwoLists = function(l1, l2{
    let preHead = new ListNode(-1);
    let cur = preHead;
    while(l1 && l2){
        if(l1.val < l2.val){
            cur.next = l1;
            l1 = l1.next;
        }else{
            cur.next = l2;
            l2 = l2.next;
        }
        cur = cur.next;
    }
    cur.next = l1 || l2;
    return preHead.next;
}

引入遞歸算法的復(fù)雜度分析:

  • 遞歸算法的時(shí)間復(fù)雜度:遞歸的總次數(shù) * 每次遞歸的數(shù)量
  • 遞歸算法的空間復(fù)雜度:遞歸的深度 * 每次遞歸創(chuàng)建變量的個(gè)數(shù)

復(fù)雜度分析

  • 時(shí)間復(fù)雜度:遞歸的總次數(shù)為 T(logn) ,每次遞歸的數(shù)量為 T(n) ,時(shí)間復(fù)雜度為 O(nlogn)
  • 空間復(fù)雜度:遞歸的深度為 T(logn) ,每次遞歸創(chuàng)建變量的個(gè)數(shù)為 T(c) (c為常數(shù)),空間復(fù)雜度為 O(logn)

關(guān)于復(fù)雜度分析,請(qǐng)看這篇:前端進(jìn)階算法1:如何分析、統(tǒng)計(jì)算法的執(zhí)行效率和資源消耗?

優(yōu)化遞歸

使用迭代代替遞歸,優(yōu)化時(shí)間復(fù)雜度:O(logn) —> O(1)

更多解答

14.10.5 撲克牌問(wèn)題

魔術(shù)師手中有一堆撲克牌,觀眾不知道它的順序,接下來(lái)魔術(shù)師:

  • 從牌頂拿出一張牌, 放到桌子上
  • 再?gòu)呐祈斈靡粡埮疲?放在手上牌的底部

如此往復(fù)(不斷重復(fù)以上兩步),直到魔術(shù)師手上的牌全部都放到了桌子上。

此時(shí),桌子上的牌順序?yàn)椋?牌頂) 1,2,3,4,5,6,7,8,9,10,11,12,13 (牌底)。

問(wèn):原來(lái)魔術(shù)師手上牌的順序,用函數(shù)實(shí)現(xiàn)。

解答:反向推導(dǎo)

假設(shè),原來(lái)魔術(shù)師手上牌的順序數(shù)組為 origin ,最后放在桌子上的順序數(shù)組為 result

正向的操作為: origin 取出第一個(gè)插入 result 前面, origin 再取出第一個(gè)換到自己的末尾,如此重復(fù);

反向操作為: origin 最后一個(gè)放到自己的第一個(gè)前面, result 拿出第一個(gè)插入 origin 前面,如此重復(fù);

const calc = (arr) => {
    const origin = [];
    for (let i = 0; i < arr.length; i++) {
        if (origin.length) {
            const item = origin.pop();
            origin.unshift(item);
        }
        origin.unshift(result[i])
    }
    return origin;
}

// 測(cè)試
const result = [12345678910111213]
// 原有順序
calc(result)
// [13, 2, 12, 6, 11, 3, 10, 5, 9, 1, 8, 4, 7]

更多解答

14.10.6 有效三角形的個(gè)數(shù)

給定一個(gè)包含非負(fù)整數(shù)的數(shù)組,你的任務(wù)是統(tǒng)計(jì)其中可以組成三角形三條邊的三元組個(gè)數(shù)。

示例 1:

輸入: [2,2,3,4]
輸出: 3
解釋:
有效的組合是: 
2,3,4 (使用第一個(gè) 2)
2,3,4 (使用第二個(gè) 2)
2,2,3

注意:

  • 數(shù)組長(zhǎng)度不超過(guò)1000。
  • 數(shù)組里整數(shù)的范圍為 [0, 1000]。

本題可結(jié)合:

  • 字節(jié)&leetcode1:兩數(shù)之和
  • 騰訊&leetcode15:三數(shù)之和

一起練習(xí)

解法:排序+雙指針

我們知道三角形的任意兩邊之和大于第三邊,任意兩邊之差小于第三邊,如果這三條邊長(zhǎng)從小到大為 a 、 b 、 c ,當(dāng)且僅當(dāng) a + b > c 這三條邊能組成三角形

解題思路: 先數(shù)組排序,排序完后,固定最長(zhǎng)的邊,利用雙指針?lè)ㄅ袛嗥溆噙?/p>

以 nums[nums.length - 1] 作為最長(zhǎng)的邊 nums[k] ( k = nums.length - 1 )

以 nums[i] 作為最短邊,以 nums[nums.length - 2] 作為第二個(gè)數(shù) nums[j] ( j = nums.length - 2 ) ,

判斷 nums[i] + nums[j] 是否大于 nums[k] ,

  • nums[i] + nums[j] > nums[k] ,則:

    nums[i+1] + nums[j] > nums[k]
    nums[i+2] + nums[j] > nums[k]
    ...
    nums[j-1] + nums[j] > nums[k]

    則可構(gòu)成三角形的三元組個(gè)數(shù)加 j-i ,并且 j 往前移動(dòng)一位( j-- ), 繼續(xù)進(jìn)入下一輪判斷

  • nums[i] + nums[j] <= nums[k],則 l 往后移動(dòng)一位(nums 是增序排列),繼續(xù)判斷

代碼實(shí)現(xiàn):

let triangleNumber = function(nums{
    if(!nums || nums.length < 3return 0
    let count = 0
    // 排序
    nums.sort((a, b) => a - b) 
    for(let k = nums.length - 1; k > 1; k--){
        let i = 0, j = k - 1
        while(i < j){ 
            if(nums[i] + nums[j] > nums[k]){
                count += j - i
                j--
            } else {
                i++
            }
        }
    }       
    return count
}

復(fù)雜度分析:

  • 時(shí)間復(fù)雜度:O(n^2^)
  • 空間復(fù)雜度:O(n)

注意:

關(guān)于 Array.prototype.sort() ,ES 規(guī)范并沒(méi)有指定具體的算法,在 V8 引擎中, 7.0 版本之前,數(shù)組長(zhǎng)度小于10時(shí), Array.prototype.sort() 使用的是插入排序,否則用快速排序。

在 V8 引擎 7.0 版本之后就舍棄了快速排序,因?yàn)樗皇欠€(wěn)定的排序算法,在最壞情況下,時(shí)間復(fù)雜度會(huì)降級(jí)到 O(n2)。

而是采用了一種混合排序的算法:TimSort 。

這種功能算法最初用于Python語(yǔ)言中,嚴(yán)格地說(shuō)它不屬于以上10種排序算法中的任何一種,屬于一種混合排序算法:

在數(shù)據(jù)量小的子數(shù)組中使用插入排序,然后再使用歸并排序將有序的子數(shù)組進(jìn)行合并排序,時(shí)間復(fù)雜度為 O(nlogn) 。

更多解答

最后

歡迎關(guān)注「三分鐘學(xué)前端」,回復(fù)「交流」自動(dòng)加入前端三分鐘進(jìn)階群,每日一道編程算法面試題(含解答),助力你成為更優(yōu)秀的前端開(kāi)發(fā)!

號(hào)內(nèi)回復(fù):

網(wǎng)絡(luò)」,自動(dòng)獲取三分鐘學(xué)前端網(wǎng)絡(luò)篇小書(shū)(90+頁(yè))
JS」,自動(dòng)獲取三分鐘學(xué)前端 JS 篇小書(shū)(120+頁(yè))
算法」,自動(dòng)獲取 github 2.9k+ 的前端算法小書(shū)
面試」,自動(dòng)獲取 github 23.2k+ 的前端面試小書(shū)
簡(jiǎn)歷」,自動(dòng)獲取程序員系列的 120 套模版
》》面試官也在看的前端面試資料《《
“在看和轉(zhuǎn)發(fā)”就是最大的


瀏覽 28
點(diǎn)贊
評(píng)論
收藏
分享

手機(jī)掃一掃分享

分享
舉報(bào)
評(píng)論
圖片
表情
推薦
點(diǎn)贊
評(píng)論
收藏
分享

手機(jī)掃一掃分享

分享
舉報(bào)

感谢您访问我们的网站,您可能还对以下资源感兴趣:

国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频 国产黄色性爱视频| 国产在线无码观看| 在线观看黄色网页| 人妻少妇被猛烈进入中文字幕 | 日韩欧美91| 天天舔| 91色色色| 俺来也俺去了| 日本中文字幕亚洲| 亚洲爱爱网站| 韩国一区二区三区在线观看| BBWBBw嫩| 免费毛片基地| 97在线观看免费视频| 欧美日韩精品一区二区三区视频播放| 尻屄视频免费| 免费看黄色电影| 亚洲免费网站| 苍井空一区| 欧美超碰在线| 精品无码三级在线观看视频| 国产精品久久久久无码AV| 蜜桃视频免费网站| 欧美成人一区免费视频| 国产高清一区| 久久久成人视频| 人人爱人人爽| 五月丁香激情婷婷| 日韩无码电影| 精品无人区无码乱码毛片国产 | 丰满人妻一区二区三区| 精品婷婷| 成人无码日韩| 粉嫩护士小泬18p| 国产麻豆一区二区三区| 梁祝艳谭A级毛片| 午夜亚洲福利视频| 曰本中文字幕在线视频| 无码国产精品一区二区免费式直播 | 日韩一区二区三区精品| 操BBB操BBB| 亚洲AV资源在线| 日韩A片免费| 人人妻人人爱| 插吧插吧网| 爱爱黄色视频| 亚洲av播放| 91国语又粗又大对白| 午夜视频免费| 久干妞| 国产精品毛片VA一区二区三区| 国产91一区在线精品| 最新中文字幕在线观看| 国产秘久久一区二区| 日本十八禁网站| 青青草免费观看视频| 久久婷婷成人综合色怡春院| 91妻人人澡人人爽人人精品| 国产91丝袜在线播放| 国产,亚洲91| 2016av天堂网| 亚洲天堂无码a| 国产免费自拍| 一区二区三区视频在线观看| 成人做爰黄A片免费看直播室动漫| 中文字幕在线观看不卡| 日韩欧美精品18| 毛片A级| 大鸡巴久久久久久久| 亚洲天堂无码av| 人妻免费在线视频| 中文字幕97| 色婷操逼| 成人小视频十八禁免费观看| 国产在线观看免费成人视频| 亚洲在线视频| 国产精品内射| 亚洲在线中文字幕| 人人操人人摸人人干| 天天干女人| 午夜精品久久久久久久| 亚洲一区二区三区在线| 99无码国产成人精品| 黑巨茎大战欧美白妞小说| 无码在线不卡| a片视频网站| 中文在线免费看视频| 亚洲成人免费在线| 丁香五月婷婷中文字幕| 国产ts在线观看| 激情三区| 人妻啪啪| 一区二区三区水蜜桃| 91精品视频在线免费观看| 国产精品v欧美精品v日韩精品| 大香蕉伊人手机在线| 日韩一区二区免费看| 亚洲人成免费网站| 亚洲无码黄色电影| 国产精品啪啪啪| 激情亚洲五月天| 日本操鸡小视频| 欧美综合网在线观看| 影音先锋中文字幕资源| 国产一级a毛一级a毛片视频黑人 | 天天色伊人| 狼友视频在线| 成人精品无码| 超碰青娱乐| 51无码| 91av视频在线观看| 操逼国产| 中日美朝美女一级片免费看| 欧美综合亚洲图片综合区| 成人性生活一级片| 亚洲影院中文字幕| 91东热激情| 最新中文字幕在线播放| 丁香五月婷婷视频| 亚洲欧美91| 操女人的网站| 国产视频123区| 无码蜜桃一区二区| 日韩一区二区三区无码电影| 中文字幕在线成人| 成人高清无码在线| 2026国产精品视频| 午夜操逼网| 神马影院午夜福利| 久一精品| 亚洲AV电影网| a免费视频| 激情五月天成人| 北条麻妃久久| 久久6| 日本少妇午夜福利| 天堂黄片| 中文在线а√天堂8| 成人在线三级| 国产精品一区二区免费| 最近日本中文字幕中文翻译歌词| 国产熟女一区| 国产永久精品| 欧美A区| 青春草在线观看视频| 波多野成人无码精品69| 中国操逼网| 国产精品福利在线| 亚洲高清国产欧美综合s8| 日韩高清久久| 成人五月天黄色电影| 三级操逼| 国产成人在线视频免费| 91人妻人人澡人人爽人人爽| 亚洲天堂网在线观看视频| 国产毛片一区| 麻豆精品传媒2021md| 国产综合一区二区| 免费中文字幕AV| 福利网站在线观看| 日韩操b| 人人操人人射| 中文字幕网在线| 操逼资源| 国产亚洲无码激情前后夹击| 日本在线一区二区| 精品无码三级在线观看视频| 97人妻在线视频| 爱射综合| 日韩精品成人| 日韩免费在线视频观看| 婷婷二区| 手机AV在线观看| 91超碰人人| 国产男女啪啪视频| 国产成人精品视频免费| 日韩激情网| 姐弟乱伦性爱| 大香蕉伊人免费| 精品国精品自拍自在线| 七十路の高齢熟女千代子下载| 一级操逼毛片| 亚洲精品一二三区| 99久久综合| 精品无码一区二区三区四区久久久软件| 国偷自产视频一区二区久| 51国产视频| 欧美日韩在线视频一区| 一级黄色电影免费观看| 啊啊啊网站| www日韩| 新狠狠干| 91逼| 大炕上公让我高潮了六次| 亚洲欧美性爱| 亚洲中文字幕在线观看视频网站| 成人无码日本动漫电影| 亚洲婷婷综合网| 毛片成人网| 欧美超碰在线| 亚洲电影在线观看| 欧美日本色| 在线观看免费a片| 极品av| 国产91在线亚洲| 大地影院在线资源观看| 无码一区二区三区四季| 大香蕉AV电影| 可以免费看的黄色| 日本a片在线观看| 亚洲日韩AV在线| 九九视屏| 欧美日韩肏屄视频| 水蜜桃网站在线观看| 无码人妻精品一区二区三千菊电影| 中文字幕在线观看亚洲| 北条麻妃一区二区三区在线观看| 亚洲三级黄片| 老司机一区二区三区| 国产精品a片| www.天天干| 欧美在线观看一区二区| 国产精品久久久久久婷婷天堂| 丁香五月婷婷五月天| 日本一区二区三区在线视频| 久久久桃色| 午夜噜噜| 肏逼网址| 北条麻妃无码观看| 亚洲精品国产精品乱玛不99 | 专区无日本视频高清8| 人人操人人爽| 老熟女网站| 狠狠欧美| BBW老熟女BBw| 超碰天天干天天摸| 91吴梦梦无码一区二区| 熟妇综合| 在线观看污视频| 粉嫩一区二区三区四区| 91无码一区二区三区| 群交无码| 殴美老妇BBBBBBBBB| 91麻豆天美传媒在线| 成人无码区亚洲AV久久| 中文有码在线| 操逼视频在线| 91日韩无码| 老司机视频在线视频18| www.第四色| 欧美日本激情| 丰满人妻一区二区三区四区不卡| 五月中文字幕| 成人国产精品秘久久久网站| 水果派解说AV无码一区| 大香蕉大香蕉视频网| 操BBBB| 国产十欧洲十美国+亚洲一二三区在线午夜 | 在线观看污视频| 99热6| 精品国产毛片| 91三级视频| 国产剧情一区二区av在线观看 | 国产黄色在线| 婷婷黄色网| 人人妻人人玩人人澡人人爽| 日韩无码电影网站| 蜜桃视频网站在线观看| 久久视频一区| 操批视频| 亚洲三级无码视频| 人人干国产| 91.xxxxx| 99久久久久久久无码| 日韩人妻无码电影| 亚洲一区二区在线免费观看| 免费操b视频| 操女人大逼| 波多野吉衣毛片| 免费AV网站观看| 黄色内射视频| 爱搞在线观看| 69堂在线观看| 在线网址你懂的| 一级免费黄色电影| 91香蕉视频在线看| 俺操也| 亚洲成人国产| 亚洲天堂在线免费观看视频 | 人人妻人人玩澡人人爽| 日韩无码视频网| 麻豆国产91在线播放| 思思精品视频| 91成人无码看片在线观看网址| 插菊花综合网1| 国产精品久久一区二区三区影音先锋| 深爱五月激情网| 日韩一级| 亚洲狠狠撸| 成人自拍视频在线观看| 黄色18禁| 成人网站免费视频| 国产AV影视| 狠狠狠狠狠狠操| 亚洲网站视频| 精品国产乱子伦一区二区三区,小小扐 | 白浆四溢av| 黄色在线不卡| 在线免费观看黄| 国产精品成人3p一区二区三区| 91天堂在线| 国产激情av| 婷婷亚洲国产| 免费高潮视频| 激情小视频在线| 亚洲日韩成人在线| 黄色一区二区三区| 91丝袜在线| 无码精品一区二区| 澳门午夜黄色在线| 中文字幕乱码中文字幕电视剧| 91视频在线观看18| 最新免费一区二区三区| 欧美一级婬片免费视频黄| 男女啪网站| 蜜桃av无码一区二区三区| 天堂亚洲AV无码精品成人| 中文字幕牛牛婷婷| 免费无码国产在线观看快色| 一级片在线免费看| 午夜av在线观看| 婷婷五月电影| 中文解说AⅤ水果派| 亚洲婷婷三级成人网| 99re在线观看观看这里只有精品| 日韩一区二区三区在线| 一级一级a免一级a做免费线看内裤| 国产灬性灬淫灬欲水灬| 中文字幕一区二区三区人妻在线视频| 亚洲.欧美.丝袜.中文.综合| 久久婷婷五月天| 88在线无码精品秘入口九色| 日韩av免费| 欧美特级黄| 国产成人精品视频免费| 苍井空精毛片精品久久久| 青娱乐欧美| 国产精品久久久久久久久久二区三区| 欧美性色网| 亚洲精品乱码久久久久久按摩观| 色婷婷在线影院| 狠狠色婷婷| 一区二区三区无码区| 国产高清免费视频| 色综合色综合色综合| 蜜臀一区二区三区| 香蕉福利网| 成人内射视频| 青青草视频免费观看| 成人在线国产| 无遮挡动态图| 一区二区三区成人电影| 无码人妻精品一区二区三区温州| 好吊妞在线| 嫩BBB槡BBBB槡BBB小号| 色婷婷在线观看视频| 五月激情黄色| 亚洲无码在线免费| 国产高清精品无码| 日本不卡在线视频| 大香蕉伊人操| 大屌色| 8090操逼网| 麻豆国产精品一区| 干B网| 高清国产mv在线观看| 毛片小电影| 亚洲V视频| 国产精品久免费的黄网站| 国产精品你懂的| 撸一撸免费视频| 激情视频网址| 精品成人影视| 国产A级毛片| 在线观看黄A片免费网站| 淫荡少妇美红久久久久久久久久 | 99热中文| 成人免费爱爱视频| 国产对白在线| 99er在线观看| 日韩a| 少妇高潮喷水| 久久久久国产一区二区三区四区| 麻豆国产91在线播放| 国产一级免费在线观看| 国产亚洲Av| 啪啪成人视频| 四虎成人网站| 靠逼网站免费观看| 影音先锋成人资源| 人人操人人干人人看| 国产成人AV免费观看| 欧美成人精品在线观看| 蝌蚪窝视频网| 黄色小视频免费观看| 日本久久久久| 中文字幕视频在线| 91麻豆精品国产91久久久久久| 99久热| 中国一级黄色毛片| 中文字幕永久在线视频v1.0| 日韩成人A片| 小黄片免费看| 欧美日韩成人电影| 亚洲男人的天堂网| 日韩操逼一区| 91亚洲国产AⅤ精品一区二区 | 足交在线观看| 黄片国产| 欧美18禁黄免费网站| 亚洲国产天堂| 91福利影院| 91工厂露脸熟女| 青青草公开视频| 无码不卡视频在线观看| 国产女人18毛片水18精| 日本视频在线免费| 日韩视频一区二区| 久久中文字幕视频| 久久久999精品视频| 99无码国产成人精品| 69久久成人精品| 欧美操B视频| 18禁无码永久免费网站大全| 很色很黄的A片一| 躁BBB躁BBB添BBBBBB| 人成在线观看| 日韩一级免费| 无码爱爱| 一区二区三区四区在线视频| 日本成人视频| 青在线视频| 午夜AV免费| 操逼视频免费在线观看| 成人午夜无码| 久久青留社区金玉| 色天天综合网| 蜜臀AV在线观看| AV天堂影视在线观看| 亚洲AV无码久久精品色无码蜜桃| 亚洲日韩精品成人无码专区AV| 亚洲高清在线视频| 奇米97| 免费AV网站在线| 在线黄色网| 久久久久成人精品无码| 国产婷婷五月天| 日韩视频一区二区三区| 内射| 国语A片| 特级西西WWW888| 色片无码| 国产AV无码一区| 中文字幕有码视频| 91人妻人人爽人人澡人人爽| 闺蜜AV| 日韩精品区| 久久久久久久久久国产| aaa国产精品| 国内老熟妇对白XXXXHD| 伊人大综合| 在线观看免费a片| 丁香六月婷婷久久综合| 欧美成人三级在线| 四虎成人在线| 亚洲中文字幕人妻。| 午夜无码在线| 骚逼综合网| 美女中文字幕| 无码在线免费观看视频| 亚洲成人影片在线观看| 国产3p绿帽骚妻视频| 波多野结衣毛片| www天天干| 黄片视频观看| 安徽妇搡BBBB搡BBBB,另类老妇| 色播五月婷婷| 在线国产91| 视频國产在线| 欧美日韩视频在线| 三级片在线网站| 爱就色色网| 人人妻人人操人人爱| 免费成人毛片| 精品无码一区二区三区的天堂| 午夜精品一区二区三区在线成人| 亚洲午夜福利| 日韩人妻在线视频| 日本中文字幕中文翻译歌词| 苏妲己一级婬片A片| 国产激情自拍| 欧美黄色毛片| 中文字幕巨肉乱码中文乱码 | 天堂a在线8| 91色色网| 99re视频在线| 影音先锋AV在线资源| 丁香五月天激情视频| 国产人妻一区二区三区欧美毛片| 亚洲精品免费观看| 豆花天天吃最新视频| 国产一区二区波多野结衣| 中文字幕三级av片| 特级西西444www高清| 欧美午夜成人一区二区三区 | 在线国产中文字幕| 免费av播放| 字幕一区二区久久人妻网站| 国产青青| 成人精品视频网站| 国产精品在线免费观看| 免费无码| 亚洲天堂免费视频| 黄色视频一级| 大香蕉这里只有精品| 亚洲AV久久无码| 内射午夜福利在线免费观看视频| 久久xx| 欧美一级婬片AAAAAA片| 免费的黄色视频在线观看| 女BBBBBB女BBB| 亚洲无码在线播放| 亚洲精品911| 中文字幕免费MV第一季歌词| 五月天激情片| 欧美日韩男女淫乱一区二区| 操逼无码视频| 站街大龄熟女x| 摸BBB搡BBB搡BBBB| 人人操97| 精品国产乱码一区二区| 九九热在线视频| 日韩成人黄色电影| 五月丁香婷婷色色| 久久超碰99| 三级片网站国产| 日韩99| 欧美黑吊大战白妞| 国产毛片在线视频| 亚洲三级电影在线观看| 一级a黄色片| 国产91白浆四溢| 国产三级在线播放| 五月婷婷六月天| 午夜AV电影| 久草欧美| 人妖和人妖互交性XXXX视频| 亚洲中文字幕在线观看视频网站| 小h片在线观看| 91久久国产综合久| 老司机一区二区三区| 丰滿人妻一区二区三| 天天干天天在线观看| 天天影视综合网免费观看电视剧国产 | 亚洲精品97久久中文字幕| 青娱乐偷拍视频| 人人爽爽| 国产激情综合在线| 91麻豆精品91久久久久同性| 成人毛片网站| 女人的天堂av| 黄色AV免费| av在线免费观看网址| 青青草黄色视频| 欧美性受XXXX黑人XYX性爽一 | 国产精品一卡二卡| 99re这里| 91无码人妻一区二区成人aⅴ| 国产AV电影网| 最新日韩中文字幕| 美女黄色视频永费在线观看网站| 国产黄色在线| 日韩免费无码| A级片在线观看| 特级艺体西西444WWw| 99热免费精品| 性免费网站| 国产人人爽| 免费成人在线网站| 成人在线观看AV| 欧美精产国品一二三| 操逼网站大全| 国产黄A| 91九色91蝌蚪91成人| 无码色| 婷婷五月综合中文字幕| 日韩AⅤ无码一区二区三区| 欧美精品xxx| 福利视频网亚洲| 久久AV电影| 久久久国产精品视频| 在线中文av| 亚洲一级AV| 亚洲无码一二三| 一区二区有限公司| 天堂在线9| 国产在线1| 人妻无码精品蜜桃| 麻豆视屏| 国产乱码| 中文字幕高清无码免费视频| 亚洲欧美综合| 欧美一区二区三区视频| 日韩欧美色图| 在线永久看片免费的视频| AV网站免费观看| 加勒比无码在线播放| a片免费在线| 久久成人网豆花视频| 91综合视频在线播放| 国产第页| AV电影在线免费观看| 日韩特黄片| 尤物视频网站在线观看| 亚洲国产另类精品| 日本人人操人人摸| 色情欧美一级A片| 超碰av在线| 天天久久综合| 天天干,夜夜操| 国产TS丝袜人妖系列视频| 国产又爽又黄A片| 无码一区二区视频| 日韩激情片| 四lll少妇BBBB槡BBBB| 中文字幕乱码中文字幕| 日本一区二区三区在线观看网站| 日韩免费中文字幕A片| 色婷婷久综合久久一本国产AV| 青娱乐日韩| 成人在线第一页| 伊人大香蕉精品| www.xxx| 色色网的五月天| 182AV| 日本免费在线黄色视频| 天天拍天天日| 午夜狠狠操| 大陆搡BBBBB搡BBBBBB| 16一17女人毛片| 思思精品在线| 嫩BBB搡BBBB搡BBBB| 3D精品啪啪一区二区免费| 18+免费网站| 香蕉视频免费| 亚洲情在线| 欧美理伦| 先锋久久资源| 国产高清精品在线| 色就是亚洲| 高清无码一区二区在线| 久久久午夜| 亚洲AV永久无码精品国产精| 黄色毛片在线播放| 五月天狠狠| 色香蕉在线视频| 国产一级黄色大片| 深爱激情综合网| 456成人| 91吴梦梦无码一区二区| 超碰在线人人爱| 超碰免费99| 91污视频在线观看| 麻豆91精品91久久久| 青娱乐精品在线| 天天看A片| 中文字幕精品人妻| 91在线无码精品秘入口国战| 精品有码| 三级在线观看视频| 国产性爱在线视频| 久久综合热| 成人视频一区二区三区| 日本精品一区二区三区四区的功能| 国模精品无码一区二区免费蜜桃 | 久久欧洲成人精品无码区| 欧美亚洲成人精品| 蜜桃导航-精品导航| 国产精品久久久91| 内射学生妹J亅| 狠狠肏视频| 久久久久99精品成人片直播| 日韩日韩日韩日韩日韩| 天天插天天拍| 91在线永久| 美日韩一区二区三区| 一区久久| 日韩欧美123| 人妻天天爽| 黑人操白人| 激情一区二区三区| 在线免费看黄片| 黄色成人网站在线观看| 国产非洲欧美在线| 亚洲成人免费在线视频| 特一级黄A片| 十八无码成人免费网站| 波多野结衣天堂| 中文字幕精品一区| 91丨九色丨熟女新版| 亚洲无码观看视频| A级片在线观看| 91探花视频精选在线播放| 亚洲午夜福利在线观看| 国产精品一级| 午夜亚洲国产一区视频网站| 人人爽亚洲AV人人爽AV人人片| 成人香蕉| 日韩欧美天堂| 一色综合| 中文字幕aV在线| 亚洲中文婷婷| 在线中文av| 无码A片| 国产成人电影| 国产成人精品视频免费看| 亚洲A片免费看| 一区二区免费在线观看| 日本免费不卡视频| 国产做爱视频| 日韩AV免费电影| 中文字幕在线观看免费高清电影| 久久精品熟妇丰满人妻99| 成人免费视频在线观看| 国产精品久久久一区二区三区 | 日本成人电影一区二区三区| 麻豆影音先锋| 日韩黄色无码视频| 奇米AV| 日韩三级视频| 日日操天天操夜夜操| 视频一区在线播放| 在线观看黄色网页| 综合色亚洲| 欧美在线一级| 久久无码一区| 成人喷水亚洲一区无码| 国产免费看| 日本少妇中文字幕| 蜜桃人妻无码AV天堂三区| 毛片A级| 97色色五月天| 成人A片在线观看| 99在线观看视频| 成人视频观看| 狠狠狠狠狠狠狠狠狠狠| 成人精品秘免费波多野结衣| 91久久综合| h片在线观看免费| 天天操综合网| 11孩岁女精品A片BBB| 高潮91PORN蝌蚪九色| 三级大香蕉| 久久综合五月天| 内射无码专区久久亚洲| 国产乱子伦真实精品| 免费看毛片中文字幕| 精品人人人| 亚洲免费看黄| 神马影院午夜福利| 亚洲精品免费观看| 中文字幕亚洲精品| 黄色a片网站| 亚洲成人午夜电影| 亚洲三级在线视频| 蜜桃AV在线| 亚洲激情小说| 在线播放日韩| 91久久超碰| 波多野结衣亚洲视频| 亚洲性爱网址| 四虎网站| 俺去了俺来也| 国产A级毛片久久久久久| 少妇高潮喷水视频| 草逼小视频| 国产午夜激情| 欧美在线va| 免费在线观看A| 巨爆乳肉感一区二区三区| a在线免费观看| 国产96在线亚洲| 日欧视频| 欧美性猛交XXXX乱大交HD| 亚洲成人AV在线观看| 91Av视频| 中文字幕乱码亚洲无线码按摩| 亚洲高清福利视频| 午夜久久电影| 尤物视频网| 欧美国产日韩综合在线观看170| 中日韩精品A片中文字幕| 九九黄色| www.777av| 国产激情AV| 国产精品视频你懂的| 欧美精品A片| 色欲综合网| 亚洲AV成人无码久久精品麻豆 | 美女高潮在线| 黄片小视频在线观看| 无码视频免费看| 天天躁狠狠躁av| 国产又爽又黄网站免费观看| 精品无码一区二区三区的天堂| 精品婷婷| 午夜国产精品AV| 亚洲深夜福利| 亚洲人妻无码一区| 激情在线视频| 欧美日本一区二区三区| 黄片网址大全| 翔田千里无码在线| 国产欧美一区二区| 性欧美丰满熟妇XXXX性久久久| 欧美四虎| 日本精品在线| 国产无套在线观看| 精品无码免费视频| 91社成人影院| 国产不卡在线| 日韩人妻无码网站| 97人妻一区二区精品视频| 久久久久久高清毛片一级| 无码视频在线免费观看| 水蜜桃成人在线| 三级片男人的天堂| 嫩草AV| 少妇人妻偷人精品无码视频新浪| 国产丰满大乳无码免费播放| 97爱爱爱| 一区二区三区视频在线观看| 精国产品一区二区三区A片| 俺也来www俺也色com| AV在线免费观看网站| 柒私黄片| 欧美亚洲操逼视频| 亚洲欧美国产视频| 蜜桃视频| 国产无限资源| 超碰97在线免费| 亚洲最大黄色| 精品无码一区二区三区四区五区| 国产精品国产三级国产专区53 | brazzers疯狂作爱| 日本一级特黄大片AAAAA级 | 免费黄色| 91女色| 国产无码操逼| 噜噜视频| 成人动漫免费观看| 江苏妇搡BBB搡BBBB| 99人妻视频| 中文字幕无吗| 免费观看操逼| 日本18禁网站| 日韩72页| 免费AV毛片| 五月天操逼网| 97天天操| 日韩精品一区二区三区中文在线| 伊人干综合| 人人操人人网站| www.婷婷六月天| 秋霞午夜成人无码精品| 日韩一级免费观看| 午夜精品久久久| 五月婷婷中文字幕| 日韩欧美高清无码| 日韩无码人妻一区二区| 丰臀肥逼高清视频电影播放| 伊人伊人网| 国产精品视频福利| 天天色色婷婷| 自拍偷拍图区| 激情乱伦五月天| 白峰美羽人妻AND-499| a一级黄片| 91色欲| 91精品国产乱码久久久久| 日操夜操| 亚洲无码人妻| 四虎综合网| 欧美性爱-熊猫成人网| 蝌蚪窝在线免费观看视频| 国产videos| 一级片在线观看视频| 日本黄色视频。| jjzz国产| 无码任你躁久久久久|