摘要:棧不管是在哪個(gè)語(yǔ)言,,還有咱們的都有這個(gè)數(shù)據(jù)結(jié)構(gòu),很多從別的行業(yè)轉(zhuǎn)開(kāi)發(fā)的朋友都會(huì)經(jīng)過(guò)這個(gè)學(xué)習(xí)過(guò)程。新添加的或待刪除的元素都保存在棧的同一端,稱作棧頂,另一端就叫棧底。移除棧頂?shù)脑?,同時(shí)返回被移除的元素。
棧:不管是在哪個(gè)語(yǔ)言,c/c++,java,python,還有咱們的javascript都有這個(gè)數(shù)據(jù)結(jié)構(gòu),很多從別的行業(yè)轉(zhuǎn)開(kāi)發(fā)的朋友都會(huì)經(jīng)過(guò)這個(gè)學(xué)習(xí)過(guò)程。
棧:一種遵從后進(jìn)先出(LIFO)原則的有序集合。新添加的或待刪除的元素都保存在棧的
同一端,稱作棧頂,另一端就叫棧底。在棧里,新元素都靠近棧頂,舊元素都接近棧底。
在現(xiàn)實(shí)生活中也能發(fā)現(xiàn)很多棧的例子。例如,下圖里的一摞書(shū)或者餐廳里堆放的盤子。
棧也被用在編程語(yǔ)言的編譯器和內(nèi)存中保存變量、方法調(diào)用等。
先熟悉一下棧的一些方法:
push(element(s)) :添加一個(gè)(或幾個(gè))新元素到棧頂。 pop() :移除棧頂?shù)脑?,同時(shí)返回被移除的元素。 peek() :返回棧頂?shù)脑?,不?duì)棧做任何修改(這個(gè)方法不會(huì)移除棧頂?shù)脑?,僅僅返回它)。 isEmpty() :如果棧里沒(méi)有任何元素就返回 true ,否則返回 false 。 clear() :移除棧里的所有元素。 size() :返回棧里的元素個(gè)數(shù)。這個(gè)方法和數(shù)組的 length 屬性很類似。
class Stack { constructor () { this.items = []; //{1} } push(element) { this.items.push(element); } pop() { this.items.pop(); } peek() { return items[items.length-1]; } isEmpty() { return items.length == 0; } size() { return items.length; } clear() { items = []; } print() { console.log(items); } }
盡管代碼看起來(lái)更簡(jiǎn)潔、更漂亮,變量 items 卻是公共的。ES6的類是基于原型的。雖然基
于原型的類比基于函數(shù)的類更節(jié)省內(nèi)存,也更適合創(chuàng)建多個(gè)實(shí)例,卻不能夠聲明私有屬性(變量)
或方法。而且,在這種情況下,我們希望 Stack 類的用戶只能訪問(wèn)暴露給類的方法。否則,就有
可能從棧的中間移除元素(因?yàn)槲覀冇脭?shù)組來(lái)存儲(chǔ)其值),這不是我們希望看到的。
1. 用ES6的限定作用域 Symbol 實(shí)現(xiàn)類
ES6新增了一種叫作 Symbol 的基本類型,它是不可變的,可以用作對(duì)象的屬性??纯丛趺从?br>它來(lái)在 Stack 類中聲明 items 屬性:
let _items = Symbol(); //{1} class Stack { constructor () { this[_items] = []; //{2} } //Stack方法 }
在上面的代碼中,我們聲明了 Symbol 類型的變量 _items (行 {1} ),在類的 constructor 函
數(shù)中初始化它的值(行 {2} )。要訪問(wèn) _items ,只需把所有的 this.items 都換成 this[_items] 。
這種方法創(chuàng)建了一個(gè)假的私有屬性,因?yàn)镋S6新增的 Object.getOwnPropertySymbols 方
法能夠取到類里面聲明的所有 Symbols 屬性。下面是一個(gè)破壞 Stack 類的例子:
let stack = new Stack(); stack.push(5); stack.push(8); let objectSymbols = Object.getOwnPropertySymbols(stack); console.log(objectSymbols.length); // 1 console.log(objectSymbols); // [Symbol()] console.log(objectSymbols[0]); // Symbol() stack[objectSymbols[0]].push(1); stack.print(); // 輸出 5, 8, 1
從以上代碼可以看到,訪問(wèn) stack[objectSymbols[0]] 是可以得到 _items 的。并且,
_items 屬性是一個(gè)數(shù)組,可以進(jìn)行任意的數(shù)組操作,比如從中間刪除或添加元素。我們操作的
是棧,不應(yīng)該出現(xiàn)這種行為。
2. 用ES6的 WeakMap 實(shí)現(xiàn)類
有一種數(shù)據(jù)類型可以確保屬性是私有的,這就是 WeakMap 。我們會(huì)在第7章深入探討 Map 這
種數(shù)據(jù)結(jié)構(gòu),現(xiàn)在只需要知道 WeakMap 可以存儲(chǔ)鍵值對(duì),其中鍵是對(duì)象,值可以是任意數(shù)據(jù)類型。
如果用 WeakMap 來(lái)存儲(chǔ) items 變量, Stack 類就是這樣的:
const items = new WeakMap(); //{1} class Stack { constructor () { items.set(this, []); //{2} } push(element) { let s = items.get(this); //{3} s.push(element); } pop() { let s = items.get(this); let r = s.pop(); return r; } //其他方法 }
行 {1} ,聲明一個(gè) WeakMap 類型的變量 items 。
行 {2} ,在 constructor 中,以 this ( Stack 類自己的引用)為鍵,把代表?xiàng)5臄?shù)組存入 items。
行 {3} ,從 WeakMap 中取出值,即以 this 為鍵(行 {2} 設(shè)置的)從 items 中取值。
現(xiàn)在我們知道, items 在 Stack 類里是真正的私有屬性了,但還有一件事要做。 items 現(xiàn)在
仍然是在 Stack 類以外聲明的,因此誰(shuí)都可以改動(dòng)它。我們要用一個(gè)閉包(外層函數(shù))把 Stack
類包起來(lái),這樣就只能在這個(gè)函數(shù)里訪問(wèn) WeakMap :
let Stack = (function () { const items = new WeakMap(); class Stack { constructor () { items.set(this, []); } //其他方法 } return Stack; //{4} })();
當(dāng) Stack 函數(shù)里的構(gòu)造函數(shù)被調(diào)用時(shí),會(huì)返回 Stack 類的一個(gè)實(shí)例(行 {4} )。
一個(gè)例子(把十進(jìn)制的數(shù)轉(zhuǎn)換成任意進(jìn)制的數(shù))
function baseConverter(decNumber, base){ var remStack = new Stack(), rem, baseString = "", digits = "0123456789ABCDEF"; //{5} while (decNumber > 0){ rem = Math.floor(decNumber % base); remStack.push(rem); decNumber = Math.floor(decNumber / base); } while (!remStack.isEmpty()){ baseString += digits[remStack.pop()]; //{6} } return baseString; }
我們只需要改變一個(gè)地方。在將十進(jìn)制轉(zhuǎn)成二進(jìn)制時(shí),余數(shù)是0或1;在將十進(jìn)制轉(zhuǎn)成八進(jìn)制
時(shí),余數(shù)是0到7之間的數(shù);但是將十進(jìn)制轉(zhuǎn)成16進(jìn)制時(shí),余數(shù)是0到9之間的數(shù)字加上A、B、C、
D、E和F(對(duì)應(yīng)10、11、12、13、14和15)。因此,我們需要對(duì)棧中的數(shù)字做個(gè)轉(zhuǎn)化才可以(行
{5} 和行 {6} )。
參考:《Javascript數(shù)據(jù)結(jié)構(gòu)與算法》
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/99367.html
摘要:我們都知道數(shù)組是里面比較常用的一種數(shù)據(jù)結(jié)構(gòu),棧和數(shù)組類似,定義如下棧是一種遵從后進(jìn)先出原則的有序集合。新增加和待刪除的元素都保存在棧的尾部,也稱棧頂,相反的另一端就叫棧底,在棧的這種數(shù)據(jù)結(jié)構(gòu)里面,我們新增的元素都在棧頂,舊的元素都在棧底。 由于不是計(jì)算機(jī)專業(yè)出身,對(duì)數(shù)據(jù)結(jié)構(gòu)這些了解的比較少,最近看了一些相關(guān)的書(shū)籍,這里做一些總結(jié)。本篇要說(shuō)的是棧。我們都知道數(shù)組是JavaScript里面...
摘要:今天實(shí)現(xiàn)的是最基本的數(shù)據(jù)結(jié)構(gòu)之一棧棧在中有著非常重要,基本類型會(huì)存儲(chǔ)在棧中,你可以操作實(shí)際的值。要定義一個(gè)棧,首先需要明白,棧的基本結(jié)構(gòu)有哪些,需要遵循哪些規(guī)則。首先創(chuàng)建一個(gè)函數(shù)對(duì)象表示棧。 Javascript工程師,總會(huì)面對(duì)一個(gè)問(wèn)題,數(shù)據(jù)結(jié)構(gòu)和算法會(huì)成為自己的短板,不僅是對(duì)非科班,甚至一些科班出身的工程師來(lái)說(shuō)也是自己的短板,于是就有了這系列文章。基礎(chǔ)決定深度,前端入門易,上升困難,...
摘要:今天實(shí)現(xiàn)的是最基本的數(shù)據(jù)結(jié)構(gòu)之一棧棧在中有著非常重要,基本類型會(huì)存儲(chǔ)在棧中,你可以操作實(shí)際的值。要定義一個(gè)棧,首先需要明白,棧的基本結(jié)構(gòu)有哪些,需要遵循哪些規(guī)則。首先創(chuàng)建一個(gè)函數(shù)對(duì)象表示棧。 Javascript工程師,總會(huì)面對(duì)一個(gè)問(wèn)題,數(shù)據(jù)結(jié)構(gòu)和算法會(huì)成為自己的短板,不僅是對(duì)非科班,甚至一些科班出身的工程師來(lái)說(shuō)也是自己的短板,于是就有了這系列文章?;A(chǔ)決定深度,前端入門易,上升困難,...
摘要:原文地址學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)一棧和隊(duì)列博主博客地址的個(gè)人博客幾乎所有的編程語(yǔ)言都原生支持?jǐn)?shù)組類型,因?yàn)閿?shù)組是最簡(jiǎn)單的內(nèi)存數(shù)據(jù)結(jié)構(gòu)。他們就是棧和隊(duì)列。我們稱作棧頂,而另一端我們稱作棧底。移除棧頂?shù)脑?,同時(shí)返回被移除元素。 前言 只要你不計(jì)較得失,人生還有什么不能想法子克服的。 原文地址:學(xué)習(xí)javascript數(shù)據(jù)結(jié)構(gòu)(一)——棧和隊(duì)列 博主博客地址:Damonare的個(gè)人博客 幾乎所有的編程...
摘要:之?dāng)?shù)組操作接下來(lái)就是數(shù)據(jù)結(jié)構(gòu)的第一部分,棧。以字符串顯示棧中所有內(nèi)容方法的實(shí)現(xiàn)說(shuō)明需要往棧中添加新元素,元素位置在隊(duì)列的末尾。的前端樂(lè)園原文鏈接寒假前端學(xué)習(xí)學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法,棧與隊(duì)列 本系列的第一篇文章: 學(xué)習(xí)JavaScript數(shù)據(jù)結(jié)構(gòu)與算法(一),棧與隊(duì)列第二篇文章:學(xué)習(xí)JavaScript數(shù)據(jù)結(jié)構(gòu)與算法(二):鏈表第三篇文章:學(xué)習(xí)JavaScript數(shù)據(jù)結(jié)構(gòu)與算法(三):集合第...
閱讀 1445·2021-11-19 11:38
閱讀 3574·2021-11-15 11:37
閱讀 821·2021-09-30 09:48
閱讀 969·2021-09-29 09:46
閱讀 908·2021-09-23 11:22
閱讀 1888·2019-08-30 15:44
閱讀 3409·2019-08-26 13:58
閱讀 2395·2019-08-26 13:26