Skip to content

Instantly share code, notes, and snippets.

@Cxarli
Created May 31, 2018 20:27
Show Gist options
  • Save Cxarli/aea94e5fc1e7df0fbf2f17b436fb6bdf to your computer and use it in GitHub Desktop.
Save Cxarli/aea94e5fc1e7df0fbf2f17b436fb6bdf to your computer and use it in GitHub Desktop.
My implementation of the pascal triangle
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
/// Get the n-th row of the pascal triangle
/// NOTE: This is a pure, recursive function without caching
/// n: the nth row to calculate
/// row: the pointer to an array with n+1 elements to store the row in
void pure_get_row(uint32_t n, uint32_t *row) {
if (n == 0) {
row[0] = 1;
return;
}
uint32_t *prev_row = malloc(n * sizeof(uint32_t));
pure_get_row(n-1, prev_row);
row[0] = prev_row[0]; // == 1
for (uint32_t i=1; i < n; i++) {
row[i] = prev_row[i - 1] + prev_row[i];
}
row[n] = prev_row[n - 1]; // == 1
}
/// Get the n-th row of the pascal triangle
/// NOTE: This is a non-pure, recursive function with caching
/// n: the nth row to get or calculate
/// cache: an array of arrays to retrieve or store the rows | NULL
/// row: the row to store the result in | NULL
/// NOTE: cache xor row has to be non-null
/// WARNING: Allocates memory for row if both cache and row are NULL; cache has precedence over row
uint32_t *get_row_with_cache(uint32_t n, uint32_t **cache, uint32_t *row) {
// Check if the row already exists in the cache
if (cache != NULL && cache[n][0] != (uint32_t) -1) {
return cache[n];
}
// Get the location to store the row
if (cache != NULL) {
row = cache[n];
}
else if (row == NULL) {
// Neither cache nor row given, so allocate some memory
row = malloc((n+1) * sizeof(uint32_t));
}
// --- Calculate the row
// Hard-coding first row
if (n == 0) {
row[0] = 1;
return row;
}
uint32_t *prev_row = get_row_with_cache(n - 1, cache, NULL);
row[0] = prev_row[0];
for (uint32_t i=1; i < n; i++) {
row[i] = prev_row[i - 1] + prev_row[i];
}
row[n] = prev_row[n - 1];
// Since there was no cache, `prev_row` has been allocated, so we should free it
if (cache == NULL) {
free(prev_row);
}
return row;
}
/// Wrapper around `get_row_with_cache` to use it without cache
void get_row_without_cache(uint32_t n, uint32_t *row) {
get_row_with_cache(n, NULL, row);
}
/// Initialise the `cache` variable with `size` so it can be used
void cache_init(uint32_t **cache, size_t size) {
for (size_t i=0; i < size; i++) {
cache[i] = malloc((i + 1) * sizeof(uint32_t));
cache[i][0] = (uint32_t) -1;
}
}
/// Free all resources malloc'ed by `cache_init`
void cache_free(uint32_t **cache, size_t size) {
for (size_t i=0; i < size; i++) {
free(cache[i]);
}
}
/// If you need to read this description, you'd better go to sleep
#define print_n_spaces(n) printf("%*s", (n), "")
int main(void) {
#ifndef AMOUNT_ROWS
#define AMOUNT_ROWS 15
#endif
// NOTE: Works best with odd numbers because there's a centre point
#define MAX_WIDTH_NUMBER 7
// Make sure one and only one algorithm is chosen
#if (defined(CACHE) + defined(NO_CACHE) + defined(SEQ)) != 1
#error "Specify CACHE, NO_CACHE xor SEQ"
// To mute future errors that'll arrive from this issue
uint32_t *row = NULL;
#endif
// Make sure SEQ+SINGLE is declared invalid
#if defined(SEQ) && defined(SINGLE)
#error "Are you sure you want to get a single value with the sequential algorithm?"
#endif
#ifdef CACHE
uint32_t *cache[AMOUNT_ROWS + 1];
cache_init((uint32_t**) &cache, AMOUNT_ROWS + 1);
#endif
#ifdef SEQ
uint32_t *prev = malloc((AMOUNT_ROWS + 1) * sizeof(uint32_t));
uint32_t *row = malloc((AMOUNT_ROWS + 1) * sizeof(uint32_t));
row[0] = (uint32_t) -1;
prev[0] = (uint32_t) -1;
// Act as if we have a complete cache, while only giving two values
uint32_t *mini_cache[2];
mini_cache[0] = prev;
mini_cache[1] = row;
#endif
#ifdef SINGLE
for (uint32_t n_row = AMOUNT_ROWS; n_row != 0; n_row = 0) {
#else
for (uint32_t n_row = 0; n_row <= AMOUNT_ROWS; n_row++) {
#endif
#ifdef CACHE
uint32_t *row = get_row_with_cache(n_row, (uint32_t**) &cache, NULL);
#endif
#ifdef NO_CACHE
uint32_t *row = malloc((n_row + 1) * sizeof(uint32_t));
get_row_without_cache(n_row, row);
#endif
#ifdef SEQ
get_row_with_cache(n_row, mini_cache - n_row + 1, row);
#endif
#ifdef NO_PRINT
// Ignore warnings about unused row
(void) row;
#else
// Print the number of the row
printf("%02x", n_row);
// Print some padding so the pyramid aligns nicely
print_n_spaces((AMOUNT_ROWS - n_row) * (MAX_WIDTH_NUMBER / 2 + 1));
// Print all digits from this row
for (uint32_t i=0; i <= n_row; i++) {
printf("%*u ", MAX_WIDTH_NUMBER, row[i]);
}
printf("\b\n");
#endif
#ifdef SEQ
// Copy new row to previous
memcpy(prev, row, (AMOUNT_ROWS + 1) * sizeof(uint32_t));
// Set new row as empty so it can be reused again
row[0] = (uint32_t) -1;
#endif
#ifdef NO_CACHE
free(row);
#endif
}
#ifdef CACHE
cache_free((uint32_t**) &cache, AMOUNT_ROWS + 1);
#endif
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment