[Go to site: main page, start]

0% found this document useful (0 votes)
6 views23 pages

DSA JavaScript Notes

The document provides comprehensive notes on Data Structures and Algorithms (DSA) using JavaScript, covering topics such as types of data structures, algorithm complexity, recursion, and various data structures like arrays, stacks, queues, linked lists, trees, and graphs. It includes explanations of fundamental concepts, code examples, and time complexity analysis for different algorithms. The course is structured into 58 videos and is presented in Hindi.

Uploaded by

lataga7517
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views23 pages

DSA JavaScript Notes

The document provides comprehensive notes on Data Structures and Algorithms (DSA) using JavaScript, covering topics such as types of data structures, algorithm complexity, recursion, and various data structures like arrays, stacks, queues, linked lists, trees, and graphs. It includes explanations of fundamental concepts, code examples, and time complexity analysis for different algorithms. The course is structured into 58 videos and is presented in Hindi.

Uploaded by

lataga7517
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

DSA with JavaScript

Complete Course Notes

Code Step By Step • 58 Videos • Hindi

Table of Contents
1. Introduction to Data Structures
2. Types of Data Structures
3. JavaScript Fundamentals for DSA
4. Algorithm Complexity — Time & Space
5. Recursion
6. Arrays
7. Searching Algorithms
8. Sorting Algorithms
9. Stack
10. Queue
11. Linked List
12. Trees & Binary Search Tree
13. Graph
14. Hash Table
1. Introduction to Data Structures

What is a Data Structure?

A Data Structure is a way of organizing, storing, and managing data in a computer so it can be accessed
and modified efficiently — like a container that holds data in a specific format.

What is an Algorithm?

An Algorithm is a step-by-step set of instructions to solve a specific problem. It takes input, processes it,
and produces output. A recipe is a real-world algorithm for cooking.

Why Learn DSA?

• Foundation of every software system (GPS, search engines, games, databases)


• Essential for cracking coding interviews (FAANG, top startups)
• Makes code efficient in both time and memory usage
• Helps solve complex real-world problems elegantly
2. Types of Data Structures

Linear Data Structures

Elements arranged sequentially, one after another.

Structure Key Feature

Array Fixed size, O(1) index access

Stack LIFO — Last In, First Out

Queue FIFO — First In, First Out

Linked List Dynamic size, node-based pointers

Non-Linear Data Structures

Elements arranged hierarchically or networked.

Structure Key Feature

Tree Hierarchical, parent-child relationships

Graph Nodes connected by edges (network model)

Hash Table Key-value pairs, average O(1) lookup


3. JavaScript Fundamentals for DSA

Variables, Functions & Loops

// Variables
let num = 10; let str = "hello"; let arr = [1, 2, 3];

// Arrow function
const multiply = (a, b) => a * b;

// For loop
for (let i = 0; i < 5; i++) { [Link](i); }

// While loop
let i = 0;
while (i < 5) { [Link](i++); }

Arrays & Objects

let arr = [10, 20, 30];


[Link](40); // add to end
[Link](); // remove from end
[Link](5); // add to beginning
[Link](); // remove from beginning

let person = { name: "Ali", age: 25 };


[Link] = function() { [Link]("Hello, " + [Link]); };

Classes (Used to implement Data Structures)

class Node {
constructor(data) {
[Link] = data;
[Link] = null;
}
}
4. Algorithm Complexity — Time & Space

Big-O Notation

Big-O describes the worst-case performance of an algorithm as input size n grows.

Big-O Name Example

O(1) Constant Array index access

O(log n) Logarithmic Binary Search

O(n) Linear Linear Search

O(n log n) Linearithmic Merge Sort

O(n²) Quadratic Bubble Sort (nested loops)

O(2■) Exponential Recursive Fibonacci

Time Complexity Examples

// O(1) — constant: always 1 step


function getFirst(arr) { return arr[0]; }

// O(n) — linear: n steps


function printAll(arr) {
for (let i = 0; i < [Link]; i++) [Link](arr[i]);
}

// O(n^2) — quadratic: n x n steps


