Compare commits

...

10 Commits

Author SHA1 Message Date
Aryadev Chavali
c02a943a29 qsort: stack based implementation 2025-10-27 23:28:19 +00:00
Aryadev Chavali
79249027cb qsort: add another way to read numbers and test 2025-10-27 23:09:56 +00:00
Aryadev Chavali
946006096b qsort: clean up the implementation (forward walk rather than backward) 2025-10-27 23:09:16 +00:00
Aryadev Chavali
964e001dd5 qsort: generate random numbers in hand instead of reading them 2025-10-27 00:29:45 +00:00
Aryadev Chavali
03ba2096c1 bsearch-gen -> num-gen 2025-10-27 00:29:19 +00:00
Aryadev Chavali
e3863557f5 Some cleanup of qsort and vec 2025-10-27 00:28:51 +00:00
Aryadev Chavali
8ee90f0d06 Fix a bug in pingala.cpp 2025-10-27 00:20:46 +00:00
Aryadev Chavali
449d15c1c7 clean up of bsearch 2025-10-27 00:20:36 +00:00
Aryadev Chavali
8dbedb691d Way more inefficient version of pingala with better padding. 2025-03-29 22:05:59 +00:00
Aryadev Chavali
c1355e3003 Clang format in C and C++ mode 2024-09-15 14:51:26 +01:00
8 changed files with 167 additions and 120 deletions

5
.dir-locals.el Normal file
View File

@@ -0,0 +1,5 @@
;;; Directory Local Variables -*- no-byte-compile: t; -*-
;;; For more information see (info "(emacs) Directory Variables")
((c-mode . ((mode . clang-format)))
(c++-mode . ((mode . clang-format))))

View File

@@ -15,6 +15,9 @@ list.out: impls/list.cpp
bsearch.out: impls/bsearch.cpp
$(CC) $(CFLAGS) $^ -o $@
qsort.out: impls/qsort.cpp
$(CC) $(CFLAGS) $^ -o $@
vec.out: impls/vec.c
$(CC) $(CFLAGS) $^ -o $@

View File

@@ -1,9 +0,0 @@
(defconst *LIST-SIZE* 128)
(defconst *UPPER-BOUND* 1024)
(with-current-buffer (find-file "bsearch.txt")
(mapcar
#'(lambda (res) (insert (format "%s\n" res)))
(cl-loop
for i from 0 to *LIST-SIZE*
collect
(random *UPPER-BOUND*))))

View File

@@ -4,6 +4,7 @@
*/
#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <fstream>
#include <iostream>
@@ -17,9 +18,7 @@ using std::ostream;
using std::string;
using std::vector;
vector<int> arr;
ostream &print_arr(ostream &os)
ostream &print_arr(ostream &os, std::vector<int> &arr)
{
os << "[";
for (size_t i = 0; i < arr.size(); ++i)
@@ -27,31 +26,46 @@ ostream &print_arr(ostream &os)
return os << "]";
}
int bsearch(int n, int l = 0, int u = arr.size() - 1)
int bsearch(int n, std::vector<int> arr)
{
int midpoint = ((u + l) / 2);
if (l >= u || u <= 0)
return -1;
int val = arr[midpoint];
if (val == n)
return midpoint;
else if (val > n)
return bsearch(n, l, midpoint - 1);
else
return bsearch(n, midpoint + 1, u);
int l = 0;
int u = arr.size() - 1;
while (l <= u)
{
int midpoint = l + ((u - l) / 2);
int val = arr[midpoint];
if (val == n)
{
return midpoint;
}
else if (val > n)
{
u = midpoint - 1;
}
else
{
l = midpoint + 1;
}
}
return -1;
}
int main(void)
int main(int argc, char *argv[])
{
std::ifstream input("bsearch.txt");
string line;
while (std::getline(input, line))
arr.push_back(std::stoi(line));
std::ifstream input(argc > 1 ? argv[1] : "bsearch.txt");
std::vector<int> arr;
for (std::string line; std::getline(input, line);
arr.push_back(std::stoi(line)))
continue;
std::sort(std::begin(arr), std::end(arr));
string inp;
cout << "Enter number to search: ";
cin >> inp;
int to_search = std::stoi(inp);
cout << bsearch(to_search) << endl;
for (size_t i = 0; i < arr.size(); ++i)
{
int index = bsearch(arr[i], arr);
assert(index == (int)i);
}
return 0;
}

