JS中的算法與數(shù)據(jù)結(jié)構(gòu)——隊(duì)列(Queue)

隊(duì)列(Queue)

我們之前說到了,它是一種比較高效的數(shù)據(jù)結(jié)構(gòu)允华,遵循 先入后出(LIFO圈浇,last-in-first-out) 的原則。而今天我們要討論的隊(duì)列靴寂,它也是一種特殊的列表磷蜀,它與棧不同的是, 隊(duì)列只能在隊(duì)尾插入元素百炬,在隊(duì)首刪除元素褐隆,就像我們平時(shí)排隊(duì)買票一樣~

隊(duì)列用于存儲按順序排列的數(shù)據(jù),遵循 先進(jìn)先出(FIFO剖踊,F(xiàn)irst-In-First-Out) 的原則庶弃,也是計(jì)算機(jī)常用的一種數(shù)據(jù)結(jié)構(gòu),別用于很多地方德澈,比如提交給操作系統(tǒng)的一系列進(jìn)程歇攻,打印池任務(wù)等。

同棧有點(diǎn)類似梆造,隊(duì)列的操作主要也是有兩種:向隊(duì)列中插入新元素和刪除隊(duì)列中的元素缴守,即入隊(duì)和出隊(duì)操作,我們采用 enqueue 和 dequeue 兩個方法。

除此之外屡穗,隊(duì)列還有一些其他的操作贴捡,比如讀取隊(duì)首的元素,該操作僅返回對頭元素并不將它從隊(duì)列中刪除村砂,類似棧的 peek 方法栈暇;back 方法讀取隊(duì)尾的元素;toString 方法可以打印當(dāng)前隊(duì)列中所有的元素箍镜;clear 方法清空當(dāng)前隊(duì)列等。

隊(duì)列數(shù)據(jù)定義

我們定義好數(shù)據(jù)類型煎源,可以通過JS中的數(shù)組去實(shí)現(xiàn)它色迂。

隊(duì)列的實(shí)現(xiàn)

//定義隊(duì)列

function Queue(){
    this.dataStore = [];
    this.enqueue = enqueue;     //入隊(duì)
    this.dequeue = dequeue;     //出隊(duì)
    this.front = front;         //查看隊(duì)首元素
    this.back = back;           //查看隊(duì)尾元素
    this.toString = toString;   //顯示隊(duì)列所有元素
    this.clear = clear;         //清空當(dāng)前隊(duì)列
    this.empty = empty;         //判斷當(dāng)前隊(duì)列是否為空
}

我們先來實(shí)現(xiàn)入隊(duì)操作:

enqueue:向隊(duì)列添加元素

//向隊(duì)列末尾添加一個元素,直接調(diào)用 push 方法即可

function enqueue ( element ) {
    this.dataStore.push( element );
}

因?yàn)镴S中的數(shù)組具有其他語言沒有的有點(diǎn)手销,可以直接利用 shift 方法刪除數(shù)組的第一個元素歇僧,因此,出隊(duì)操作的實(shí)現(xiàn)就變得很簡單了锋拖。

dequeue:刪除隊(duì)首的元素

//刪除隊(duì)列首的元素诈悍,可以利用 JS 數(shù)組中的 shift 方法

function dequeue () {
    if( this.empty() ) return 'This queue is empty';
    else this.dataStore.shift();
}

我們注意的,上面我做了一個判斷兽埃,隊(duì)列是否還有元素侥钳,因?yàn)槿h除空隊(duì)列的元素是沒有意義的,那么柄错,我們就來看看 empty 方法是如何實(shí)現(xiàn)的舷夺。

empty:判斷隊(duì)列是否為空

//我們通過判斷 dataStore 的長度就可知道隊(duì)列是否為空

function empty(){
    if( this.dataStore.length == 0 ) return true;
    else return false;
}

我們先來看看測試一下這幾個方法,

var queue = new Queue();

console.log( queue.empty() );       //true

//添加幾個元素
queue.enqueue('Apple');
queue.enqueue('Banana');
queue.enqueue('Pear');

console.log( queue.empty() );       // false

現(xiàn)在售貌,我不知道誰在第一個给猾,誰是最后一個,我們可以利用 front 和 back 方法分別來查看颂跨,

front:查看隊(duì)首元素

//查看隊(duì)首元素敢伸,直接返回?cái)?shù)組首個元素即可

function front(){
    if( this.empty() ) return 'This queue is empty';
    else return this.dataStore[0];
}

back:查看隊(duì)尾元素

//查看隊(duì)首元素恒削,直接返回?cái)?shù)組最后一個元素即可

//讀取隊(duì)列尾的元素
function back () {
    if( this.empty() ) return 'This queue is empty';
    else return this.dataStore[ this.dataStore.length - 1 ];
}

我們先看看對不對:

//查看隊(duì)首元素
console.log( queue.front() );  // Apple
//查看隊(duì)尾元素  
console.log( queue.back() );   // Pear

//出隊(duì)
queue.dequeue();

//查看隊(duì)首元素
console.log( queue.front() );  // Banana
//查看隊(duì)尾元素  
console.log( queue.back() );   // Pear

沒問題池颈!現(xiàn)在,我想看看钓丰,總共有多少水果饶辙,toString方法來實(shí)現(xiàn),

toString:查看隊(duì)列中所有元素

//查看對了所有元素斑粱,我這里采用數(shù)組的 join 方法實(shí)現(xiàn)

function toString(){
    return this.dataStore.join('\n');
}

現(xiàn)在弃揽,你可以看看你還有什么水果沒吃的了,

console.log( queue.toString() )     //  Apple
                                    //  Banana
                                    //  Pear

我們就剩下一個 clear 方法了,如果你已經(jīng)把所有水果都吃完了,那么你應(yīng)該使用 clear 方法矿微,

//清空當(dāng)前隊(duì)列痕慢,也很簡單,我們直接將 dataStore 數(shù)值清空即可

function clear(){
    delete this.dataStore;
    this.dataStor = [];
}

至此涌矢,我們已經(jīng)用JS實(shí)現(xiàn)了一個隊(duì)列掖举,怎么樣,是不是覺得JS的數(shù)組超級好用娜庇,省去了不少麻煩塔次,有木有!名秀!

//清空隊(duì)列

queue.clear();

console.log( queue.empty() );    // true

下面励负,我們利用隊(duì)列來實(shí)現(xiàn)基數(shù)排序。

基數(shù)排序(radix sort)屬于“分配式排序”(distribution sort)匕得,它是透過鍵值的部份資訊继榆,將要排序的元素分配至某些“桶”中,藉以達(dá)到排序的作用汁掠,基數(shù)排序法是屬于穩(wěn)定性的排序略吨,其時(shí)間復(fù)雜度為O (nlog(r)m),其中r為所采取的基數(shù)考阱,而m為堆數(shù)翠忠,在某些時(shí)候,基數(shù)排序法的效率高于其它的穩(wěn)定性排序法乞榨。

先看一下基數(shù)排序的的實(shí)現(xiàn)步驟(以兩位數(shù)為例)负间,需要掃描兩次,第一次按個位數(shù)字進(jìn)行排序姜凄,第二次按十位數(shù)字排序政溃,每個數(shù)字根據(jù)對應(yīng)的數(shù)值分配到到不同的盒子里,最后將盒子的數(shù)字依次取出态秧,組成新的列表即為排序好的數(shù)字董虱。

  1. 假設(shè)我們有一串?dāng)?shù)字,分別為 73, 22, 93, 43, 55, 14, 28, 65, 39, 81
  2. 首先根據(jù)個位數(shù)字排序申鱼,放到不同的盒子里愤诱,如下圖


    第一次排序
  3. 接下來將這些盒子中的數(shù)值重新串接起來,成為以下的數(shù)列:81, 22, 73, 93, 43, 14, 55, 65, 28, 39
  4. 然后根據(jù)十位數(shù)字排序,再放到不同的盒子里,如下圖


    第二次排序
  5. 接下來將這些盒子中的數(shù)值重新串接起來享潜,整個數(shù)列已經(jīng)排序完畢:14, 22, 28, 39, 43, 55, 65, 73, 81, 93

