Marcy Lab School Docs
  • Welcome
  • Student Guidelines & Policies
    • Student Handbook
    • AI Policy
    • Academic Calendar
  • Environment Setup
    • Local Environment Setup - Mac
    • Local Environment Setup - Windows
    • GitHub Setup
    • Postgres Setup
  • How-Tos
    • How To Code at Marcy: Code Style Guide
    • How to Do Short Response and Coding Assignments
    • How to Debug
    • How to PEDAC
    • How to Create A GitHub Organization and Scrumboard
    • How to Create Projects with Vite
    • How to Deploy on GitHub Pages
    • How to Deploy on Render
    • How to Test your API with Postman
  • Mod 0 - Command Line Interfaces, Git, and GitHub
    • Overview
    • 1. Command Line Interfaces
    • 2. Git & GitHub
    • 3. Git Pulling & Merging
    • 4. Git Branching & PRs
  • Mod 1 - JavaScript Fundamentals
    • Overview
    • 1. Intro to Programming
    • 2. Errors
    • 3. Node & Node Modules
    • 4. Variables, Functions & String Methods
    • 5. Control Flow, typeof, and Math
    • 6. Loops
    • 7. Arrays
    • 8. Objects
    • 9. Higher Order Functions: Callbacks
    • 10. Higher Order Functions: Array Methods
    • 11. Regex
  • Mod 2 - HTML, CSS & the DOM
    • Overview
    • 1. HTML
    • 2. CSS
    • 3. Accessibility (a11y)
    • 4. The Document Object Model (DOM) API
    • 5. Events
    • 6. Forms
    • 7. The Box Model and Positioning
    • 8. Flexbox
    • 9. Grid & Media Queries
    • 10. ESModules
    • 11. Vite
    • 12. LocalStorage
  • Mod 3 - Async & APIs
    • Overview
    • 1. Promises
    • 2. Fetch
    • 3. Building a Fetching App
    • 4. Async & Await
    • 5. A Generic Fetch Handler
  • Mod 4 - Project Week!
    • Important How Tos and Guides
      • How to Create a GitHub Organization and Scrum Board
      • How To Start a Project with Vite
      • How To Deploy a Project with GitHub Pages
    • Project Week Overview
    • Agile Methodologies
    • Deliverables & Milestones
    • Technical Requirements Checklist
    • Free API List
    • Collaborative GitHub
  • Mod 5 - Object-Oriented Programming
    • Overview
    • 1. Intro to OOP, Encapsulation, Factory Functions, and Closure
    • 2. Classes
    • 3. Private & Static
    • 4. UML Diagrams & Has Many/Belongs To Relationships
    • 5. Challenge: Implementing Has Many/Belongs To
    • 6. Inheritance
    • 7. Polymorphism
    • 8. Review and Practice
    • MDN: Object Prototypes
  • Mod 6 - Data Structures & Algorithms
    • Overview
    • Important How Tos and Guides
      • How to Debug
      • How to PEDAC
    • 1. Nodes & Linked Lists
    • 2. Singly & Doubly Linked Lists
    • 3. Stacks & Queues
    • 4. Recursion
    • 5. Trees
  • Mod 7 - React
    • Overview
    • Important How Tos and Guides
      • How to Create Projects with Vite
      • How to Deploy on GitHub Pages
    • 1. Intro to React
    • 2. Events, State, and Forms
    • 3. Fetching with useEffect
    • 4. React Router
    • 5. Building a Flashcards App
    • 6. React Context
    • 7. Global Context Pattern
  • Mod 8 - Backend
    • Overview
    • Important How Tos and Guides
      • How to Deploy on Render
      • How to Test your API with Postman
      • Postgres Setup
    • 1. Intro to Express
    • 2. Building a Static Web Server with Middleware
    • 3. Securing API Keys and Environment Variables
    • 4. RESTful CRUD API
    • 5. Model-View-Controller Architecture
    • 6. SQL and Databases
    • 7. JOIN (Association) SQL Queries
    • 8. Knex
    • 9. Your First Fullstack App!
    • 10. Migrations & Seeds
    • 11. Schema Design & Normalization
    • 12. Hashing Passwords with Bcrypt
    • 13. React Express Auth Template Overview
  • Mod 9 - Civic Tech Hackathon
    • Overview
    • Rubric
  • Mod 10 - Capstone
    • Overview
Powered by GitBook
On this page
  • Essential Questions
  • Key Terms
  • Nodes
  • Making a Node Class for Linked Lists
  • Making a Linked List Class
  • Algorithm: Prepend to head
  • Algorithm: Append to tail
  • Algorithm: isCyclic
  1. Mod 6 - Data Structures & Algorithms

1. Nodes & Linked Lists

Essential Questions

  • What are the qualities of Graphs

  • What are the tradeoffs between linked lists and arrays?

  • What are the tradeoffs between singly linked lists and doubly linked lists?

  • What are the run times for insertion, deletion, and accessing from linked lists?

Key Terms

  • Graph

  • Node

  • Singly linked list

  • Doubly linked list

  • Random access

  • Sequential access

Nodes

In the Stack and Queue data structure,

A Graph is a category of abstract data type that is used to organize relationships between data.

The thing that all graphs share is that they are comprised of nodes that hold a single piece of data, and edges that connect two nodes.

Q: Consider the abstract data structures below. What do the nodes in each structure point to?

Linked Lists

Doubly Linked Lists

Trees

Making a Node Class for Linked Lists

Nodes themselves typically do not have any methods.

The simplest kind of node is the one used in a linked list. It holds its own data and a pointer to the next node in the list.

// depending on how the node is used, it may have a next, prev, parent, or children, property
class Node {
    constructor(data) {
        this.data = data;
        this.next = null;
    }
}

const nodeA = new Node("a");
const nodeB = new Node("b");
const nodeC = new Node("C");

nodeA.next = nodeB;
nodeB.next = nodeC;

console.log(nodeA, nodeB, nodeC); // What do you expect to see?

Q: What is the head of the linked list? What is the tail?

Making a Linked List Class

The linked list itself holds only a reference to a head node and various methods for modifying or "traversing" the list.

class LinkedList {
    constructor() {
        this.head = null;
    }
    
    appendToTail(data) {}
    prependToHead(data) {}
    removeFromHead() {}
    removeFromTail() {}
    contains() {}
}

"Traversing" is a fancy word for "visiting the nodes in a particular order" in a data structure.

Q: What is the way/what are the ways that we can traverse a linked list?

Some linked lists may also implement:

  • adding a new node in the middle

  • removing a node from the middle

Let's visualize: https://visualgo.net/en/list

Algorithm: Prepend to head

  • Inputs: data to add

  • Output: the new head of the linked list

  • Behavior: the new node should be the new head of the linked list and it should point to the previous head of the linked list

const list = new LinkedList();
list.prependToHead('a')
list.prependToHead('b')
list.prependToHead('c')
console.log(list.head);
console.log(list.head.next);
console.log(list.head.next.next);
// Node { data: 'c', next: Node }
// Node { data: 'b', next: Node }
// Node { data: 'a', next: null }
Solution
class LinkList {
    constructor() {
        this.head = null;
    }
    prependToHead(data) {
        const newNode = new Node(data);
        newNode.next = this.head;
        this.head = newNode;
    }
}
  1. The new node is going at the beginning of the list. So it's next pointer should point to the existing head of the list.

  2. Then, the list's head pointer should now point at the new node.

  3. Test:

    • Adding to a list with multiple nodes

    • Adding to an empty list

    • Adding to a list with one value

Algorithm: Append to tail

  • Inputs: data to add

  • Output: the head of the linked list

  • Behavior: the previous tail node's next property should point to the new node.

const list = new LinkedList();
list.appendToTail('a')
list.appendToTail('b')
list.appendToTail('c')
console.log(list.head);
console.log(list.head.next);
console.log(list.head.next.next);
// Node { data: 'a', next: Node }
// Node { data: 'b', next: Node }
// Node { data: 'c', next: null }
Solution
class LinkList {
    constructor() {
        this.head = null;
    }
    prependToHead(data) { /* ... */ }
    
    appendToTail(data) {
        const newNode = new Node(data);
        if (!this.head) {
            this.head = newNode;
        } 
        else {
            let currNode = this.head;
            while (currNode.next !== null) {
                currNode = currNode.next;
            }
            currNode.next = newNode;
        }
    }
}
  1. To put the new node at the end of the list, we need to first get to the end of the list, starting at the list's head. We'll use a currNode variable to keep track of where we are in the list.

  2. Using a while loop, we iterate as long as the currNode has a next node to move to.

  3. We'll reach the tail node once currNode has no next node. At this point, we set the currNode (which is the tail) to point to the new node.

  4. Test:

    • Adding to a list with multiple nodes

    • Adding to an empty list

    • Adding to a list with one node

Algorithm: isCyclic

This is not a method of linked lists but a method whose input is the head of a linked list. It should return true if the linked list contains a cycle, false otherwise.

const list = new LinkedList();

const nodeA = new Node("a");
const nodeB = new Node("b");
const nodeC = new Node("c");

list.head = nodeA;

nodeA.next = nodeB;
nodeB.next = nodeC;

isCyclic(list.head); // false

nodeC.next = nodeA; // a cycle!

isCyclic(list.head); // true
Solution
function isCyclic(headNode) {

    let nodesEncountered = []; // track nodes we've seen
    
    let currentNode = headNode; // track the current node in our traversal
    
    while(currentNode) { // eventually it will be null
        
        // if we've encountered it before...
        if (nodesEncountered.includes(currentNode)) {
            return true; // we found a cycle!
        } 
        
        // otherwise...
        nodesEncountered.push(currentNode); // add it to the encountered list
        currentNode = currentNode.next; // traverse to the next node
    }
    
    return false;
}
PreviousImportant How Tos and GuidesNext2. Singly & Doubly Linked Lists

Last updated 8 months ago