日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

数据结构算法 二进制转十进制_数据结构 - 栈

發布時間:2023/12/19 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构算法 二进制转十进制_数据结构 - 栈 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

兩種類似數組的數據結構,在添加和刪除元素時更為可控,他們就是棧和隊列

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

被用在編程語言的編譯器和內存中保存變量、方法調用等,也被用于瀏覽器歷史記錄(瀏覽器的返回按鈕)。

創建一個基于數組的棧

創建一個類來表示棧,利用數組來保存棧里的元素

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

數組允許我們在任何位置添加或刪除元素,由于棧遵循 LIFO 原則,所以需要對元素的添加和刪除做一些限制,接下來為棧聲明一些方法

  • push() : 添加新元素到棧頂
  • pop() : 移除棧頂的 元素,同時返回被移除的元素
  • peek() : 返回棧頂的元素,不對棧做任何修改
  • isEmpty() : 如果棧里沒有任何元素返回 true, 否則返回 false
  • clear() : 移除棧里所有的元素
  • size() : 返回棧里的元素個數

向棧添加元素,首先實現 push() ,向棧里添加新元素,該方法只添加元素到棧頂,可以這樣寫

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

從棧移除元素,實現 pop() 方法,移除棧里的元素,棧遵循 LIFO 原則,移除的是最后添加進去的元素

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

限制為 push 和 pop 方法添加和刪除棧中元素,這樣棧就自然遵循了 LIFO 原則

查看棧頂元素,想知道棧里最后添加的元素是什么,可以用 peek 方法,該方法將返回棧頂的元素

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

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

isEmpty() {return this.items.length === 0 }

實現棧的長度

size() {return this.items.length }

清空棧元素,實現 clear 方法,移除棧里所有的元素

clear() {this.items = [] }

以上實現了一個棧

使用 Stack 類

在深入了解棧的應用前,先來了解如何使用 Stack 類。首先需要初始化 Stack 類,然后驗證一下棧是否為空(輸出是 true,因為還沒有往棧里添加元素)

const stack = new Stack() console.log(stack.isEmpty()) //true

接下來,往棧里添加一些元素

stack.push(5) stack.push(8)

調用 peek 方法(),返回棧頂的元素

console.log(stack.peek()) //8

再添加一個元素

stack.push(11) console.log(stack.size()) //3 console.log(stack.isEmpty()) //false

繼續添加元素

stack.push(15)

下圖描繪了我們對棧的操作,以及棧的當前狀態

調用兩次 pop 方法從棧里移除兩個元素

stack.pop() stack.pop() console.log(stack.size()) //2

在兩次調用 pop 方法前,我們的棧里有四個元素。調用兩次后,現在棧里僅剩下 5 和 8 了,下圖描繪了這個執行過程

創建一個基于對象的 Stack 類

使用數組來存儲元素,在處理大量數據時,需評估如何操作數據是最高效的,使用數組時,大部分方法的時間復雜度是 O(n) ,我們需要迭代整個數組直到找到要找的那個元素,在最壞的情況下需要迭代數組的所有位置,其中的 n 代表數組的長度。如果數組有更多元素的話,所需的時間會更長。另外,數組是元素的一個有序集合,為了保證元素排列有序,它會占用更多的內存空間。

如果我們能直接獲取元素,占用較少的內存空間,并且仍然保證所有元素按照我們的需要排列,那不是更好嗎?對于使用 JavaScript 語言實現棧數據結構的場景,我們也可以使用一個JavaScript 對象來存儲所有的棧元素,保證它們的順序并且遵循 LIFO 原則。我們來看看如何實現這樣的行為。

首先聲明一個 stack 類