10
impls/num-gen.el Normal file
View File

@@ -0,0 +1,10 @@
(defconst *LIST-SIZE* 128)
(defconst *UPPER-BOUND* 1024)
(with-current-buffer (find-file "nums.txt")
(mapcar
#'(lambda (res) (insert (format "%s\n" res)))
(cl-remove-duplicates
(cl-loop
for i from 0 to *LIST-SIZE*
collect
(random *UPPER-BOUND*)))))

View File

@@ -4,38 +4,39 @@
*/
#include <cstdio>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
void padding(size_t n, size_t depth)
{
for (size_t i = 0; i < ((depth - n) / 2); ++i)
printf("\t");
}
void generate_triangle(const size_t depth)
std::vector<std::string> generate_triangle(const size_t depth)
{
std::vector<std::string> levels;
std::vector<size_t> items;
items.reserve(depth * depth);
std::stringstream ss;
levels.reserve(depth);
items.resize(depth * depth);
#define AT(i, j) items[((i) * depth) + (j)]
AT(0, 0) = 1;
padding(0, depth);
printf("%lu\n", items[0]);
levels.push_back("1");
for (size_t i = 1; i < depth; ++i)
{
AT(i, 0) = 1;
padding(i, depth);
printf("%lu,\t", AT(i, 0));
ss << "1 ";
for (size_t j = 1; j < i; ++j)
{
// Recurrence relation
AT(i, j) = AT(i - 1, j - 1) + AT(i - 1, j);
printf("%lu,\t", AT(i, j));
ss << AT(i, j) << " ";
}
AT(i, i) = 1;
printf("%lu\n", AT(i, i));
ss << "1";
levels.push_back(ss.str());
ss.str(std::string{});
}
#undef AT
return levels;
}
void usage(FILE *fp)
@@ -46,18 +47,29 @@ void usage(FILE *fp)
int main(int argc, char *argv[])
{
if (argc < 2)
{
usage(stderr);
return 1;
}
int arg = std::stoi(argv[1]);
if (arg <= 0)
{
usage(stderr);
return 1;
}
// Variable declarations
std::vector<std::string> levels;
int depth = 0;
generate_triangle(arg);
if (argc < 2)
goto error;
depth = std::stoi(argv[1]);
if (depth <= 0)
goto error;
levels = generate_triangle(depth);
for (const auto &level : levels)
{
for (size_t i = 0;
i < (levels[levels.size() - 1].size() - level.size()) / 2; ++i)
{
printf(" ");
}
printf("%s\n", level.c_str());
}
return 0;
error:
usage(stderr);
return 1;
}

View File