我們已經(jīng)了解了基數(shù)排序的算法思想沾鳄,接著我們要結(jié)合隊(duì)列去實(shí)現(xiàn)它帮匾,一起來看看吧奖慌。

//基數(shù)排序

var queues = [];    //定義隊(duì)列數(shù)組
var nums = [];      //定義數(shù)字?jǐn)?shù)組

//選十個0~99的隨機(jī)數(shù)進(jìn)行排序
for ( var i = 0 ; i < 10 ; i ++ ){
    queues[i] = new Queue();
    nums[i] = Math.floor( Math.random() * 101 );
}

//排序之前
console.log( 'before radix sort: ' + nums );

//基數(shù)排序
distribution( nums , queues , 10 , 1 );
collect( queues , nums );
distribution( nums , queues , 10 , 10 );
collect( queues , nums );

//排序之后
console.info('after radix sort: ' + nums );

//根據(jù)相應(yīng)的(個位和十位)數(shù)值昼窗,將數(shù)字分配到相應(yīng)隊(duì)列

function distribution ( nums , queues , n , digit ) {  //digit表示個位或者十位的值
    for( var i = 0 ; i < n ; i++ ){
        if( digit == 1){
            queues[ nums[i] % 10 ].enqueue( nums[i] );
        }else{
            queues[ Math.floor( nums[i] / 10 ) ].enqueue( nums[i] );
        }
    }
}

//從隊(duì)列中收集數(shù)字

function collect ( queues , nums ) {
    var i = 0;
    for ( var digit = 0 ; digit < 10 ; digit ++ ){
        while ( !queues[digit].empty() ){
            nums[ i++ ] = queues[digit].front();
            queues[digit].dequeue();
        }
    }
}

我這里貼出兩組測試的結(jié)果累颂,大家自己動手實(shí)踐一下对人。

//第一組測試

before radix sort: 23,39,2,67,90,41,47,21,98,13
after radix sort: 2,13,21,23,39,41,47,67,90,98

//第二組測試

before radix sort: 29,62,38,16,55,26,33,54,76,65
after radix sort: 16,26,29,33,38,54,55,62,65,76

至此谣殊,我們隊(duì)列也就告一段落了,大家還可以往深入拓展牺弄,比如優(yōu)先隊(duì)列姻几,循環(huán)隊(duì)列等,希望大家能發(fā)散思維势告,多動手實(shí)踐蛇捌,一起加油!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末咱台,一起剝皮案震驚了整個濱河市络拌,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌吵护,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件表鳍,死亡現(xiàn)場離奇詭異馅而,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)譬圣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進(jìn)店門瓮恭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人厘熟,你說我怎么就攤上這事屯蹦。” “怎么了绳姨?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵登澜,是天一觀的道長。 經(jīng)常有香客問我飘庄,道長脑蠕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任跪削,我火速辦了婚禮谴仙,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘碾盐。我一直安慰自己晃跺,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布毫玖。 她就那樣靜靜地躺著掀虎,像睡著了一般凌盯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上涩盾,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天十气,我揣著相機(jī)與錄音,去河邊找鬼春霍。 笑死砸西,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的址儒。 我是一名探鬼主播芹枷,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼莲趣!你這毒婦竟也來了鸳慈?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤喧伞,失蹤者是張志新(化名)和其女友劉穎走芋,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體潘鲫,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡翁逞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了溉仑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挖函。...
    茶點(diǎn)故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖浊竟,靈堂內(nèi)的尸體忽然破棺而出怨喘,到底是詐尸還是另有隱情,我是刑警寧澤振定,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布必怜,位于F島的核電站,受9級特大地震影響后频,放射性物質(zhì)發(fā)生泄漏棚赔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一徘郭、第九天 我趴在偏房一處隱蔽的房頂上張望靠益。 院中可真熱鬧,春花似錦残揉、人聲如沸胧后。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽壳快。三九已至纸巷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間眶痰,已是汗流浹背瘤旨。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留竖伯,地道東北人存哲。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像七婴,于是被迫代替她去往敵國和親祟偷。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評論 2 355

推薦閱讀更多精彩內(nèi)容