棧是計算機科學中的一種抽象數據類型,只容許在有序的線性數據集合的一端(稱爲堆棧頂端,英語:top)進行加入數據(英語:push)和移除數據(英語:pop)的運算。於是按照後進先出(LIFO, Last In First Out)的原理運做。(百科全書)
html
<font size="3">棧中有兩個基本的操做數組
棧的基本提點就是瀏覽器
對於棧的畫面的理解,能夠想象成一個步槍彈夾添加子彈和射擊的過程
彈夾只有一個出入口進行推入和彈出</font>數據結構
<body style='width: 80%;height:80%; margin: 10% auto;'> <ul id="stackBox" style="width:100px;border:1px solid #1fb19e;"> </ul> <div style="width:400px; display:flex;"> <input id="funStackBox" value="執行函數"> <div style="margin-left:100px;"> <button onclick="pushStack()" type='primary'>進棧</button> <button onclick="popStack()" type='primary'>出棧</button> </div> </div> <script> // 棧盒子 let stackBox = document.getElementById('stackBox') // 執行函數盒子 let funStackBox = document.getElementById('funStackBox') // 棧類 class Stack { constructor(length) { this.list = [] this.length = length } // 新增棧 addStack(val) { if (this.length > this.list.length) { this.list.push(val) let beforeDom = document.getElementById(this.list.length - 1) // 新增棧 let el = document.createElement('li') el.id = this.list.length el.innerText = this.list[this.list.length - 1] stackBox.insertBefore(el, beforeDom) }else{ console.log('棧滿了') } } // 彈出棧 popStack() { let delDom = document.getElementById(this.list.length) stackBox.removeChild(delDom) return this.list.pop() } // 棧的大小 stackLength() { console.log('當前棧大小爲'+this.list.length) return this.list.length } // 棧的頂層元素 stackIsHas() { return this.list.length?this.list[this.list.length]:console.log('沒有棧了') } //查看全部元素 showStack() { return this.list.join('\n'); } //清空隊列 clearStack() { this.list = []; this.showStack() console.log('棧空了') } } stackOne = new Stack(5) /** * @author: 周靖鬆 * @information: 進棧 * @Date: 2019-06-10 12:47:16 */ function pushStack() { stackOne.addStack(funStackBox.value) console.log(funStackBox.value, '進棧') stackOne.stackLength() stackOne.stackIsHas() } /** * @author: 周靖鬆 * @information: 出棧 * @Date: 2019-06-10 12:47:16 */ function popStack() { let popStack = stackOne.popStack(funStackBox.value) console.log(popStack, '出棧') stackOne.stackLength() stackOne.stackIsHas() } </script> </body>
<font size="3">效果圖以下</font>函數
<font size="3">上邊說了棧的基本結構和方法,那麼棧被建立的時候又作了什麼事情呢flex
首先在咱們的js在解釋執行代碼的時候,最早遇到的就是全局代碼,因此在一開始的時候首先就會向棧裏邊壓入一個全局執行上下文this
全局上下文 只有在全局執行環境被銷燬的時候纔會被彈出銷燬
全局執行上下文 只有一個 就是瀏覽器中的window對象,this默認指向這個全局對象spa
而後當執行一個函數的時候,會在開始先建立一個執行上下文壓入棧中,若是裏邊又執行其餘的函數的時候,又會建立一個新的執行上下文壓入執行棧中,直到函數執行完畢,就會把函數的上下文從執行棧中彈出</font>3d
function fun3() { console.log('3') } function fun2() { fun3(); } function fun1() { fun2(); } fun1();
<font size="3">好比說上邊這段代碼 ,他的進棧出棧順序就是一開始咱們放的那兩張圖的效果</font>指針
function fun1() { console.log('1') } function fun2() { console.log('2') } function fun3() { console.log('3') }
<font size="3">若是是這種的話 則會是最下邊有一個全局的棧,而後三個函數分別進棧出棧</font>
<font size="3">剛纔咱們在上邊提到了執行上下文的概念,執行上下文是跟函數相關的,執行上下文分爲兩個階段</font>
<font size="3">首先建立階段</font>
<font size="3">簡單說一下詞法環境和變量環境的區別,我我的理解的就是說詞法環境是包含變量環境的
在js裏邊原型鏈你們都不陌生 ,js在當前的對象裏邊找不到所使用的屬性的話會去他的上一級去找
直到Object,再找不到就會undefined ,這裏邊 當前對象的做用域就是他的變量環境,而詞法環境則是與之關聯的的執行上下文中聲明的變量
在建立階段 函數的聲明會被儲存在當前的變量環境之中,var的變量的話則會被設置成undefined
,因此咱們在聲明以前就能夠訪問到var聲明的變量 ,but他是一個undfined
而後就是執行階段了
這個時候已經完成了對全部變量的分配,開始執行代碼</font>
<font size="3">隊列是一種比較高效的數據結構,他與棧不一樣的是,隊列只能在隊尾插入元素,在隊首刪除元素,
隊列用生活中的事物距離的話,你們能夠想一想一下沙漏,先進入的沙子先出去,後進去的沙子後出去
隊列比棧高效的地方就在於,循環的時候,棧會開闢一個新的臨時棧,而後進行排序,再循環,最後在確保不打亂原有順序的狀況下 排列回去
隊列則不須要這麼多步驟</font>
<font size="3">隊列經常使用的一些操做有</font>
<font size="3">就先拿這些經常使用的方法實現如下,老規矩,請你們看代碼</font>
// 隊列類 class Queue { constructor() { this.dataStore = [] } //新增 addQueue(val) { this.dataStore.push(val); } //刪除隊列首的元素 delQueue() { return this.queueIsNone()?console.log('隊列空了'):this.dataStore.shift() } //隊列是否爲空 queueIsNone() { return this.dataStore.length == 0 } //查看全部元素 showQueue() { return this.dataStore.join('\n'); } //清空隊列 clearQueue() { this.dataStor = []; this.showQueue() console.log('隊列空了') } } // 隊列實例 let queueOne = new Queue() /** * @author: 周靖鬆 * @information: 進隊 * @Date: 2019-06-11 21:01:28 */ function QueueIn (){ queueOne.addQueue(funStackBox.value) console.log(queueOne.showQueue()) } /** * @author: 周靖鬆 * @information: 出隊 * @Date: 2019-06-11 21:01:35 */ function QueueOut (){ queueOne.delQueue() console.log(queueOne.showQueue()) } /** * @author: 周靖鬆 * @information: 清空隊列 * @Date: 2019-06-11 21:05:35 */ function QueueClear(){ queueOne.clearQueue() }
<font size="3">上邊的代碼 你們能夠本身寫個html試一下哈,html就不寫了直接貼一下效果圖</font>
<font size="3">另外雖然剛纔咱們再例子中是用數據去模擬的棧和隊列的實現,but 數組他其實並非一個棧內存,他是一個堆內存</font>
如果知足如下特性,便可稱爲堆:是計算機科學中的一種特別的樹狀數據結構。能夠給堆中的任意節點添加新的節點(百科全書)
<font size="3">在JS中,每個數據都須要一個內存空間。內存空間又被分爲兩種,棧內存(stack)與堆內存(heap)。</font>
<font size="3">也不是說不會自動釋放,堆在沒有引用的時候,下一次垃圾回收機制出現的時候會回收他的內存
js 的變量分爲基本類型和引用類型</font>
基本類型在內存中佔據空間小、大小固定 ,他們的值保存在棧(stack)空間,是按值來訪問
引用類型佔據空間大、大小不固定, 棧內存中存放地址指向堆(heap)內存中的對象。是按引用訪問的
<font size="3">盜個圖舉個例子</font>
<font size="3">js不容許直接訪問堆內存中的位置,所以咱們不能直接操做對象的堆內存空間,因此棧中存的是一個指向堆內存的一個地址
當咱們要訪問堆內存中的引用數據類型時,實際上咱們首先是從棧中獲取了該對象的地址引用(或者地址指針),而後再從堆內存中取得咱們須要的數據。
今天就堆棧隊列的內容就大概說到這裏 下一篇博客 在繼續說一下, 有什麼說的不對或者不足的地方,請你們批評指正</font></font >