@@ -4,8 +4,15 @@
* Commentary: The inplace O(nlog(n)) sortitng algorithm. Originally designed
* in C, hence the lack of iostream.
*/
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <stack>
#include <vector>
using u64 = uint64_t;
#define ARR_SIZE(XS) (sizeof(XS) / sizeof((XS)[0]))
#define SWAP(A, B) \
@@ -16,85 +23,90 @@
(A) ^= (B); \
} while (0)
#define TEST_SIZE 20
void print_arr(int *arr, int size)
void print_arr(u64 *arr, u64 size)
{
printf("{");
for (int i = 0; i < size - 1; ++i)
printf("%d, ", arr[i]);
printf("%d}", arr[size - 1]);
printf("{\n");
for (u64 i = 0; i < size; ++i)
printf(" %lu,\n", arr[i]);
printf("}\n");
}
void quicksort(int *arr, int arr_size)
struct Partition
{
#ifdef TRACE
printf("before, arr=");
print_arr(arr, arr_size);
printf("\n");
#endif
// Optimisation: for small arr_size, a different sort like the
// bubble sort may be better, instead of initialising new stack
// frames.
if (arr_size < 2)
return;
// Optimisation: Use some heuristics to figure out a better pivot
// than some constant choice of element.
int pivot = 0;
int pivot_value = arr[0];
for (int i = 1; i < arr_size; ++i)
u64 *arr;
u64 arr_size;
};
void quicksort(u64 *arr, u64 arr_size)
{
std::stack<Partition> partitions;
partitions.push({arr, arr_size});
while (!partitions.empty())
{
if (arr[i] <= pivot_value)
const auto partition = partitions.top();
arr = partition.arr;
arr_size = partition.arr_size;
partitions.pop();
// TODO: Use a different sort for small enough sizes?
if (arr_size > 1)
{
if (i != pivot)
SWAP(arr[i], arr[pivot]);
++pivot;
// TODO: Choose a better pivot maybe?
u64 pivot = arr[arr_size - 1]; // Choose the last element as pivot
u64 pivot_index = -1;
for (u64 j = 0; j < arr_size; ++j)
{
if (arr[j] < pivot)
{
++pivot_index;
std::swap(arr[pivot_index], arr[j]);
}
}
std::swap(arr[pivot_index + 1], arr[arr_size - 1]);
partitions.push({arr, pivot_index + 1});
partitions.push({arr + pivot_index + 1, arr_size - pivot_index - 1});
}
}
#ifdef TRACE
printf("after, arr=");
print_arr(arr, arr_size);
printf("\n");
#endif
// Optimisation: Use a stack to do this instead of recursion.
//
// This algorithm is similar to a pre order traversal/dfs, in this
// case on an array where left and right partition are children
// nodes to the original array node. Also with recursion there's a
// real risk for very large ARR_SIZE of running out of space in the
// call stack.
if (pivot != 0)
quicksort(arr, pivot);
if (pivot < arr_size - 1)
quicksort(arr + pivot + 1, arr_size - pivot - 1);
}
int main(void)
int main(int argc, char *argv[])
{
int arr[TEST_SIZE] = {0};
const int size = TEST_SIZE;
(void)argc;
(void)argv;
// Generate a completely reverse ordered list
/*for (size_t i = 0; i < size; ++i) */
/* arr[TEST_SIZE - i - 1] = i;*/
#define TEST_SIZE 10
// randomly generate some numbers
// u64 *arr = new u64[TEST_SIZE];
// u64 arr_size = TEST_SIZE;
// Generate a list where the first half is completely sorted and the
// other half is in reverse order.
for (size_t i = 0; i < size / 2; ++i)
arr[i] = i;
for (size_t i = size / 2; i < size; ++i)
arr[TEST_SIZE - (i - size / 2) - 1] = i;
// for (size_t i = 0; i < TEST_SIZE; ++i)
// arr[i] = rand() % (2L << 30);
// Use nums.txt
std::ifstream input(argc > 1 ? argv[1] : "nums.txt");
std::vector<u64> num_vec;
for (std::string line; std::getline(input, line);
num_vec.push_back(std::stoi(line)))
continue;
u64 *arr = &num_vec[0];
u64 arr_size = num_vec.size();
printf("Before: ");
print_arr(arr, size);
print_arr(arr, arr_size);
printf("\n");
quicksort(arr, size);
quicksort(arr, arr_size);
printf("After: ");
print_arr(arr, size);
print_arr(arr, arr_size);
printf("\n");
// delete[] arr;
return 0;
}

View File

@@ -16,7 +16,7 @@
@brief A vector, consisting of a header and some payload (data).
@details The idea is that the user must never actually interact with this
structure directly, only the data involved. Any vector related functions
deal with
will take the pointer to the data and look behind it to get the header.
*/
typedef struct
{