【问题标题】:How can I use a Javascript object/map as queue如何使用 Javascript 对象/地图作为队列
【发布时间】:2016-02-01 04:16:27
【问题描述】:

现在我有一个队列(JS 数组),用于存储等待游戏的玩家。我需要队列的 FIFO 属性,以便首先添加到队列中的玩家首先进入新游戏。队列的问题在于它没有固定的时间查找。如果我可以拥有一个跟踪插入顺序的地图,那就太好了(我知道依靠地图来做到这一点是 JS 不可靠的)。如果我给属性一个插入顺序的值,如果有人离开队列,它就需要更新,所以这也没有帮助。无论如何围绕这个?一种获得持续查找和维护插入顺序的方法?

【问题讨论】:

  • 链表行得通吗?
  • 链表与数组队列的查找成本相同
  • 您能否就我的回答是否有用给我一些反馈?我认为它符合您提到的要求,但我可能遗漏了一些东西。

标签: javascript arrays dictionary queue


【解决方案1】:

您可以将地图与队列一起使用以提供恒定时间访问。下面是 TypeScript 4.2 中的实现。使用Map 代替Object 来提供better performance 附加和删除值。

// TypeScript typing
export type KeyValuePair<K, V> = [ K, V ]

interface ValueData<V> {
  value: V
  refCount: number
}

// Public classes
export class MapQueue<K, V> {
  readonly #queue: Array<KeyValuePair<K, V>>
  readonly #map: Map<K, ValueData<V>>

  constructor () {
    this.#queue = []
    this.#map = new Map()
  }

  get length (): number {
    return this.#queue.length
  }

  unshiftOne (pair: KeyValuePair<K, V>): number {
    const [key, value] = pair
    const valueData = this.#map.get(key)
    if (valueData !== undefined) {
      if (valueData.value !== value) {
        throw new Error(`Key ${String(key)} with different value already exists`)
      }
      valueData.refCount++
    } else {
      this.#map.set(key, {
        value,
        refCount: 1
      })
    }
    return this.#queue.unshift(pair)
  }

  pop (): KeyValuePair<K, V> | undefined {
    const result = this.#queue.pop()
    if (result !== undefined) {
      const valueData = this.#map.get(result[0])
      if (valueData !== undefined) {
        valueData.refCount--
        if (valueData.refCount === 0) {
          this.#map.delete(result[0])
        }
      }
    }
    return result
  }

  get (key: K): V | undefined {
    return this.#map.get(key)?.value
  }
}

【讨论】:

    【解决方案2】:

    如果您没有内存限制,也许您可​​以维护一个映射,其中队列实现为双链表。这是一个示例实现:

    function Queue() {
        var oldestRequest,
            newestRequest,
            map = {};
    
        this.addUser = function(userID) {
            var newRequest = { userID: userID };
            map[userID] = newRequest;
    
            // Set this as the oldest request if it is the first request
            if (!oldestRequest) {
                oldestRequest = newRequest;
            }
    
            // If this isn't the first request, add it to the end of the list
            if (newestRequest) {
                newestRequest.next = newRequest;
                newRequest.previous = newestRequest;
            }
    
            newestRequest = newRequest;
        };
    
        this.nextUser = function() {
            // If we don't have any requests, undefined is returned
            if (oldestRequest) {
               var request = oldestRequest;
               oldestRequest = request.next;
               delete map[request.userID];
    
               // Make sure we don't hang on to references to users
               // that are out of the queue
               if (oldestRequest) {
                   delete oldestRequest.previous;
               }
    
               // This is the last request in the queue so "empty" it
               if (request === newestRequest) {
                   newestRequest = undefined;
               }
    
               return request;
            }
        };
    
        this.removeUser = function(userID) {
            var request = map[userID];
            delete map[userID];
    
            if (request.previous) {
                request.previous.next = request.next;
            }
    
            if (request.next) {
                request.next.previous = request.previous;
            }
        };
    
        return this;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-11-01
      • 1970-01-01
      • 2015-05-13
      • 2021-03-18
      • 1970-01-01
      相关资源
      最近更新 更多