最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入解析桶排序算法及Node.js上JavaScript的代碼實(shí)現(xiàn)

 更新時(shí)間:2016年07月06日 18:05:33   投稿:goldensun  
桶排序Radix Sort算法利用分治思想將元素分入各桶中排序后匯總,以下我們就來(lái)深入解析桶排序算法及Node.js上JavaScript的代碼實(shí)現(xiàn),需要的朋友可以參考下

1. 桶排序介紹
桶排序(Bucket sort)是一種基于計(jì)數(shù)的排序算法,工作的原理是將數(shù)據(jù)分到有限數(shù)量的桶子里,然后每個(gè)桶再分別排序(有可能再使用別的排序算法或是以遞回方式繼續(xù)使用桶排序進(jìn)行排序)。當(dāng)要被排序的數(shù)據(jù)內(nèi)的數(shù)值是均勻分配的時(shí)候,桶排序時(shí)間復(fù)雜度為Θ(n)。桶排序不同于快速排序,并不是比較排序,不受到時(shí)間復(fù)雜度 O(nlogn) 下限的影響。
桶排序按下面4步進(jìn)行:
(1)設(shè)置固定數(shù)量的空桶。
(2)把數(shù)據(jù)放到對(duì)應(yīng)的桶中。
(3)對(duì)每個(gè)不為空的桶中數(shù)據(jù)進(jìn)行排序。
(4)拼接從不為空的桶中數(shù)據(jù),得到結(jié)果。
桶排序,主要適用于小范圍整數(shù)數(shù)據(jù),且獨(dú)立均勻分布,可以計(jì)算的數(shù)據(jù)量很大,而且符合線性期望時(shí)間。

2. 桶排序算法演示
舉例來(lái)說(shuō),現(xiàn)在有一組數(shù)據(jù)[7, 36, 65, 56, 33, 60, 110, 42, 42, 94, 59, 22, 83, 84, 63, 77, 67, 101],怎么對(duì)其按從小到大順序排序呢?

201676175211022.png (850×614)

操作步驟說(shuō)明:
(1)設(shè)置桶的數(shù)量為5個(gè)空桶,找到最大值110,最小值7,每個(gè)桶的范圍20.8=(110-7+1)/5 。
(2)遍歷原始數(shù)據(jù),以鏈表結(jié)構(gòu),放到對(duì)應(yīng)的桶中。數(shù)字7,桶索引值為0,計(jì)算公式為floor((7 – 7) / 20.8), 數(shù)字36,桶索引值為1,計(jì)算公式floor((36 – 7) / 20.8)。
(3)當(dāng)向同一個(gè)索引的桶,第二次插入數(shù)據(jù)時(shí),判斷桶中已存在的數(shù)字與新插入數(shù)字的大小,按照左到右,從小到大的順序插入。如:索引為2的桶,在插入63時(shí),桶中已存在4個(gè)數(shù)字56,59,60,65,則數(shù)字63,插入到65的左邊。
(4)合并非空的桶,按從左到右的順序合并0,1,2,3,4桶。
(5)得到桶排序的結(jié)構(gòu)

3. Nodejs程序?qū)崿F(xiàn)
像桶排序這種成熟的算法,自己實(shí)現(xiàn)一下并不難,按照上文的思路,我寫了一個(gè)簡(jiǎn)單的程序?qū)崿F(xiàn)。我感覺其中最麻煩的部分,是用Javascript操作鏈表。
現(xiàn)實(shí)代碼如下:

'use strict';

/////////////////////////////////////////////////
// 桶排序
/////////////////////////////////////////////////
var _this = this
  , L = require('linklist');//鏈表

/**
 * 普通數(shù)組桶排序,同步
 *
 * @param arr Array 整數(shù)數(shù)組
 * @param num 桶的個(gè)數(shù)
 *
 * @example:
 * sort([1,4,1,5,3,2,3,3,2,5,2,8,9,2,1],5)
 * sort([1,4,1,5,3,2,3,3,2,5,2,8,9,2,1],5,0,5)
 */
