1. 程式人生 > >javascript資料結構與演算法筆記(一):棧

javascript資料結構與演算法筆記(一):棧

javascript資料結構與演算法筆記(一):棧

一:簡介

棧是一種遵從後進先出( LIFO)原則的有序集合。新新增的或待刪除的元素都儲存在棧的
同一端,稱作棧頂,另一端就叫棧底。在棧裡,新元素都靠近棧頂,舊元素都接近棧底。

二:ES6版Stack類(陣列)

1.宣告Stack類

class Stack{
	constructor(){
		this.items=[];
	}
}

2.向棧新增元素
只需與構建函式constructor()同級命名建立即可,下同。

push(element){
	items.push(element);
}

3.從棧移除元素
pop方法會刪除原棧中的元素

pop(){
	return items.pop();
}

4.檢視棧頂元素

peek(){
	return items[items.length-1];
}

5.檢查棧是否為空
isEmpty,如果棧為空的話將返回true,否則就返回false:

isEmpty(){
	return items.length==0;
}
size(){
	return items.length;
}

6.清空棧

isEmpty(){
	return items=[];
}

7.列印棧元素

print(){
	console.log(items.toString());
	//或者
	console.log(items.join(","));
}

8.使用棧

let stack=new Stack();
console.log(stack.isEmpty());
stack.push(1);
stack.push(2);
console.
log(stack.size()); console.log(stack.peek()); console.log(stack.size()); console.log(stack.pop()); stack.print(); 注:使用es6的class封裝的Stack,其中的items屬於公有屬性,即:無法讓使用者只通過類方法才能獲取到items的值,直接獲取stack.items也是可以被外部訪問到。

三:ES版Stack類私有屬性的封裝

1.偽私有屬性封裝

(1)使用ES6的限定作用域Symbol實現
ES6新增了一種叫作Symbol的基本型別,它是靜態的,不可變的,可以用作物件的屬性。

let _items=Symbol();
class Stack(){
	this[_items]=[];
}

注:其他方法就可以讓this[_items]取代this.items即可。
(2)使用該類
之所以被稱為偽私有屬性,因為ES6新增了Object.getOwnPropertySymbols方
法能夠取到類裡面宣告的所有Symbols屬性。即:

let stack=new Stack();
stack.push(5);
stack.push(8);
console.log(stack.this[_items]);//並不能打印出items的內容
//但是
let objectSymbols = Object.getOwnPropertySymbols(stack);
console.log(objectSymbols.length); // 1
console.log(objectSymbols); // [Symbol()]
console.log(objectSymbols[0]); // Symbol()
console.log(stack[objectSymbols[0]]);//就可以直接獲取stack的值,也無法實現讓使用者只能通過方法獲取屬性的意圖。
stack[objectSymbols[0]].push(1);
stack.print(); //輸出 5, 8, 1

2.真私有屬性封裝

(1)使用ES6的WeakMap實現
WeakMap可以儲存鍵值對,其中鍵是物件,值可以是任意資料型別。

const items = new WeakMap(); 
class Stack {
	constructor () {
		items.set(this, []); //給棧初始化為[]
	}
	push(element) {
		let s = items.get(this);//獲取棧的內容 
		s.push(element);
	}
	pop() {
		let s = items.get(this);
		let r = s.pop();
		return r;
	}
	//其他方法
}

注:此時我們就不可以在外部直接獲取該私有屬性,但是如果該類檔案內還有此類同級的邏輯使用,那樣我們就可以在同文件下,呼叫到items.get(this),棧的值,那我們需要再封裝一下:

//用一個閉包(外層函式)把Stack類包起來,這樣就只能在這個函式裡訪問WeakMap:
let Stack = (function () {
	const items = new WeakMap();
	class Stack {
		constructor () {
			items.set(this, []);
		}
		//其他方法
	}
	return Stack; //{5}
})();

注:這樣跟Stack同文件內,類外的呼叫就不可以直接調取到items屬性了,但是這種方法的話:擴充套件類無法繼承私有屬性。所以建議最好棧類檔案裡面只封裝一個類。

四:ES6版Stack類(連結串列)

class Stack{
    constructor(){
        this.dataStore=[];
        this.top=0;
    }
    push(element){
        this.dataStore[this.top++]=element;
    }
    pop(){
        return this.dataStore[--this.top];

    }
    peek(){
        if (this.dataStore[this.top - 1] == undefined) {
                return "none"
        }
        return this.dataStore[this.top-1];
    }
    length(){   
        return this.top;
    }
    clear(){
        this.top=0;
    }
}

五:棧解決實際問題案例

十進位制轉換為其他進位制

function divideByBase(decNumber,base){
    let remStack=new Stack_Array();
    let rem;
    let binaryString='';
    let digits='0123456789ABCDEF';
    while(decNumber>0){
        rem=Math.floor(decNumber%base);
        remStack.push(rem);
        decNumber=Math.floor(decNumber/base);
    }
    while(!remStack.isEmpty()){
        binaryString+=digits[remStack.pop()];
    }
    return binaryString;
}
console.log(divideByBase(15,16));

說明:
base為基數,即二進位制則為:2,八進位制為8,十六進位制為16
decNmuber為十進位制數。