Skip to content

Latest commit

 

History

History
206 lines (162 loc) · 4.86 KB

live-code.md

File metadata and controls

206 lines (162 loc) · 4.86 KB
// QUEUE

// Add -> "Enqueue"
// Remove -> "Dequeue"
// Look at the next thing -> "Front"
// "isEmpty"

// Two implementations
// 1st: Easy one using an Array

class Queue {

  constructor() {
    this.list = [];
  }

  enqueue(value) {
    // add to the end
    this.list.push(value)
    // O(1)
  }

  dequeue() {
    // shows us what's in front
    // it removes that item from the front
    // "takes that item out of line"
    return this.list.shift()

    // When removing first, we have to move all the other items over one spot to the left
    // O(n)
  }

  get front() {
    // edge case: nothing in queue. what do we do? up to you :) as-is, this returns undefined
    return this.list[0];
    // O(1)
  }

  // easy... wipe off your brow, good job.
  get isEmpty() {
    return this.list.length === 0;
    // O(1)
  }

}

let queue = new Queue()
for (i = 0; i < 5; i ++ ) {
  queue.enqueue(i)
}

console.log(queue.front) // 0, because 0 gets added first
console.log(queue.isEmpty) // false

for (i = 0; i < 3; i ++) {
  queue.dequeue()
}

console.log(queue.front) // 3, because 3 "moved up 3 spaces in line"

class Animal {
  constructor(genus, name) {
    this.genus = genus;
    this.name = name;
  }
}

const dog = new Animal("canus", "spot")
const cat = new Animal("feline", "minnos")
const frog = new Animal("frogus", "jumpy")

const vetSchedule = [dog, frog, cat]

let vetQueue = new Queue()

for (i = 0; i < vetSchedule.length; i++ ) {
  vetQueue.enqueue(vetSchedule[i])
}

//now our vet knows what animals they're seeing, and in what order

vetQueue.dequeue // A dog


// Dequeueing with our Queue is slow. We want our data structures to be fast!
// Let's make it better using a LinkedList


// Why would we choose something harder?
// Because we can make it work faster/more efficiently

class Node {
  constructor(value, next) {
    this.value = value
    this.next = next
  }
}

class LinkedList {
  constructor() {
    // front -> where we'll dequeue from
    this.head = null
    // back -> where we'll enqueue to
    this.tail = null
  }

  /* 
    HEAD(2) -> (3) -> TAIL(4)
    enqueue(6)
    HEAD(2) -> (3) -> (4) -> TAIL(6)
    dequeue()
    HEAD(3) -> (4) -> TAIL(6)
  */
}

class LLQueue {
  constructor() {
    this.list = new LinkedList()
  }

  enqueue(value) {
    // Overall strategy: I want to reassign tail to be a node with the `value` coming in here
    const node = new Node(value)
    
    // edge cases:
    // What if tail doesnt exist? what is head doesn't exist
    // -> these both mean there's an empty list
    
    if (this.list.tail === null) {
      // for an empty list, that node is both head and tail
      this.list.tail = node
      this.list.head = node
    } else {
      let tail = this.list.tail
    // first, we make sure that the current tail now points to the new node
    // make sure there's a connection
      tail.next = node
    // situation 1: HEAD(2) -> (3) -> TAIL(4) -> (6)
    // situation 2: HEADTAIL(2)
    // then reassign
      this.list.tail = node
    // situation 1: HEAD(2) -> (3) -> (4) -> TAIL(6)
    // situation 2: HEAD(2) -> TAIL(6)
    
    }
  }

  dequeue() {
    // remove from the front
    // We'll always change HEAD in this function
    // We'll need to watch out for tail in certain edge cases

    // what if there are no node/values/items?
    if (this.list.head === null) {
      // situation 1: nothing to dequeue, because no head node
      // solution: do nothing.
      return;
    } 
    
    // what if there is one item?
    // before dequeue, tail points to the same node as head
    if (this.list.head === this.list.tail) {
      // we need to go from one item to zero items
      // situation 2: HEADTAIL(2)
      // dequeue -> remove the first item
      // head and tail now don't point to any node

      let value = this.list.head.value
      this.list.head = null
      this.list.tail = null
      return value
      // O(1), because it doesnt take longer as the list grows
    }
    
    // if we start from 2+ items in the queue
    // situation 3: HEAD(2) -> (3) -> (4) -> TAIL(6)

    let head = this.list.head
    // head = node(3)
    this.list.head = head.next
    // situation 3: HEAD(3) -> (4) -> TAIL(6)
    // the node (2) "falls off"
    return head.value
    // O(1), because it doesnt take longer as the list grows
    
    // "garbage collection" -> how does the software clear memory to get rid of items that are no longer in use?
    // how does this get cleaned up in JS v. in Ruby
    // similar to ActiveStorage in Rails?
    
  }

  get front() {
    //edge case: empty queue
    if (this.list.head === null) {
      return
    }
    return this.list.head.value
  }

  get isEmpty() {
    return this.list.head === null
  }
}