exports.sort = function (arr, count) {
  if (arr.length == 0) return [];
  count = count || (count > 1 ? count : 10);

  // 判斷最大值、最小值
  var min = arr[0], max = arr[0];
  for (var i = 1; i < arr.length; i++) {
    min = min < arr[i] ? min : arr[i];
    max = max > arr[i] ? max : arr[i];
  }
  var delta = (max - min + 1) / count;
  // console.log(min+","+max+","+delta);

  //初始化桶
  var buckets = [];

  //存儲(chǔ)數(shù)據(jù)到桶
  for (var i = 0; i < arr.length; i++) {
    var idx = Math.floor((arr[i] - min) / delta); // 桶索引

    if (buckets[idx]) {//非空桶
      var bucket = buckets[idx];
      var insert = false;//插入標(biāo)石
      L.reTraversal(bucket, function (item, done) {
        if (arr[i] <= item.v) {//小于,左邊插入
          L.append(item, _val(arr[i]));
          insert = true;
          done();//退出遍歷
        }
      });
      if (!insert) { //大于,右邊插入
        L.append(bucket, _val(arr[i]));
      }
    } else {//空桶
      var bucket = L.init();
      L.append(bucket, _val(arr[i]));
      buckets[idx] = bucket; //鏈表實(shí)現(xiàn)
    }
  }

  var result = [];
  for (var i = 0, j = 0; i < count; i++) {
    L.reTraversal(buckets[i], function (item) {
      // console.log(i+":"+item.v);
      result[j++] = item.v;
    });
  }
  return result;
}

//鏈表存儲(chǔ)對(duì)象
function _val(v) {
  return {v: v}
}

運(yùn)行程序:

var algo = require('./index.js');
var data = [ 7, 36, 65, 56, 33, 60, 110, 42, 42, 94, 59, 22, 83, 84, 63, 77, 67,101 ];
console.log(data);
console.log(algo.bucketsort.sort(data,5));//5個(gè)桶
console.log(algo.bucketsort.sort(data,10));//10個(gè)桶

輸出:

[ 7, 36, 65, 56, 33, 60, 110, 42, 42, 94, 59, 22, 83, 84, 63, 77, 67, 101 ]
[ 7, 22, 33, 36, 42, 42, 56, 59, 60, 63, 65, 67, 77, 83, 84, 94, 101, 110 ]
[ 7, 22, 33, 36, 42, 42, 56, 59, 60, 63, 65, 67, 77, 83, 84, 94, 101, 110 ]

需要說(shuō)明的是:

(1)桶內(nèi)排序,可以像程序中所描述的,在插入過(guò)程中實(shí)現(xiàn);也可以插入不排序,在合并過(guò)程中,再進(jìn)行排序,可以調(diào)用快度排序。
(2)鏈表,在Node的底層API中,有一個(gè)鏈表的實(shí)現(xiàn),我沒有直接使用,而是通過(guò)linklist包調(diào)用的:https://github.com/nodejs/node-v0.x-archive/blob/master/lib/_linklist.js

4. 案例:桶排序統(tǒng)計(jì)高考分?jǐn)?shù)
桶排序最出名的一個(gè)應(yīng)用場(chǎng)景,就是統(tǒng)計(jì)高考的分?jǐn)?shù)。一年的全國(guó)高考考生人數(shù)為900萬(wàn)人,分?jǐn)?shù)使用標(biāo)準(zhǔn)分,最低200 ,最高900 ,沒有小數(shù),如果把這900萬(wàn)數(shù)字進(jìn)行排序,應(yīng)該如何做呢?
算法分析:
(1)如果使用基于比較的排序,快速排序,平均時(shí)間復(fù)雜度為O(nlogn) = O(9000000*log9000000)=144114616=1.44億次比較。
(2)如果使用基于計(jì)數(shù)的排序,桶排序,平均的時(shí)候復(fù)雜度,可以控制在線性復(fù)雜度,當(dāng)創(chuàng)建700桶時(shí)從200分到900分各一個(gè)桶,O(N)=O(9000000),就相當(dāng)于掃描一次900W條數(shù)據(jù)。
我們跑一個(gè)程序,對(duì)比一次快速排序和桶排序。

//產(chǎn)生100W條,[200,900]閉區(qū)間的數(shù)據(jù)
var data = algo.data.randomData(1000*1000,200,900);
var s1 = new Date().getTime();
algo.quicksort.sort(data);//快速排序
var s2 = new Date().getTime();
algo.bucketsort.sort(data,700);//裝到700個(gè)桶
var s3 = new Date().getTime();

console.log("quicksort time: %sms",s2-s1);
console.log("bucket time: %sms",s3-s2);

輸出:

quicksort time: 14768ms
bucket time: 1089ms

所以,對(duì)于高考計(jì)分的案例來(lái)說(shuō),桶排序是更適合的!我們把合適的算法,用在適合的場(chǎng)景,會(huì)給程序帶來(lái)超越硬件的性能提升。

5. 桶排序代價(jià)分析
BUT....
桶排序利用函數(shù)的映射關(guān)系,減少了幾乎所有的比較工作。實(shí)際上,桶排序的f(k)值的計(jì)算,其作用就相當(dāng)于快排中劃分,已經(jīng)把大量數(shù)據(jù)分割成了基本有序的數(shù)據(jù)塊(桶)。然后只需要對(duì)桶中的少量數(shù)據(jù)做先進(jìn)的比較排序即可。
對(duì)N個(gè)關(guān)鍵字進(jìn)行桶排序的時(shí)間復(fù)雜度分為兩個(gè)部分:
(1) 循環(huán)計(jì)算每個(gè)關(guān)鍵字的桶映射函數(shù),這個(gè)時(shí)間復(fù)雜度是O(N)。
(2) 利用先進(jìn)的比較排序算法對(duì)每個(gè)桶內(nèi)的所有數(shù)據(jù)進(jìn)行排序,其時(shí)間復(fù)雜度為  ∑ O(Ni*logNi) 。其中Ni 為第i個(gè)桶的數(shù)據(jù)量。
 很顯然,第(2)部分是桶排序性能好壞的決定因素。盡量減少桶內(nèi)數(shù)據(jù)的數(shù)量是提高效率的唯一辦法(因?yàn)榛诒容^排序的最好平均時(shí)間復(fù)雜度只能達(dá)到O(N*logN)了)。因此,我們需要盡量做到下面兩點(diǎn):
(1) 映射函數(shù)f(k)能夠?qū)個(gè)數(shù)據(jù)平均的分配到M個(gè)桶中,這樣每個(gè)桶就有[N/M]個(gè)數(shù)據(jù)量。
(2) 盡量的增大桶的數(shù)量。極限情況下每個(gè)桶只能得到一個(gè)數(shù)據(jù),這樣就完全避開了桶內(nèi)數(shù)據(jù)的“比較”排序操作。 當(dāng)然,做到這一點(diǎn)很不容易,數(shù)據(jù)量巨大的情況下,f(k)函數(shù)會(huì)使得桶集合的數(shù)量巨大,空間浪費(fèi)嚴(yán)重。這就是一個(gè)時(shí)間代價(jià)和空間代價(jià)的權(quán)衡問(wèn)題了。
對(duì)于N個(gè)待排數(shù)據(jù),M個(gè)桶,平均每個(gè)桶[N/M]個(gè)數(shù)據(jù)的桶排序平均時(shí)間復(fù)雜度為:

O(N)+O(M*(N/M)*log(N/M))=O(N+N*(logN-logM))=O(N+N*logN-N*logM)

當(dāng)N=M時(shí),即極限情況下每個(gè)桶只有一個(gè)數(shù)據(jù)時(shí)。桶排序的最好效率能夠達(dá)到O(N)。

6. 總結(jié)
桶排序的平均時(shí)間復(fù)雜度為線性的O(N+C),其中C=N*(logN-logM)。如果相對(duì)于同樣的N,桶數(shù)量M越大,其效率越高,最好的時(shí)間復(fù)雜度達(dá)到O(N)。 當(dāng)然桶排序的空間復(fù)雜度 為O(N+M),如果輸入數(shù)據(jù)非常龐大,而桶的數(shù)量也非常多,則空間代價(jià)無(wú)疑是昂貴的。此外,桶排序是穩(wěn)定的。
 其實(shí)我個(gè)人還有一個(gè)感受:在查找算法中,基于比較的查找算法最好的時(shí)間復(fù)雜度也是O(logN)。比如折半查找、平衡二叉樹、紅黑樹等。但是Hash表卻有O(C)線性級(jí)別的查找效率(不沖突情況下查找效率達(dá)到O(1))。大家好好體會(huì)一下:Hash表的思想和桶排序是不是有一曲同工之妙呢?

