NeonArmageddon
NeonArmageddon

Reputation: 21

Optimizing memory usage in TimSort

I've written a simple implementation of TimSort, with which I sort structures that have fields for ID and Points (they're supposed to be test scores) like such:

struct funkc {
    int id;
    int punkty;
};


void insertSort(funkc arr[], int left, int right) {
    for (int i = left + 1; i <= right; i++) {
        funkc key = arr[i];
        int j = i - 1;
        while (j >= left && arr[j].punkty > key.punkty) {
            arr[j + 1] = arr[j];
            j--;
        }
        arr[j + 1] = key;
    }
}

void merge(funkc arr[], int left, int mid, int right) {
    int n1 = mid - left + 1;
    int n2 = right - mid;

    funkc* L = new funkc[n1];
    funkc* R = new funkc[n2];

    for (int i = 0; i < n1; i++) {
        L[i] = arr[left + i];
    }
    for (int j = 0; j < n2; j++) {
        R[j] = arr[mid + 1 + j];
    }

    int i = 0, j = 0, k = left;
    while (i < n1 && j < n2) {
        if (L[i].punkty <= R[j].punkty) {
            arr[k] = L[i];
            i++;
        } else {
            arr[k] = R[j];
            j++;
        }
        k++;
    }

    while (i < n1) {
        arr[k] = L[i];
        i++;
        k++;
    }

    while (j < n2) {
        arr[k] = R[j];
        j++;
        k++;
    }

    delete[] L;
    delete[] R;
}

void timSort(funkc arr[], int n) {
    const int RUN = 32;
    for (int i = 0; i < n; i += RUN) {
        insertSort(arr, i, min((i + RUN - 1), (n - 1)));
    }

    for (int size = RUN; size < n; size = 2 * size) {
        for (int left = 0; left < n; left += 2 * size) {
            int mid = left + size - 1;
            int right = min((left + 2 * size - 1), (n - 1));
            if(mid < right)
                merge(arr, left, mid, right);
        }
    }
}

int main() {
    ios_base::sync_with_stdio(false);

    int n = 0;
    cin >> n ;
    funkc* arr = new funkc[n];
    for (int i = 0; i < n; i++){
        funkc f;
        f.id = i;
        f.punkty =  (rand() % 1000001);
        arr[i] = f;

    }

    timSort(arr, n);


    for (int i = 0; i < n; i++) {
        cout << arr[i].punkty << " ";
    }

    delete[] arr;

    return 0;
}

However, the tests I'm trying to pass my program through, have a strict memory limit. It does fine enough in most cases, but for the test with over 22 million elements to sort, this implementation doesn't fit in the memory allowed. I'm looking for ways to somehow lower this algorithm's memory usage. The exact size of the test is 22500024 elements, and we're only allowed 42000 kB of memory, my program is just a bit above that, using 45244 kB

An idea I've tried was to move the L and R arrays out of the merge function and into the timSort function, so that they're not initialized multiple times in the

for (int size = RUN; size < n; size = 2 * size) {
        for (int left = 0; left < n; left += 2 * size) {
            int mid = left + size - 1;
            int right = min((left + 2 * size - 1), (n - 1));
            if(mid < right)
                merge(arr, left, mid, right);
        }
    }

loop, but it only broke what was already working, so I'm not sure if it was a good direction to go in.

I also tried adjusting the RUN size in TimSort, but it seems that it doesn't actually affect the memory used at all.

Upvotes: 0

Views: 90

Answers (0)

Related Questions