function printPairs(arr) {
for (let i = 0; i < [Link]; i++)
for (let j = 0; j < [Link]; j++)
[Link](arr[i], arr[j]);
}

Space Complexity

// O(1) space — fixed extra memory regardless of input


function sum(arr) {
let total = 0;
for (let x of arr) total += x;
return total;
}

// O(n) space — creates new array proportional to input


function double(arr) {
let result = [];
for (let x of arr) [Link](x * 2);
return result;
}

Rules for Calculating Big-O

• Drop constants: O(2n) becomes O(n)


• Drop non-dominant terms: O(n² + n) becomes O(n²)
• Different inputs = different variables: O(a + b) when processing two separate arrays
5. Recursion
A function that calls itself until a base condition is met. Each call is pushed onto the call stack; when the
base case is hit, calls unwind.

Factorial

function factorial(n) {
if (n === 0) return 1; // base case
return n * factorial(n - 1); // recursive case
}
// factorial(5) = 5 x 4 x 3 x 2 x 1 = 120

Fibonacci

function fibonacci(n) {
if (n <= 1) return n; // base cases: fib(0)=0, fib(1)=1
return fibonacci(n-1) + fibonacci(n-2);
}
// fibonacci(6) = 8

■ Note: Naive Fibonacci is O(2^n) — very slow. Use memoization for large inputs.

Recursion vs Iteration

Feature Recursion Iteration

Code style Cleaner, shorter Longer but explicit

Memory Uses call stack (more) Usually less memory

Speed Can be slower Generally faster

Best for Trees, graphs, divide & conquer Simple sequential loops
6. Arrays
An ordered collection of elements stored at contiguous memory locations, accessible via index starting
from 0.

Operations & Complexity

Operation Method Time Complexity

Access arr[i] O(1)

Search Loop O(n)

Insert at end push() O(1)

Remove from end pop() O(1)

Insert at start unshift() O(n)

Remove from start shift() O(n)

Insert at middle splice() O(n)

Common Array Methods

let arr = [3, 1, 4, 1, 5, 9, 2];


[Link](4); // 2 — index of value
[Link](9); // true
[Link](); // reverses in place
[Link]((a, b) => a-b); // sort ascending
[Link](1, 3); // [1, 4] — non-mutating
[Link](2, 1, 99); // remove 1 at index 2, insert 99
[Link](x => x * 2); // new array, each element doubled
[Link](x => x > 3); // new array, elements > 3
[Link]((acc,x) => acc+x, 0); // sum all elements
7. Searching Algorithms

7.1 Linear Search

Check each element one by one from start to end.


function linearSearch(arr, target) {
for (let i = 0; i < [Link]; i++) {
if (arr[i] === target) return i; // found -> return index
}
return -1; // not found
}
linearSearch([10, 25, 3, 7, 40], 7); // returns 3

• Time: O(n) | Space: O(1)


• Works on unsorted AND sorted arrays
• Best for small datasets

7.2 Binary Search

Repeatedly halve the search space by comparing with the middle element.
■ Note: Requires a SORTED array!

function binarySearch(arr, target) {


let left = 0, right = [Link] - 1;
while (left <= right) {
let mid = [Link]((left + right) / 2);
if (arr[mid] === target) return mid;
else if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
}
binarySearch([2,5,8,12,16,23,38], 23); // returns 5

Comparison

Feature Linear Search Binary Search

Sorted array needed? No Yes

Time Complexity O(n) O(log n)

For n = 1,000,000 ~1M steps ~20 steps


8. Sorting Algorithms

8.1 Bubble Sort

Repeatedly swap adjacent elements if in wrong order. Largest elements bubble up.
function bubbleSort(arr) {
let n = [Link];
for (let i = 0; i < n - 1; i++) {
for (let j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j+1])
[arr[j], arr[j+1]] = [arr[j+1], arr[j]];
}
}
return arr;
}

8.2 Selection Sort

Find the minimum element in unsorted portion, place it at the front.


function selectionSort(arr) {
let n = [Link];
for (let i = 0; i < n - 1; i++) {
let minIdx = i;
for (let j = i + 1; j < n; j++)
if (arr[j] < arr[minIdx]) minIdx = j;
[arr[i], arr[minIdx]] = [arr[minIdx], arr[i]];
}
return arr;
}

8.3 Insertion Sort

Build sorted array one element at a time by inserting each into its correct position.
function insertionSort(arr) {
for (let i = 1; i < [Link]; i++) {
let key = arr[i], j = i - 1;
while (j >= 0 && arr[j] > key) { arr[j+1] = arr[j]; j--; }
arr[j+1] = key;
}
return arr;
}

8.4 Merge Sort

Divide into halves, sort each recursively, then merge.


function mergeSort(arr) {
if ([Link] <= 1) return arr;
let mid = [Link]([Link] / 2);
let left = mergeSort([Link](0, mid));
let right = mergeSort([Link](mid));
return merge(left, right);
}
function merge(left, right) {
let result = []; let i = 0, j = 0;
while (i < [Link] && j < [Link])
[Link](left[i] <= right[j] ? left[i++] : right[j++]);
return [Link]([Link](i)).concat([Link](j));
}

8.5 Quick Sort

Choose a pivot, partition smaller left / larger right, sort both sides recursively.
function quickSort(arr, low=0, high=[Link]-1) {
if (low < high) {
let p = partition(arr, low, high);
quickSort(arr, low, p - 1);
quickSort(arr, p + 1, high);
}
return arr;
}
function partition(arr, low, high) {
let pivot = arr[high], i = low - 1;
for (let j = low; j < high; j++)
if (arr[j] <= pivot) { i++; [arr[i],arr[j]]=[arr[j],arr[i]]; }
[arr[i+1],arr[high]]=[arr[high],arr[i+1]];
return i + 1;
}

Sorting Summary Table

Algorithm Best Average Worst Space Stable

Bubble Sort O(n) O(n²) O(n²) O(1) Yes

Selection Sort O(n²) O(n²) O(n²) O(1) No

Insertion Sort O(n) O(n²) O(n²) O(1) Yes

Merge Sort O(n log n) O(n log n) O(n log n) O(n) Yes

Quick Sort O(n log n) O(n log n) O(n²) O(log n) No


9. Stack
A linear data structure following LIFO — Last In, First Out. Like a stack of plates: add on top, remove from
top.

Operations

Operation Description Time

push(x) Add element to top O(1)

pop() Remove & return top O(1)

peek() View top (no removal) O(1)

isEmpty() Check if empty O(1)

Implementation

class Stack {
constructor() { [Link] = []; }
push(el) { [Link](el); }
pop() { return [Link]() ? "Underflow" : [Link](); }
peek() { return [Link][[Link] - 1]; }
isEmpty() { return [Link] === 0; }
size() { return [Link]; }
}

Real-World Applications

• Undo/Redo in text editors (Ctrl+Z)


• Browser Back button (history stack)
• Function Call Stack in JavaScript
• Balanced parentheses checking
• Expression evaluation (infix → postfix)

Example: Balanced Parentheses

function isBalanced(str) {
let stack = [], map = { ')':'(', '}':'{', ']':'[' };
for (let c of str) {
if ('({['.includes(c)) [Link](c);
else if ([Link]() !== map[c]) return false;
}
return [Link] === 0;
}
isBalanced("{[()]}"); // true
isBalanced("{[(])}"); // false
10. Queue
A linear data structure following FIFO — First In, First Out. Like a line at a ticket counter: first person in,
first served.

Operations

Operation Description Time

enqueue(x) Add element to rear O(1)

dequeue() Remove & return front O(1)

front() View front element O(1)

isEmpty() Check if empty O(1)

Implementation

class Queue {
constructor() { [Link] = []; }
enqueue(el) { [Link](el); }
dequeue() { return [Link]() ? "Underflow" : [Link](); }
front() { return [Link][0]; }
isEmpty() { return [Link] === 0; }
size() { return [Link]; }
}

Real-World Applications

• CPU process scheduling


• Printer job queue
• BFS graph traversal
• Call center systems
• Keyboard input buffer
11. Linked List
A dynamic linear data structure where elements (nodes) are stored at non-contiguous memory
locations, connected via pointers. Each node holds data and a reference to the next node.

Array vs Linked List

Feature Array Linked List

Size Fixed (static) Dynamic

Memory Contiguous Non-contiguous

Access O(1) — by index O(n) — traverse

Insert/Delete start O(n) O(1)

Insert/Delete end O(1) O(n) / O(1) with tail

Full Singly Linked List Implementation

class Node {
constructor(data) { [Link] = data; [Link] = null; }
}
class LinkedList {
constructor() { [Link] = null; [Link] = 0; }

append(data) { // Add to end — O(n)


let node = new Node(data);
if (![Link]) { [Link] = node; }
else {
let cur = [Link];
while ([Link]) cur = [Link];
[Link] = node;
}
[Link]++;
}
prepend(data) { // Add to beginning — O(1)
let node = new Node(data);
[Link] = [Link]; [Link] = node; [Link]++;
}
delete(data) { // Delete by value — O(n)
if (![Link]) return;
if ([Link] === data) { [Link] = [Link]; return; }
let cur = [Link];
while ([Link]) {
if ([Link] === data) { [Link] = [Link]; return; }
cur = [Link];
}
}
search(data) { // Search — O(n)
let cur = [Link], i = 0;
while (cur) { if ([Link] === data) return i; cur = [Link]; i++; }
return -1;
}
traverse() { // Print all nodes
let cur = [Link], out = [];
while (cur) { [Link]([Link]); cur = [Link]; }
[Link]([Link](" -> "));
}
}

Types of Linked Lists

• Singly: each node points to next only → [10|•] → [20|•] → [null]


• Doubly: each node has prev AND next pointers → bidirectional traversal
• Circular: last node points back to head → forms a loop
12. Trees & Binary Search Tree
A non-linear hierarchical data structure with nodes connected by edges. A Binary Tree has at most 2
children per node. A BST adds the ordering property: left values < root < right values.

Key Terminology

Term Meaning

Root Top node — no parent

Leaf Node with no children

Height Longest path from root to leaf

Depth Distance from root to a node

Inorder Left → Root → Right (gives sorted output for BST)

Preorder Root → Left → Right (good for copying)

Postorder Left → Right → Root (good for deleting)

BST Implementation

class TreeNode { constructor(d) { [Link]=d; [Link]=[Link]=null; } }

class BST {
constructor() { [Link] = null; }

insert(data) {
let node = new TreeNode(data);
if (![Link]) { [Link] = node; return; }
let cur = [Link];
while (true) {
if (data < [Link]) {
if (![Link]) { [Link] = node; return; } else cur = [Link];
} else {
if (![Link]) { [Link] = node; return; } else cur = [Link];
}
}
}
search(data) {
let cur = [Link];
while (cur) {
if (data === [Link]) return true;
cur = data < [Link] ? [Link] : [Link];
}
return false;
}
}
All 4 Traversals

// Inorder — Left, Root, Right


function inorder(node) { if(!node)return; inorder([Link]); [Link]([Link]); inorder([Link]

// Preorder — Root, Left, Right


function preorder(node) { if(!node)return; [Link]([Link]); preorder([Link]); preorder(node.

// Postorder — Left, Right, Root


function postorder(node) { if(!node)return; postorder([Link]); postorder([Link]); [Link](no

// Level Order (BFS) — uses Queue


function levelOrder(root) {
let q = [root];
while ([Link]) {
let node = [Link]();
[Link]([Link]);
if ([Link]) [Link]([Link]);
if ([Link]) [Link]([Link]);
}
}

BST Complexity

Operation Average (Balanced) Worst (Skewed)

Search O(log n) O(n)

Insert O(log n) O(n)

Delete O(log n) O(n)


13. Graph
A non-linear data structure of vertices (nodes) and edges (connections). Models networks: social
graphs, road maps, web pages, etc.

Types of Graphs

• Undirected: A—B means both directions


• Directed (Digraph): A→B does NOT imply B→A
• Weighted: edges carry a cost/distance value
• Connected: every vertex reachable from every other

Graph Representation — Adjacency List

class Graph {
constructor() { [Link] = {}; }

addVertex(v) { if (![Link][v]) [Link][v] = []; }

addEdge(v1, v2) { // undirected


[Link][v1].push(v2);
[Link][v2].push(v1);
}
removeEdge(v1, v2) {
[Link][v1] = [Link][v1].filter(v => v !== v2);
[Link][v2] = [Link][v2].filter(v => v !== v1);
}
}

DFS — Depth First Search

dfs(start) {
let visited = {}, result = [];
const explore = (vertex) => {
visited[vertex] = true; [Link](vertex);
[Link][vertex].forEach(nb => { if (!visited[nb]) explore(nb); });
};
explore(start); return result;
}

BFS — Breadth First Search

bfs(start) {
let queue = [start], visited = { [start]: true }, result = [];
while ([Link]) {
let vertex = [Link](); [Link](vertex);
[Link][vertex].forEach(nb => {
if (!visited[nb]) { visited[nb] = true; [Link](nb); }
});
}
return result;
}

DFS vs BFS

Feature DFS BFS

Data Structure Stack / Recursion Queue

Shortest Path Not guaranteed Yes (unweighted graphs)

Space O(h) — tree height O(w) — max width

Use Case Cycle detection, topological sort Shortest path, level traversal
14. Hash Table
Stores key-value pairs and uses a hash function to map keys to array indices, enabling average O(1)
insert, search, and delete.

Hash Table Implementation

class HashTable {
constructor(size = 53) { [Link] = new Array(size); }

_hash(key) {
let total = 0, PRIME = 31;
for (let i = 0; i < [Link]([Link], 100); i++)
total = (total * PRIME + [Link](i) - 96) % [Link];
return total;
}
set(key, value) {
let idx = this._hash(key);
if (![Link][idx]) [Link][idx] = [];
for (let pair of [Link][idx])
if (pair[0] === key) { pair[1] = value; return; }
[Link][idx].push([key, value]);
}
get(key) {
let idx = this._hash(key);
if (![Link][idx]) return undefined;
for (let pair of [Link][idx]) if (pair[0] === key) return pair[1];
}
delete(key) {
let idx = this._hash(key);
if (![Link][idx]) return false;
[Link][idx] = [Link][idx].filter(p => p[0] !== key);
return true;
}
}

JavaScript Built-in Hash Structures

// Map — best for frequent add/delete, any key type


let map = new Map();
[Link]("name", "Ali"); [Link]("name"); // "Ali"
[Link]("name"); // true
[Link]("name"); [Link]; // 0

// Set — stores only unique values


let set = new Set([1, 2, 3, 2, 1]);
[Link]([...set]); // [1, 2, 3]
[Link](4); [Link](2); // true
Collision Handling

• Separate Chaining: each index holds an array/linked list of key-value pairs


• Open Addressing (Linear Probing): if slot is occupied, try the next slot

Complexity

Operation Average Worst (many collisions)

Insert O(1) O(n)

Search O(1) O(n)

Delete O(1) O(n)


Master Complexity Reference

Structure Access Search Insert Delete Space

Array O(1) O(n) O(n) O(n) O(n)

Stack O(n) O(n) O(1) O(1) O(n)

Queue O(n) O(n) O(1) O(1) O(n)

Linked List O(n) O(n) O(1) O(1) O(n)

BST (avg) O(log n) O(log n) O(log n) O(log n) O(n)

Hash Table N/A O(1) O(1) O(1) O(n)

Graph O(V+E) O(V+E) O(1) O(E) O(V+E)

Key Takeaways

• Choose the right data structure — it makes all the difference in performance
• Always analyze complexity: time AND space before committing to an approach
• Recursion is powerful — always define a clear base case to avoid infinite loops
• Arrays for random access; Linked Lists for dynamic inserts/deletes
• Stacks for LIFO problems (undo, call stack); Queues for FIFO (scheduling, BFS)
• BSTs give O(log n) average operations when balanced
• Graphs model real-world networks; choose DFS or BFS based on the problem
• Hash Tables give O(1) average key-value lookups — incredibly powerful

Notes compiled from: DSA with JavaScript in Hindi — Code Step By Step (58 videos)

You might also like