相關(guān)文章

  • NodeJS中的命令行程序、工程目錄、NPM

    NodeJS中的命令行程序、工程目錄、NPM

    使用NodeJS編寫的東西,要么是一個(gè)包,要么是一個(gè)命令行程序,而前者最終也會(huì)用于開發(fā)后者,一般我們會(huì)同時(shí)提供命令行模式和API模式兩種使用方式,并且我們會(huì)借助三方包來(lái)編寫代碼,NPM是隨同NodeJS一起安裝的包管理工具,能解決NodeJS代碼部署上的很多問(wèn)題
    2023-11-11
  • NodeJS去除BOM和轉(zhuǎn)換UTF8編碼

    NodeJS去除BOM和轉(zhuǎn)換UTF8編碼

    使用NodeJS編寫前端工具時(shí),操作得最多的是文本文件,但遺憾的是,GBK編碼不在NodeJS自身支持范圍內(nèi),UTF8文件還可能帶有BOM,在讀取不同編碼的文本文件時(shí),需要將文件內(nèi)容轉(zhuǎn)換為JS使用的UTF8編碼字符串后才能正常處理
    2023-11-11
  • 通過(guò)實(shí)例了解Nodejs模塊系統(tǒng)及require機(jī)制

    通過(guò)實(shí)例了解Nodejs模塊系統(tǒng)及require機(jī)制

    這篇文章主要介紹了通過(guò)實(shí)例了解Nodejs模塊系統(tǒng)及require機(jī)制,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • nodejs和C語(yǔ)言插入mysql數(shù)據(jù)庫(kù)亂碼問(wèn)題的解決方法

    nodejs和C語(yǔ)言插入mysql數(shù)據(jù)庫(kù)亂碼問(wèn)題的解決方法

    這篇文章主要介紹了nodejs和C語(yǔ)言插入mysql數(shù)據(jù)庫(kù)亂碼問(wèn)題,需要的朋友可以參考下
    2017-04-04
  • yarn與npm的命令行小結(jié)

    yarn與npm的命令行小結(jié)

    想必最近大家對(duì)新的JavaScript包管理工具yarn已經(jīng)有所耳聞,并已通過(guò)npm i -g yarn進(jìn)行了安裝,現(xiàn)在想知道怎么樣使用嗎?如果你了解 npm,你已經(jīng)會(huì)很大一部分啦!下面是這篇文章從npm切換到y(tǒng)arn的一些筆記。有需要的朋友們可以參考借鑒。下面來(lái)一起看看吧。
    2016-10-10
  • node.js安裝及環(huán)境配置超詳細(xì)步驟講解(Windows系統(tǒng)安裝包方式)

    node.js安裝及環(huán)境配置超詳細(xì)步驟講解(Windows系統(tǒng)安裝包方式)

    這篇文章主要介紹了node.js安裝及環(huán)境配置超詳細(xì)教程(Windows系統(tǒng)安裝包方式),本文分步驟通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-02-02
  • Node.js的項(xiàng)目構(gòu)建工具Grunt的安裝與配置教程

    Node.js的項(xiàng)目構(gòu)建工具Grunt的安裝與配置教程

    Grunt是為Node打造的項(xiàng)目構(gòu)建工具,相當(dāng)于C/C++世界中的makefile,可以執(zhí)行像壓縮、編譯、單元測(cè)試、代碼檢查以及打包發(fā)布的任務(wù),下面我們就來(lái)一起看一下Node.js的項(xiàng)目構(gòu)建工具Grunt的安裝與配置教程:
    2016-05-05
  • NodeJS中配置請(qǐng)求代理服務(wù)器方式

    NodeJS中配置請(qǐng)求代理服務(wù)器方式

    這篇文章主要介紹了NodeJS中配置請(qǐng)求代理服務(wù)器方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • nodejs+express實(shí)現(xiàn)文件上傳下載管理網(wǎng)站

    nodejs+express實(shí)現(xiàn)文件上傳下載管理網(wǎng)站

    這篇文章主要為大家詳細(xì)介紹了nodejs+express實(shí)現(xiàn)文件上傳下載管理的網(wǎng)站,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • node.js中的fs.appendFile方法使用說(shuō)明

    node.js中的fs.appendFile方法使用說(shuō)明

    這篇文章主要介紹了node.js中的fs.appendFile方法使用說(shuō)明,本文介紹了fs.appendFile方法說(shuō)明、語(yǔ)法、接收參數(shù)、使用實(shí)例和實(shí)現(xiàn)源碼,需要的朋友可以參考下
    2014-12-12

最新評(píng)論

太湖县| 临夏县| 柘荣县| 九龙坡区| 深水埗区| 麻城市| 凤凰县| 田林县| 内江市| 右玉县| 珲春市| 微博| 贵溪市| 聂拉木县| 墨玉县| 崇左市| 开化县| 招远市| 百色市| 彩票| 成都市| 龙陵县| 东阿县| 闻喜县| 谢通门县| 台南市| 柳河县| 新源县| 凭祥市| 大渡口区| 江口县| 岱山县| 修文县| 友谊县| 天水市| 东宁县| 太湖县| 高安市| 巴中市| 图木舒克市| 广昌县|