class Stack {constructor() {this.count = 0 //記錄棧的大小this.items = {}} }

向棧中插入元素,因為使用的是對象, 所以 push 方法只允許我們一次插入一個元素

push(element) {this.items[this.count] = elementthis.count++ }

對象是鍵值對的集合,所以要向棧中添加元素,可以使用 count 變量作為 items 對象的鍵名,插入的元素則是它的值。在向棧插入元素后,我們遞增 count 變量。

使用 Stack 類,插入元素 5,8

const stack = new Stack() stack.push(5) stack.push(8)

查看 stack

驗證一個棧是否為空, count 屬性也表示棧的大小,因此,我們可以簡單地返回 count 屬性的值來實現 size 方法

size() {return this.count }

驗證棧是否為空

isEmpty() {return this.count === 0 }

從棧中彈出元素,對象中沒有直接用的 api ,所以手動實現

pop() {if (this.isEmpty()) {return undefined}this.count--const result = this.items[this.count]delete this.items[this.count]return result }

首先,我們需要檢驗棧是否為空。如果為空,就返回 undefined。如果棧不為空的話,我們會將 count 屬性減 1,并保存棧頂的值,以便在刪除它之后將它返回。

stack.pop() //8

模擬 pop 操作, 要訪問到棧頂的元素(即最后添加的元素 8),我們需要訪問鍵值為 1 的位置。因此我們將 count 變量從 2 減為 1。這樣就可以訪問 items[1],刪除它,并將它的值返回了。

查看棧頂的元素

peek() {if (this.isEmpty()) {return undefined}return this.items[this.count -1] }

清空該棧,只需要將它的值復原為構造函數中使用的值即可

clear() {this.items = {}this.count = 0 }

創建 toString 方法

在數組版本中,我們不需要關心 toString 方法的實現,因為數據結構可以直接使用數組已經提供的 toString 方法。對于使用對象的版本,我們將創建一個 toString 方法來像數組一樣打印出棧的內容。

toString() {if (this.isEmpty()) {return ''}let objString = `${this.items[0]}`for (let i = 1; i < this.count; i++) {objString = `${objString}, ${this.items[i]}`}return objString }

如果棧是空的,我們只需返回一個空字符串即可。如果它不是空的,就需要用它底部的第一個元素作為字符串的初始值,然后迭代整個棧的鍵,一直到棧頂,添加一個逗號以及下一個元素如果棧只包含一個元素,for循環不會執行

除了 toString 方法,我們創建的其他方法的復雜度均為 O(1),代表我們可以直接找到目標元素并對其進行操作(push、 pop 或 peek)。

保護數據結構內部元素

在創建別的開發者也可以使用的數據結構或對象時,我們希望保護內部的元素,只有我們暴露出的方法才能修改內部結構,對于 Stack 類來說,要確保元素只會被添加到棧頂,而不是棧底或其他任意位置(比如棧的中間)。

使用 WeakMap 實現類

WeakMap 可以存儲鍵值對,其中鍵是對象,值可以是任意數據類型,如果用 WeakMap 來存儲 items 屬性(數組版本), Stack 類就是這樣的:

const items = new WeakMap() //聲明一個 WeakMap 類型的變量 itemsclass Stack {constructor() {items.set(this, []) //以 this(Stack 類自己的引用)為鍵,把代表棧的數組存入 items。}push(element) {//從 WeakMap 中取出值,即以 this 為鍵(行{2}設置的)從 items 中取值。const s = items.get(this)s.push(element)}pop() {const s = items.get(this)const r = s.pop()return r} }

items 在 Stack 類里是真正的私有屬性

ECMAScript 類屬性提案(易讀性更好)

class Stack {#count = 0#items = 0//方法 }

用棧解決問題

如何解決十進制轉二進制問題,以及任意進制轉換的算法。

從十進制到二進制

該十進制數除以 2(二進制是滿二進一)并對商取整,直到結果是 0 為止。舉個例子,把十進制的數 10 轉化成二進制的數字,過程大概是如下這樣。

function decimalToBinary(decNumber) {const remStack = new Stack()let number = decNumberlet rem let binaryString = ''while (number > 0) {rem = Math.floor(number % 2) //js 不區分整數和浮點數,使用 Math.floor 返回整數部分,得到余數remStack.push(rem) //放入棧里number = Math.floor(number / 2) //繼續除以2,直到結果等于0時,才會停止 }while (!remStack.isEmpty()) {binaryString += remStack.pop().toString() //用 pop 方法把棧中的元素都移除,把出棧的元素連接成字符串}return binaryString }

測試

console.log(decimalToBinary(233)) //11101001 console.log(decimalToBinary(10)) //1010 console.log(decimalToBinary(1000)) //1111101000

進制轉換算法

修改上面的算法,使之能把十進制轉換成基數為 2~36 的任意進制。除了把十進制數除以 2 轉成二進制數,還可以傳入其他任意進制的基數為參數,就像下面的算法這樣。

function baseConverter(decNumber, base) {const remStack = new Stack()const digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'let number = decNumberlet remlet baseString = ''if (!(base >= 2 && base <= 36)) {return ''}while (number > 0) {rem = Math.floor(number % base)remStack.push(rem)number = Math.floor(number / base)}while (!remStack.isEmpty()) {baseString += digits[remStack.pop()]}return baseString }console.log(baseConverter(100345, 2)); // 11000011111111001 console.log(baseConverter(100345, 8)); // 303771 console.log(baseConverter(100345, 16)); // 187F9 console.log(baseConverter(100345, 35)); // 2BW0

我們只需要改變一個地方。在將十進制轉成二進制時,余數是 0 或 1;在將十進制轉成八進制時,余數是 0~7;但是將十進制轉成十六進制時,余數是 0~9 加上 A、 B、 C、 D、 E 和 F(對應 10、 11、 12、 13、 14 和 15)。因此,我們需要對棧中的數字做個轉化才可以(行{6}和行{7})。因此,從十一進制開始,字母表中的每個字母將表示相應的基數。字母 A 代表基數 11, B 代表基數 12,以此類推。

總結

以上是生活随笔為你收集整理的数据结构算法 二进制转十进制_数据结构 - 栈的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。