溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何在JS中實現(xiàn)排序和搜索算法

發(fā)布時間:2020-07-10 14:52:20 來源:億速云 閱讀:158 作者:Leah 欄目:web開發(fā)

如何在JS中實現(xiàn)排序和搜索算法?很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。

一、準備

在進入正題之前,先準備幾個基礎(chǔ)的函數(shù)

(1)交換數(shù)組兩個元素

function swap(arr, sourceIndex, targetIndex) {
  let temp = arr[sourceIndex];
  arr[sourceIndex] = arr[targetIndex];
  arr[targetIndex] = temp;
}

(2)快速生成0~N的數(shù)組

function createArr(length) {
  return Array.from({length}, (_, i) => i);
}

(3)洗牌函數(shù)

洗牌函數(shù)可快速打亂數(shù)組,常見的用法如切換音樂播放順序

function shuffle(arr) {
  for (let i = 0; i < arr.length; i += 1) {
    const rand = Math.floor(Math.random() * (i + 1));
    if (rand !== i) {
      swap(arr, i, rand);
    }
  }
  return arr;
}

二、排序

常見排序算法可以分為兩大類:

  • 比較類排序:通過比較來決定元素間的相對次序,由于其時間復(fù)雜度不能突破O(nlogn),因此也稱為非線性時間比較類排序
  • 非比較類排序:不通過比較來決定元素間的相對次序,它可以突破基于比較排序的時間下界,以線性時間運行,因此也稱為線性時間非比較類排序

如何在JS中實現(xiàn)排序和搜索算法

在本篇文章中,僅對比較類排序的幾種排序方式進行學(xué)習(xí)介紹

2.1 冒泡排序

冒泡排序是所有排序算法中最簡單的,通常也是我們學(xué)習(xí)排序的入門方法。但是,從運行時間的角度來看,冒泡排序是最差的一種排序方式。

核心:比較任何兩個相鄰的項,如果第一個比第二個大,則交換它們。元素項向上移動至正確的順序,就好像氣泡升至表面一樣,冒泡排序因而得名

動圖:

如何在JS中實現(xiàn)排序和搜索算法

注意:第一層遍歷找出剩余元素的最大值,至指定位置【依次冒泡出最大值】

代碼:

function bubbleSort(arr) {
  const len = arr.length;
  for (let i = 0; i < len; i += 1) {
    for (let j = 0; j < len - 1 - i; j += 1) {
      if (arr[j] > arr[j + 1]) { // 比較相鄰元素
        swap(arr, j, j + 1);
      }
    }
  }
  return arr;
}

2.2 選擇排序

選擇排序是一種原址比較排序算法。

核心:首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再從剩余未排序元素中繼續(xù)尋找最小元素,然后放到已排序序列的末尾。以此類推,直到所有元素均排序完畢

動圖:

如何在JS中實現(xiàn)排序和搜索算法

注意:第一層遍歷找出剩余元素最小值的索引,然后交換當前位置和最小值索引值【依次找到最小值】

代碼:

function selectionSort(arr) {
  const len = arr.length;
  let minIndex;
  for (let i = 0; i < len - 1; i += 1) {
    minIndex = i;
    for (let j = i + 1; j < len; j += 1) {
      if (arr[i] > arr[j]) {
        minIndex = j; // 尋找最小值對應(yīng)的索引
      }
    }
    if (minIndex === i) continue;
    swap(arr, minIndex, i);
  }
  return arr;
}

2.3 插入排序

插入排序的比較順序不同于冒泡排序和選擇排序,插入排序的比較順序是當前項向前比較。

核心:通過構(gòu)建有序序列,對于未排序數(shù)據(jù),在已排序序列中從后向前掃描,找到相應(yīng)位置并插入

動圖:

如何在JS中實現(xiàn)排序和搜索算法

注意:從第二項開始,依次向前比較,保證當前項以前的序列是順序排列

代碼:

function insertionSort(arr) {
  const len = arr.length;
  let current, pointer;
  for (let i = 1; i < len; i += 1) {
    current = arr[i];
    pointer = i;
    while(pointer >= 0 && current < arr[pointer - 1]) { // 每次向前比較
      arr[pointer] = arr[pointer - 1]; // 前一項大于指針項,則向前移動一項
      pointer -= 1;
    }
    arr[pointer] = current; // 指針項還原成當前項
  }
  return arr;
}

2.4 歸并排序

歸并排序和快速排序相較于上面三種排序算法在實際中更具有可行性(在第四小節(jié)我們會通過實踐復(fù)雜度來比較這幾種排序算法)

JavaScriptArray類定義了一個sort函數(shù)(Array.prototype.sort)用以排序JavaScript數(shù)組。ECMAScript沒有定義用哪個排序算法,所以瀏覽器廠商可以自行去實現(xiàn)算法。例如,Mozilla Firefox使用歸并排序作為Array.prototype.sort的實現(xiàn),而Chrome使用了一個快速排序的變體

歸并排序是一種分治算法。其思想是將原始數(shù)組切分成較小的數(shù)組,直到每個小數(shù)組只有一 個位置,接著將小數(shù)組歸并成較大的數(shù)組,直到最后只有一個排序完畢的大數(shù)組。因此需要用到遞歸

核心:歸并排序,拆分成左右兩塊數(shù)組,分別排序后合并

動圖:

如何在JS中實現(xiàn)排序和搜索算法

