Adding 2nd assignment - recursion
This commit is contained in:
10
Fundamental_Recursion/CMakeLists.txt
Normal file
10
Fundamental_Recursion/CMakeLists.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
cmake_minimum_required(VERSION 4.0)
|
||||
project(Fundamental_Recursion)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
add_executable(Fundamental_Recursion
|
||||
main.cpp
|
||||
utils.cpp
|
||||
Utils.h
|
||||
)
|
||||
132
Fundamental_Recursion/Utils.cpp
Normal file
132
Fundamental_Recursion/Utils.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include "Utils.h"
|
||||
|
||||
void printNaturalNumber(const int n)
|
||||
{
|
||||
if (n == 0)
|
||||
return;
|
||||
// "Digs down" until n = 0, then prints all natural numbers on the way back up
|
||||
printNaturalNumber(n-1);
|
||||
std::cout << n << " ";
|
||||
}
|
||||
|
||||
int calculateFactorial(const int n)
|
||||
{
|
||||
if (n <= 1)
|
||||
return 1;
|
||||
// "Digs down" until n <= 1, then multiplies by n for every step back up
|
||||
return n * calculateFactorial(n-1);
|
||||
}
|
||||
|
||||
int power(const int base,const int exp)
|
||||
{
|
||||
if (exp == 0 || base == 1 || base == 0)
|
||||
return 1;
|
||||
// "Digs down" until exp <= 0, then multiplies base with the base for every step back up
|
||||
return base * power(base, exp - 1); // The simplest to write, not the most efficient - O(n)
|
||||
|
||||
// int half = power(base / 2, exp);
|
||||
// if (exp % 2 == 0)
|
||||
// return half * half;
|
||||
// else
|
||||
// return base * half * half; // More efficient implementation, reduces the recursive call by half
|
||||
// O(log n)
|
||||
|
||||
}
|
||||
|
||||
int fibonacci(const int n)
|
||||
{
|
||||
if (n == 0)
|
||||
return 0;
|
||||
if (n == 1)
|
||||
return 1;
|
||||
return fibonacci(n - 1) + fibonacci(n - 2); // O(2^n), each call spawns two more recursive calls
|
||||
// Could be optimised by using iteration instead of recursion
|
||||
// For loop would be O(n) since it takes the previous number, adding
|
||||
// current number, then stepping up until it has iterated n times
|
||||
// Linear growth instead of exponential
|
||||
// int current = 1;
|
||||
// int previous = 0;
|
||||
// for (int i = 2; i <= n; i++)
|
||||
// {
|
||||
// int next = previous + current;
|
||||
// previous = current;
|
||||
// current = next;
|
||||
// }
|
||||
// return current;
|
||||
}
|
||||
|
||||
int countOccurrences (const std::string& s, const char c)
|
||||
{
|
||||
if (s.empty())
|
||||
return 0;
|
||||
const int count = (s[0] == c ? 1 : 0);
|
||||
return count + countOccurrences(s.substr(1), c);
|
||||
// O(n^2) since we have to make a new substring for every index of the original string
|
||||
}
|
||||
|
||||
int findLargestElement(const int arr[], const int size)
|
||||
{
|
||||
if (size <= 0)
|
||||
return 0;
|
||||
if (size == 1)
|
||||
return arr[0];
|
||||
const int mid = size / 2;
|
||||
const int leftMax = findLargestElement(arr, mid);
|
||||
const int rightMax = findLargestElement(arr + mid, size - mid);
|
||||
|
||||
return (leftMax > rightMax) ? leftMax : rightMax;
|
||||
// O(n) time complexity, since we have to compare each element at least once
|
||||
}
|
||||
|
||||
// Up to, not including, end
|
||||
void traverseAsciiTable(const char start, const char end)
|
||||
{
|
||||
if (start >= end)
|
||||
return;
|
||||
std::cout << start << " "; // Reflects the building
|
||||
traverseAsciiTable(static_cast<char>(start + 1), end);
|
||||
|
||||
std::cout << " "; // Reflects the unwinding
|
||||
}
|
||||
|
||||
// Helper funcs to populate and randomise input
|
||||
|
||||
void fillRandomArray(int arr[], const int size, const int minVal, const int maxVal)
|
||||
{
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<> dist(minVal, maxVal);
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
arr[i] = dist(gen);
|
||||
}
|
||||
}
|
||||
|
||||
std::string makeRandomString(const int len, char minChar = 'a', char maxChar = 'z')
|
||||
{
|
||||
if (len <= 0)
|
||||
return{};
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<int> dist(minChar, maxChar);
|
||||
|
||||
std::string s;
|
||||
s.reserve(len);
|
||||
for (int i = 0; i < len; i++)
|
||||
s.push_back(static_cast<char>(dist(gen)));
|
||||
return s;
|
||||
}
|
||||
|
||||
int countOccurrences_index(const std::string& s, const char c, int index)
|
||||
{
|
||||
if (index >= static_cast<int>(s.size()))
|
||||
return 0;
|
||||
const int hit = (s[index] == c ? 1 : 0);
|
||||
return hit + countOccurrences_index(s, c, index + 1);
|
||||
}
|
||||
|
||||
|
||||
33
Fundamental_Recursion/Utils.h
Normal file
33
Fundamental_Recursion/Utils.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef FUNDAMENTAL_RECURSION_UTILS_H
|
||||
#define FUNDAMENTAL_RECURSION_UTILS_H
|
||||
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
|
||||
|
||||
void printNaturalNumber(int n);
|
||||
int calculateFactorial(int n);
|
||||
int power(int base, int exp);
|
||||
int fibonacci(int n);
|
||||
int countOccurrences(const std::string& s, char c);
|
||||
int findLargestElement(const int arr[], int size);
|
||||
void traverseAsciiTable(char start, char end);
|
||||
|
||||
|
||||
// Helpers partially generated by ChatGPT
|
||||
void fillRandomArray(int arr[], int size, int minVal, int maxVal);
|
||||
std::string makeRandomString(int len, char minChar, char maxChar);
|
||||
int countOccurrences_index(const std::string& s, char c, int index);
|
||||
|
||||
template<typename F, typename... Args>
|
||||
double time_ms(F&& f, Args&&... args)
|
||||
{
|
||||
auto t0 = std::chrono::high_resolution_clock::now();
|
||||
(void)std::forward<F>(f)(std::forward<Args>(args)...);
|
||||
auto t1 = std::chrono::high_resolution_clock::now();
|
||||
return std::chrono::duration<double, std::milli>(t1 - t0).count();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif //FUNDAMENTAL_RECURSION_UTILS_H
|
||||
89
Fundamental_Recursion/main.cpp
Normal file
89
Fundamental_Recursion/main.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include "Utils.h"
|
||||
|
||||
static void line(const char* title)
|
||||
{
|
||||
std::cout << "\n======= " << title << "=======\n";
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
line("Neutral numbers");
|
||||
printNaturalNumber(10);
|
||||
std::cout << "\n";
|
||||
|
||||
|
||||
line("Factorial");
|
||||
const int fact_expect[] = {
|
||||
1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800
|
||||
};
|
||||
bool ok_fact = true;
|
||||
for (int n = 0; n <= 10; ++n) {
|
||||
int r = calculateFactorial(n);
|
||||
std::cout << "n=" << n << " -> " << r
|
||||
<< (r == fact_expect[n] ? " OK" : " MISMATCH") << "\n";
|
||||
ok_fact &= (r == fact_expect[n]);
|
||||
}
|
||||
|
||||
|
||||
line ("Power");
|
||||
struct Case { int base, exp, expect; };
|
||||
const Case pow_cases[] = {
|
||||
{2,0,1}, {2,1,2}, {2,5,32}, {3,4,81}, {5,3,125}, {10,2,100}
|
||||
};
|
||||
bool ok_pow = true;
|
||||
for (auto c : pow_cases) {
|
||||
int r = power(c.base, c.exp);
|
||||
std::cout << c.base << "^" << c.exp << " = " << r
|
||||
<< (r == c.expect ? " OK" : " MISMATCH") << "\n";
|
||||
ok_pow &= (r == c.expect);
|
||||
|
||||
line("Fibonacci");
|
||||
const int fib_expect[] = {0,1,1,2,3,5,8,13,21,34,55,89,144};
|
||||
bool ok_fib = true;
|
||||
for (int n = 0; n <= 12; ++n) {
|
||||
int r = fibonacci(n);
|
||||
std::cout << "F(" << n << ") = " << r
|
||||
<< (r == fib_expect[n] ? " OK" : " MISMATCH") << "\n";
|
||||
ok_fib &= (r == fib_expect[n]);
|
||||
}
|
||||
|
||||
|
||||
line("Count occurrences");
|
||||
std::string s = makeRandomString(2000, 'a', 'f');
|
||||
char target = 'c';
|
||||
int rec = countOccurrences(s, target); //<--- recursive
|
||||
int ref = static_cast<int>(std::count(s.begin(), s.end(), target));
|
||||
std::cout << "recursive=" << rec << " std::count=" << ref
|
||||
<< (rec == ref ? " OK" : " MISMATCH") << "\n";
|
||||
double t_rec_ms = time_ms([&]{ (void)countOccurrences(s, target); });
|
||||
std::cout << "perf (recursive substr): ~" << t_rec_ms << " ms\n";
|
||||
|
||||
|
||||
line ("Find largest element");
|
||||
constexpr int N = 100000;
|
||||
int* arr = new int[N];
|
||||
fillRandomArray(arr, N, -100000, 100000);
|
||||
double t_my_ms = time_ms([&]{ (void)findLargestElement(arr, N); });
|
||||
int myMax = findLargestElement(arr, N);
|
||||
int stdMax = *std::max_element(arr, arr + N);
|
||||
std::cout << "myMax=" << myMax << " stdMax=" << stdMax
|
||||
<< (myMax == stdMax ? " OK" : " MISMATCH") << "\n";
|
||||
std::cout << "perf (recursive): ~" << t_my_ms << " ms\n";
|
||||
delete[] arr;
|
||||
|
||||
|
||||
line("Traverse Ascii table");
|
||||
traverseAsciiTable('A', 'F');
|
||||
std::cout << "\n";
|
||||
|
||||
|
||||
line("Summary");
|
||||
std::cout << "Factorial: " << (ok_fact ? "OK" : "FAIL") << "\n";
|
||||
std::cout << "Power: " << (ok_pow ? "OK" : "FAIL") << "\n";
|
||||
std::cout << "Fibonacci: " << (ok_fib ? "OK" : "FAIL") << "\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
17
assignment1/.idea/workspace.xml
generated
17
assignment1/.idea/workspace.xml
generated
@@ -29,15 +29,6 @@
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="e3758ede-1321-4b2e-94dd-da87753a03f6" name="Changes" comment="Finished">
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/CMakeLists.txt" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/TMovie.cpp" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/TMovie.h" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/TMovieList.cpp" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/TMovieList.h" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/TMovieNode.cpp" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/TMovieNode.h" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/cmake-build-debug/CMakeFiles/clion-Debug-log.txt" beforeDir="false" afterPath="$PROJECT_DIR$/cmake-build-debug/CMakeFiles/clion-Debug-log.txt" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/main.cpp" beforeDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@@ -91,11 +82,6 @@
|
||||
}
|
||||
}</component>
|
||||
<component name="RunManager" selected="C/C++ File.main.cpp">
|
||||
<configuration default="true" type="CLionExternalRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true">
|
||||
<method v="2">
|
||||
<option name="CLION.EXTERNAL.BUILD" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration name="assignment1" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="assignment1" TARGET_NAME="assignment1" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="assignment1" RUN_TARGET_NAME="assignment1">
|
||||
<method v="2">
|
||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||
@@ -108,8 +94,8 @@
|
||||
</method>
|
||||
</configuration>
|
||||
<list>
|
||||
<item itemvalue="C/C++ File.main.cpp" />
|
||||
<item itemvalue="CMake Application.assignment1" />
|
||||
<item itemvalue="C/C++ File.main.cpp" />
|
||||
</list>
|
||||
</component>
|
||||
<component name="TaskManager">
|
||||
@@ -123,6 +109,7 @@
|
||||
<workItem from="1760788441262" duration="11460000" />
|
||||
<workItem from="1760967500921" duration="5495000" />
|
||||
<workItem from="1761213959983" duration="4210000" />
|
||||
<workItem from="1761302251197" duration="113000" />
|
||||
</task>
|
||||
<task id="LOCAL-00001" summary="Finished">
|
||||
<option name="closed" value="true" />
|
||||
|
||||
Reference in New Issue
Block a user