簡體   English   中英

Javascript中遞歸函數的記憶

[英]Memoization of a recursive function in Javascript

我有這個遞歸函數,它接收一組卡片並找到特定卡片的索引:

const getCardIndex = (deck, fullCardName) => fullCardName === deck[0] ? 52 - deck.length : getCardIndex(deck.splice(1), fullCardName)

const deck = 'Ace of Hearts, Ace of Diamonds, Ace of Clubs, Ace of Spades, Two of Hearts, Two of Diamonds, Two of Clubs, Two of Spades, Three of Hearts, Three of Diamonds, Three of Clubs, Three of Spades, Four of Hearts, Four of Diamonds, Four of Clubs, Four of Spades, Five of Hearts, Five of Diamonds, Five of Clubs, Five of Spades, Six of Hearts, Six of Diamonds, Six of Clubs, Six of Spades, Seven of Hearts, Seven of Diamonds, Seven of Clubs, Seven of Spades, Eight of Hearts, Eight of Diamonds, Eight of Clubs, Eight of Spades, Nine of Hearts, Nine of Diamonds, Nine of Clubs, Nine of Spades, Ten of Hearts, Ten of Diamonds, Ten of Clubs, Ten of Spades, Jack of Hearts, Jack of Diamonds, Jack of Clubs, Jack of Spades, Queen of Hearts, Queen of Diamonds, Queen of Clubs, Queen of Spades, King of Hearts, King of Diamonds, King of Clubs, King of Spades'.split(', ')

const result = getCardIndex(deck, 'King of Spades')

console.log(result)

有什么辦法可以加快速度,即使用記憶?

正如評論所暗示的那樣,幾乎沒有理由遞歸地執行此操作。 indexOf很好地解決了這個問題。

但是,如果您決定編寫遞歸解決方案,則您的技術存在巨大問題。 您正在破壞您要搜索的對象!

Array.prototype.splice破壞性的 它改變了它處理的數組。 最后,您將擁有一個索引和一副幾乎為空的紙牌!

這完全有效幾乎是巧合。 如果您打算使用slice ,那會起作用並且不會出現此問題。 slice只是為您提供從一個索引開始並在另一個索引(或數組末尾)結束的數組副本。 splice做的更多。 它刪除元素的子列表,插入額外的元素並返回刪除的元素。 如果你碰巧只用一個起始索引調用它,它會刪除數組的其余部分並返回它。 所以調用deck.slice(1)deck.splice(1)碰巧返回相同的東西,但第二個也從你的數組中刪除了所有返回的項目。

因此,對您的函數的最快修復就是這樣:

const getCardIndex = (deck, fullCardName) => 
  fullCardName === deck[0] 
    ? 52 - deck.length 
    : getCardIndex (deck.slice(1), fullCardName)

但這沒什么意義,老實說。 它可以工作,但在每次遞歸調用時,它都會構建一個新數組,比以前的版本短。 對於簡單的搜索來說,這是很多內存。

所以這是另一種僅在索引上遞歸的技術:

const getCardIndex = (deck, fullCardName, idx = 0) =>
  idx >= deck.length 
    ? -1
    : deck [idx] == fullCardName
      ? idx
      : getCardIndex (deck, fullCardName, idx + 1)

但是請注意,除了變量和函數的名稱之外,沒有任何特定於甲板和卡片的內容。 因此,我們可以將其轉換為更通用的函數,如下所示:

const getIndex = (xs, x, idx = 0) =>
  idx >= xs.length 
    ? -1
    : xs [idx] == x
      ? idx
      : getIndex (xs, x, idx + 1)

我們有一個遞歸解決方案,用於在任意數組中查找值的索引。

不過,再次說明,幾乎沒有理由使用此功能。 這是學習遞歸的合理練習,但除此之外別無他法。 改用indexOf

對於預先確定解決方案( O(52) = O(1) )然后可以在單個操作中查找解決方案的解決方案,拋棄遞歸函數,將牌組變成一個對象,其鍵是卡片名稱和值是卡片索引,然后只需查找對象上的卡片屬性:

 const deck = 'Ace of Hearts, Ace of Diamonds, Ace of Clubs, Ace of Spades, Two of Hearts, Two of Diamonds, Two of Clubs, Two of Spades, Three of Hearts, Three of Diamonds, Three of Clubs, Three of Spades, Four of Hearts, Four of Diamonds, Four of Clubs, Four of Spades, Five of Hearts, Five of Diamonds, Five of Clubs, Five of Spades, Six of Hearts, Six of Diamonds, Six of Clubs, Six of Spades, Seven of Hearts, Seven of Diamonds, Seven of Clubs, Seven of Spades, Eight of Hearts, Eight of Diamonds, Eight of Clubs, Eight of Spades, Nine of Hearts, Nine of Diamonds, Nine of Clubs, Nine of Spades, Ten of Hearts, Ten of Diamonds, Ten of Clubs, Ten of Spades, Jack of Hearts, Jack of Diamonds, Jack of Clubs, Jack of Spades, Queen of Hearts, Queen of Diamonds, Queen of Clubs, Queen of Spades, King of Hearts, King of Diamonds, King of Clubs, King of Spades'.split(', ') const deckObj = Object.fromEntries(deck.map((str, i) => [str, i])); console.log(deckObj['King of Spades']) console.log(deckObj['Ace of Diamonds']) console.log(deckObj['Queen of Diamonds'])

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM