Arrays: Static, Dynamic & Multi-dimensional

অ্যারে — static, dynamic, multi-dim

Read: ~30 min Beginner 7 practice problems Live C++ runner

1. Why Arrays — The Original Data Structure

An array is the simplest and most fundamental data structure in computer science. It is a contiguous block of memory holding elements of the same type. Because the elements sit side-by-side, the CPU can compute the address of element i with a single multiplication — giving us O(1) random access, the property every other data structure envies.

অ্যারে হলো কম্পিউটার বিজ্ঞানের সবচেয়ে মৌলিক data structure। এটি একই type-এর কতগুলো element একসাথে স্মৃতিতে পাশাপাশি সাজিয়ে রাখে। ফলে i-তম element-এর address বের করতে শুধু একটি গুণ লাগে — যা O(1) random access নিশ্চিত করে। অন্য সব data structure এই গুণটিকে ঈর্ষা করে।
Module insight vector যখন capacity শেষ করে double করে — তখন প্রতিটি push_back amortised O(1)।

2. Memory Layout — How an Array Lives in RAM

Suppose you declare int a[6]; and the compiler places it at address 0x1000. Each int occupies 4 bytes, so element a[i] sits at 0x1000 + i × 4. The CPU can jump straight to it — no scan, no pointer chase.

ধরা যাক int a[6]; declare করলেন এবং compiler array-টি 0x1000 address-এ বসালো। প্রতিটি int 4 byte নেয়, তাই a[i] থাকবে 0x1000 + i × 4 address-এ। CPU সরাসরি সেই জায়গায় চলে যেতে পারে — কোনো খোঁজাখুঁজি লাগে না।
int a[6] = {7, 3, 9, 1, 8, 5}; 7 3 9 1 8 5 a[0] a[1] a[2] a[3] a[4] a[5] 0x1000 0x1004 0x1008 0x100C 0x1010 0x1014 Figure 6.1 — Array elements live in contiguous memory; address(a[i]) = base + i × sizeof(int)।
Common bug Reading a[6] in the array above is out-of-bounds. C++ does not check; you may read garbage, crash, or worse — silently corrupt unrelated data.
সতর্কতা: উপরের array-তে a[6] পড়লে out-of-bounds হবে। C++ check করে না — আপনি garbage পেতে পারেন, crash করতে পারে, এমনকি অন্য data নষ্ট হতে পারে।

3. Static vs Dynamic — Two Flavours

A static array (int a[100];) has a fixed size known at compile time. A dynamic array (std::vector<int>) can grow at runtime. How does vector grow? It allocates a bigger buffer, copies the old elements, then frees the old one — typically doubling capacity each time. This doubling trick is what makes push_back amortised O(1).

Static array-এর size compile-time-এই fixed (int a[100];)। Dynamic array (std::vector) runtime-এ বড় হতে পারে। কিভাবে? আগের চেয়ে বড় একটি buffer allocate করে পুরনো element-গুলো copy করে, পুরনোটিকে free করে দেয়। সাধারণত capacity প্রতিবার দ্বিগুণ করা হয় — এই doubling কৌশলই push_back-কে amortised O(1) রাখে।
Capacity doubling: 1 → 2 → 4 → 8 → 16 → 32 cap=1 cap=2 cap=4 cap=8 cap=16 Figure 6.2 — Dark বার = size, হালকা বার = capacity. Capacity শেষ হলেই double করে নতুন buffer।

4. Demo 1 — Build Your Own Dynamic Array

Let's implement a tiny DynArr that doubles its capacity on every overflow. This is essentially what std::vector does under the hood.

চলুন একটি ছোট DynArr বানাই, যেটি capacity শেষ হলে নিজেকে দ্বিগুণ করে। std::vector ভেতরে ভেতরে এটিই করে।
dynarr.cpp
#include <bits/stdc++.h>
using namespace std;

struct DynArr {
    int* data;
    int sz, cap;
    DynArr() { cap = 1; sz = 0; data = new int[cap]; }
    void push_back(int x) {
        if (sz == cap) {
            cap *= 2;
            int* nd = new int[cap];
            for (int i = 0; i < sz; i++) nd[i] = data[i];
            delete[] data;
            data = nd;
        }
        data[sz++] = x;
    }
    int get(int i) { return data[i]; }
};

int main() {
    DynArr a;
    for (int i = 1; i <= 10; i++) a.push_back(i * i);
    cout << "size = " << a.sz << ", capacity = " << a.cap << "\n";
    for (int i = 0; i < a.sz; i++) cout << a.get(i) << " ";
    cout << "\n";
    return 0;
}
Amortised analysis: Inserting n elements involves at most n + n/2 + n/4 + ... < 2n element copies. So total work = O(n), per insert = O(1) on average.
সারমর্ম: n element insert করতে সর্বোচ্চ ~2n copy লাগে — তাই গড়ে প্রতিটি insert O(1)।

5. Demo 2 — Rotate an Array Left by k

Given an array [1,2,3,4,5,6,7] and k=3, the result should be [4,5,6,7,1,2,3]. The clever three-reverse trick does it in O(n) time and O(1) extra space.

[1,2,3,4,5,6,7] এবং k=3 দিলে output হবে [4,5,6,7,1,2,3]। তিনবার reverse-এর কৌশলে এটি O(n) সময়ে এবং O(1) extra space-এ করা যায়: প্রথম k element reverse → বাকি n-k reverse → পুরো array reverse।
rotate.cpp
#include <bits/stdc++.h>
using namespace std;

void rev(vector<int>& a, int l, int r) {
    while (l < r) swap(a[l++], a[r--]);
}

void rotateLeft(vector<int>& a, int k) {
    int n = a.size();
    k %= n;
    rev(a, 0, k - 1);
    rev(a, k, n - 1);
    rev(a, 0, n - 1);
}

int main() {
    vector<int> a = {1,2,3,4,5,6,7};
    rotateLeft(a, 3);
    for (int x : a) cout << x << " ";
    cout << "\n";
    return 0;
}

6. 2D Arrays & Matrices

A 2D array is just a 1D array laid out row-by-row in memory (row-major order in C/C++). int m[3][4] takes 3 × 4 × 4 = 48 bytes; element m[i][j] sits at base + (i × 4 + j) × 4.

2D array আসলে memory-তে row-by-row সাজানো একটি 1D array (C/C++-এ row-major)। m[i][j]-এর ঠিকানা = base + (i × cols + j) × sizeof(elem)। তাই matrix traversal-এ row-by-row লুপ করলে CPU cache অনেক বেশি hit করে — অনেক দ্রুত চলে।
OperationStatic arraystd::vector
Access by indexO(1)O(1)
Insert at end—amortised O(1)
Insert at middle—O(n)
Erase at end—O(1)
Erase at middle—O(n)
Search (unsorted)O(n)O(n)

7. Common Bugs & Pitfalls

✅ Best Practice

  • Always check i < n before a[i]
  • Use vector::at() while debugging — it throws on OOB
  • Reserve capacity (v.reserve(n)) when n is known
  • Pass large arrays by reference, never by value

⚠️ Mistakes to Avoid

  • Off-by-one: for(i=0;i<=n;i++)
  • Reading a[n] after a loop ends
  • Using sizeof(arr)/sizeof(arr[0]) on a function parameter
  • Forgetting that vector may invalidate iterators on growth
Real story: A Codeforces solution that "passed locally" but TLE-d on judge often had vector reallocations inside an inner loop. Always v.reserve(n) for hot paths.

8. Practice Problems

Try each problem first, then click Show Answer to compare with a runnable solution.

প্রতিটি প্রশ্ন আগে নিজে চেষ্টা করুন, তারপর Show Answer-এ ক্লিক করে runnable C++ সমাধানের সাথে মেলান।
  1. Find the maximum subarray sum using the naive O(n²) approach.
    Naive O(n²) পদ্ধতিতে maximum subarray sum বের করুন।
    ✨ Show Answer (উত্তর দেখুন)
    ans1.cpp
    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        vector<int> a = {-2,1,-3,4,-1,2,1,-5,4};
        int n = a.size(), best = INT_MIN;
        for (int i = 0; i < n; i++) {
            int s = 0;
            for (int j = i; j < n; j++) { s += a[j]; best = max(best, s); }
        }
        cout << best << "\n";
    }
  2. Reverse an array in-place using two pointers.
    Two-pointer পদ্ধতিতে in-place একটি array reverse করুন।
    ✨ Show Answer (উত্তর দেখুন)
    ans2.cpp
    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        vector<int> a = {1,2,3,4,5};
        int l = 0, r = a.size() - 1;
        while (l < r) swap(a[l++], a[r--]);
        for (int x : a) cout << x << " ";
        cout << "\n";
    }
  3. Rotate an array right by k positions in O(n) time and O(1) space.
    O(n) সময় ও O(1) space-এ array-কে ডানে k বার rotate করুন।
    ✨ Show Answer (উত্তর দেখুন)
    ans3.cpp
    #include <bits/stdc++.h>
    using namespace std;
    void rev(vector<int>& a,int l,int r){while(l<r) swap(a[l++],a[r--]);}
    int main() {
        vector<int> a = {1,2,3,4,5,6,7};
        int n = a.size(), k = 3 % n;
        rev(a,0,n-1); rev(a,0,k-1); rev(a,k,n-1);
        for (int x : a) cout << x << " ";
        cout << "\n";
    }
  4. Print a 2D matrix in spiral order.
    2D matrix-কে spiral order-এ print করুন।
    ✨ Show Answer (উত্তর দেখুন)
    ans4.cpp
    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        vector<vector<int>> m = {{1,2,3},{4,5,6},{7,8,9}};
        int top=0, bot=m.size()-1, lt=0, rt=m[0].size()-1;
        while (top <= bot && lt <= rt) {
            for (int j=lt;j<=rt;j++) cout << m[top][j] << " "; top++;
            for (int i=top;i<=bot;i++) cout << m[i][rt] << " "; rt--;
            if (top <= bot) { for (int j=rt;j>=lt;j--) cout << m[bot][j] << " "; bot--; }
            if (lt <= rt)  { for (int i=bot;i>=top;i--) cout << m[i][lt] << " "; lt++; }
        }
        cout << "\n";
    }
  5. Find the second largest element in a single pass.
    Array-এ একবার ঘুরেই দ্বিতীয় সর্বোচ্চ element বের করুন।
    ✨ Show Answer (উত্তর দেখুন)
    ans5.cpp
    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        vector<int> a = {12,35,1,10,34,35,1};
        int first = INT_MIN, second = INT_MIN;
        for (int x : a) {
            if (x > first) { second = first; first = x; }
            else if (x > second && x < first) second = x;
        }
        cout << second << "\n";
    }
  6. Move all zeros to the end of the array, preserving order of non-zeros, in O(n).
    Array-এর সব 0-কে শেষে সরান (non-zero-দের আপেক্ষিক order বজায় রেখে), O(n)-এ।
    ✨ Show Answer (উত্তর দেখুন)
    ans6.cpp
    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        vector<int> a = {0,1,0,3,12};
        int j = 0;
        for (int i = 0; i < (int)a.size(); i++)
            if (a[i] != 0) swap(a[i], a[j++]);
        for (int x : a) cout << x << " ";
        cout << "\n";
    }
  7. Given two sorted arrays, merge them into a single sorted array.
    দুটি sorted array-কে merge করে একটি sorted array বানান।
    ✨ Show Answer (উত্তর দেখুন)
    ans7.cpp
    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        vector<int> a = {1,3,5,7}, b = {2,4,6,8,10};
        vector<int> c;
        int i=0, j=0;
        while (i < (int)a.size() && j < (int)b.size()) {
            if (a[i] <= b[j]) c.push_back(a[i++]);
            else c.push_back(b[j++]);
        }
        while (i < (int)a.size()) c.push_back(a[i++]);
        while (j < (int)b.size()) c.push_back(b[j++]);
        for (int x : c) cout << x << " ";
        cout << "\n";
    }

Summary — Module 06

Arrays are contiguous blocks of memory that give us O(1) random access. Static arrays have a fixed compile-time size; dynamic arrays like std::vector grow by doubling capacity, making push_back amortised O(1). 2D arrays are stored row-major in C/C++. Watch for off-by-one and out-of-bounds bugs — they cause more crashes in CSE Bangladesh contests than any other class of mistake.

Array হলো memory-তে পাশাপাশি সাজানো same-type element-এর block — যা O(1) random access দেয়। Static array compile-time-এই fixed size, কিন্তু std::vector capacity দ্বিগুণ করে বড় হয়, ফলে push_back amortised O(1)। 2D array C/C++-এ row-major-এ থাকে। off-by-one এবং out-of-bounds bug আজকের ICPC Dhaka contest-এ সবচেয়ে বেশি crash ঘটায় — সাবধান।

Next Module → Strings & Pattern Basics — character array থেকে naive matching পর্যন্ত।