注意:遞歸中最小的左右數(shù)組比較為單個元素的數(shù)組,因此在較上層多個元素對比時,左右兩個數(shù)組一定是順序的

代碼:

function mergeSort(arr) {
  const len = arr.length;

  if (len < 2) return arr; // 遞歸的終止條件
  const middle = Math.floor(len / 2); // 拆分左右數(shù)組
  const left = arr.slice(0, middle);
  const right = arr.slice(middle);
  
  return merge(mergeSort(left), mergeSort(right));
}

function merge(left, right) { // 將左右兩側(cè)比較后進行合并
  const ret = [];

  while (left.length && right.length) {
    if (left[0] > right[0]) {
      ret.push(right.shift());
    } else {
      ret.push(left.shift());
    }
  }

  while (left.length) {
    ret.push(left.shift());
  }
  while (right.length) {
    ret.push(right.shift());
  }

  return ret;
}

2.5 快速排序

快速排序也許是最常用的排序算法了。它的復(fù)雜度為O(nlogn),且它的性能通常比其他的復(fù) 雜度為O(nlogn)的排序算法要好。和歸并排序一樣,快速排序也使用分治的方法,將原始數(shù)組分為較小的數(shù)組

核心:分治算法,以參考值為界限,將比它小的和大的值拆開

動圖:

如何在JS中實現(xiàn)排序和搜索算法

注意:每一次遍歷篩選出比基準點小的值

代碼:

function quickSort(arr, left = 0, right = arr.length - 1) {
  // left和right默認為數(shù)組首尾
  if (left < right) {
    let partitionIndex = partition(arr, left, right);
    quickSort(arr, left, partitionIndex - 1);
    quickSort(arr, partitionIndex + 1, right);
  }
  return arr;
}

function partition(arr, left, right) {
  let pivot = left;
  let index = left + 1; // 滿足比較條件的依次放在分割點后

  for (let i = index; i <= right; i += 1) {
    if (arr[i] < arr[pivot]) {
      swap(arr, i, index);
      index += 1;
    }
  }
  swap(arr, index - 1, pivot); // 交換順序時,以最后一位替換分隔項
  return index - 1;
}

三、搜索算法

3.1 順序搜索

順序或線性搜索是最基本的搜索算法。它的機制是,將每一個數(shù)據(jù)結(jié)構(gòu)中的元素和我們要找的元素做比較。順序搜索是最低效的一種搜索算法。

function findItem(item, arr) {
  for (let i = 0; i < arr.length; i += 1) {
    if (item === arr[i]) {
      return i;
    }
  }
  return -1;
}

3.2 二分搜索

二分搜索要求被搜索的數(shù)據(jù)結(jié)構(gòu)已排序。以下是該算法遵循的步驟:

  1. 選擇數(shù)組的中間值
  2. 如果選中值是待搜索值,那么算法執(zhí)行完畢
  3. 如果待搜索值比選中值要小,則返回步驟1在選中值左邊的子數(shù)組中尋找
  4. 如果待搜索值比選中值要大,則返回步驟1在選中值右邊的子數(shù)組中尋找
function binarySearch(item, arr) {
  arr = quickSort(arr); // 排序

  let low = 0;
  let high = arr.length - 1;
  let mid;

  while (low <= high) {
    min = Math.floor((low + high) / 2);
    if (arr[mid] < item) {
      low = mid + 1;
    } else if (arr[mid] > item) {
      high = mid - 1;
    } else {
      return mid;
    }
  }
  return -1;
}

四、算法復(fù)雜度

4.1 理解大O表示法

大O表示法用于描述算法的性能和復(fù)雜程度。分析算法時,時常遇到一下幾類函數(shù)

如何在JS中實現(xiàn)排序和搜索算法

(1)O(1)

function increment(num){
    return ++num;
}

執(zhí)行時間和參數(shù)無關(guān)。因此說,上述函數(shù)的復(fù)雜度是O(1)(常數(shù))

(2)O(n)

順序搜索函數(shù)為例,查找元素需要遍歷整個數(shù)組,直到找到該元素停止。函數(shù)執(zhí)行的總開銷取決于數(shù)組元素的個數(shù)(數(shù)組大小),而且也和搜索的值有關(guān)。但是函數(shù)復(fù)雜度取決于最壞的情況:如果數(shù)組大小是10,開銷就是10;如果數(shù)組大小是1000,開銷就是1000。這種函數(shù)的時間復(fù)雜度是O(n),n是(輸入)數(shù)組的大小

(3)O(n2)

冒泡排序為例,在未優(yōu)化的情況下,每次排序均需進行n*n次執(zhí)行。時間復(fù)雜度為O(n2)

時間復(fù)雜度O(n)的代碼只有一層循環(huán),而O(n2)的代碼有雙層嵌套循環(huán)。如 果算法有三層遍歷數(shù)組的嵌套循環(huán),它的時間復(fù)雜度很可能就是O(n3)

4.2 時間復(fù)雜度比較

(1)常用數(shù)據(jù)結(jié)構(gòu)時間復(fù)雜度

如何在JS中實現(xiàn)排序和搜索算法

(2)排序算法時間復(fù)雜度

如何在JS中實現(xiàn)排序和搜索算法

看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進一步的了解或閱讀更多相關(guān)文章,請關(guān)注億速云行業(yè)資訊頻道,感謝您對億速云的支持。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI