>[success] # 實現一個js的棧
~~~
1.上個章節我們說了一個實現思路是通過'數組形式'來實現一個棧,這種棧叫做'順序棧',
這個章節就用js 實現一個順序棧
~~~
>[info] ## 實現是一個順序棧 -- 先進后出(LIFO 原則)
~~~
1.首先'順序棧' 是基于數組,只能對棧頂進行操作因此接下來要實現的順序棧會有以下的方法
push(element(s)):添加一個(或幾個)新元素到棧頂。
pop():移除棧頂的元素,同時返回被移除的元素。
peek():返回棧頂的元素,不對棧做任何修改(該方法不會移除棧頂的元素,僅僅返回它)。
isEmpty():如果棧里沒有任何元素就返回 true,否則返回 false。
clear():移除棧里的所有元素。
size():返回棧里的元素個數。該方法和數組的 length 屬性很類似。
~~~
* 棧頂如圖

>[danger] ##### 代碼實現
~~~
class StackArray{
constructor(){
// 創建一個數組用來保存棧
this.item = []
}
// 棧頂添加
push(element){
this.item.push(element)
}
// 移除棧頂元素
pop(){
return this.item.pop()
}
// 返回當前棧頂元素
peek(){
return this.item[this.item.length-1]
}
// 判斷當前棧是否有元素
isEmpty(){
return this.item.length === 0
}
// 移除棧里所有元素
clear(){
this.item = []
}
// 返回棧中的個數
size(){
return this.item.length
}
toArray() {
return this.items;
}
toString() {
return this.items.toString();
}
}
~~~
>[info] ## 使用js 對象為基礎實現 -- 棧
~~~
1.數組是連續的開辟內存空間所以對空間的占用相對較多,減少較少的
空間使用可以考慮對象這種創建方式
~~~
>[danger] ##### 代碼實現
~~~
class Stack{
constructor(){
this.count = 0
this.items = {}
}
// 檢查棧是否為空
isEmpty(){
return this.count === 0
}
// 添加元素
push(element){
this.items[this.count ++ ] = element
}
// 刪除元素
pop(){
// 如果棧為空刪除返回undefined
if(this.isEmpty()){
return undefined
}
const result = this.items[--this.count ]
delete this.items[this.count]
return result
}
// 返回棧頂元素
peek() {
if (this.isEmpty()) {
return undefined;
}
return this.items[this.count - 1];
}
// 棧的大小
size(){
return this.count
}
// 清楚棧
clear() {
// 循環這種 利用先進后出按順序依次刪除
/* while (!this.isEmpty()) {
this.pop();
} */
// 這種最簡單粗暴一步到位
this.items = {};
this.count = 0;
}
toString() {
if (this.isEmpty()) {
return '';
}
// 為了可以拼接處1,2,3
let objString = `${this.items[0]}`;
for (let i = 1; i < this.count; i++) {
objString = `${objString},${this.items[i]}`;
}
return objString;
}
}
const stack = new Stack()
stack.push(1)
stack.push(2)
stack.push(3)
console.log(stack.toString()) // 1,2,3
~~~
>[info] ## 上面的兩種實現的弊端
~~~
1.上面的兩種已經實現了,但是不是那么友好,因為對外暴露了items,
這樣使用的人可以任意對暴露的items 進行更改es10是具備私有屬性,
我們可以將這些不想對外暴露的屬性設置為私有屬性
2.當然我們也可用'symbol'來操作,但這依舊會有問題
~~~
>[danger] ##### 使用symbol 創建私有屬性
~~~
const _items = Symbol('stackItems');
class Stack {
constructor () {
this[_items] = [];
}
// 棧的方法
}
// 但是依舊可以使用 getOwnPropertySymbols 獲取symbol 并且更改
const 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
~~~
>[danger] ##### 使用 WeakMap
* WeakMap配合 數組
~~~
1.采用這種方法,代碼的可讀性不強,而且在擴展該類時無法繼承私有屬性
~~~
~~~
const items = new WeakMap();
class Stack {
constructor () {
items.set(this, []);
}
push(element){
const s = items.get(this);
s.push(element);
}
pop(){
const s = items.get(this);
const r = s.pop();
return r;
}
// 其他方法
}
~~~
* WeakMap配合 對象
~~~
const _items = new WeakMap();
const _count = new WeakMap();
class Stack {
constructor() {
_count.set(this, 0);
_items.set(this, {});
}
push(element) {
const items = _items.get(this);
const count = _count.get(this);
items[count] = element;
_count.set(this, count + 1);
}
pop() {
if (this.isEmpty()) {
return undefined;
}
const items = _items.get(this);
let count = _count.get(this);
count--;
_count.set(this, count);
const result = items[count];
delete items[count];
return result;
}
peek() {
if (this.isEmpty()) {
return undefined;
}
const items = _items.get(this);
const count = _count.get(this);
return items[count - 1];
}
isEmpty() {
return _count.get(this) === 0;
}
size() {
return _count.get(this);
}
clear() {
/* while (!this.isEmpty()) {
this.pop();
} */
_count.set(this, 0);
_items.set(this, {});
}
toString() {
if (this.isEmpty()) {
return '';
}
const items = _items.get(this);
const count = _count.get(this);
let objString = `${items[0]}`;
for (let i = 1; i < count; i++) {
objString = `${objString},${items[i]}`;
}
return objString;
}
}
~~~
>[info] ## 總結
~~~
1.當然了可以使用es10 私有屬性或者使用ts,畢竟每個語言都有自己的
特點
~~~
- 接觸數據結構和算法
- 數據結構與算法 -- 大O復雜度表示法
- 數據結構與算法 -- 時間復雜度分析
- 最好、最壞、平均、均攤時間復雜度
- 基礎數據結構和算法
- 線性表和非線性表
- 結構 -- 數組
- JS -- 數組
- 結構 -- 棧
- JS -- 棧
- JS -- 棧有效圓括號
- JS -- 漢諾塔
- 結構 -- 隊列
- JS -- 隊列
- JS -- 雙端隊列
- JS -- 循環隊列
- 結構 -- 鏈表
- JS -- 鏈表
- JS -- 雙向鏈表
- JS -- 循環鏈表
- JS -- 有序鏈表
- 結構 -- JS 字典
- 結構 -- 散列表
- 結構 -- js 散列表
- 結構 -- js分離鏈表
- 結構 -- js開放尋址法
- 結構 -- 遞歸
- 結構 -- js遞歸經典問題
- 結構 -- 樹
- 結構 -- js 二搜索樹
- 結構 -- 紅黑樹
- 結構 -- 堆
- 結構 -- js 堆
- 結構 -- js 堆排序
- 結構 -- 排序
- js -- 冒泡排序
- js -- 選擇排序
- js -- 插入排序
- js -- 歸并排序
- js -- 快速排序
- js -- 計數排序
- js -- 桶排序
- js -- 基數排序
- 結構 -- 算法
- 搜索算法
- 二分搜索
- 內插搜索
- 隨機算法
- 簡單
- 第一題 兩數之和
- 第七題 反轉整數
- 第九題 回文數
- 第十三題 羅馬數字轉整數
- 常見一些需求
- 把原始 list 轉換成樹形結構