Merge branch 'master' into fix/codeql-warnings

This commit is contained in:
David Leal 2021-11-05 12:10:31 -06:00 committed by GitHub
commit 4d357c468f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 1307 additions and 212 deletions

66
.vscode/settings.json vendored
View File

@ -1,6 +1,64 @@
{
"C_Cpp.clang_format_style": "{ BasedOnStyle: Google, UseTab: Never, IndentWidth: 4, TabWidth: 4, AllowShortIfStatementsOnASingleLine: false, IndentCaseLabels: true, ColumnLimit: 80, AccessModifierOffset: -3, AlignConsecutiveMacros: true }",
"editor.formatOnSave": true,
"editor.formatOnType": true,
"editor.formatOnPaste": true
"C_Cpp.clang_format_style": "{ BasedOnStyle: Google, UseTab: Never, IndentWidth: 4, TabWidth: 4, AllowShortIfStatementsOnASingleLine: false, IndentCaseLabels: true, ColumnLimit: 80, AccessModifierOffset: -3, AlignConsecutiveMacros: true }",
"editor.formatOnSave": true,
"editor.formatOnType": true,
"editor.formatOnPaste": true,
"files.associations": {
"array": "cpp",
"atomic": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"chrono": "cpp",
"cinttypes": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"complex": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"list": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"map": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"ratio": "cpp",
"set": "cpp",
"string": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"new": "cpp",
"ostream": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"typeinfo": "cpp",
"valarray": "cpp"
}
}

View File

@ -2,75 +2,131 @@
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
Examples of behavior that contributes to a positive environment for our
community include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior by participants include:
Examples of unacceptable behavior include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* The use of sexualized language or imagery, and sexual attention or advances of
any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Publishing others' private information, such as a physical or email address,
without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
professional setting
## Our Responsibilities
## Enforcement Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at 1anuppanwar@gmail.com, dynamitechetan@gmail.com, nikhilkala8@gmail.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
reported to the community leaders responsible for enforcement at
hello@the-algorithms.com.
All complaints will be reviewed and investigated promptly and fairly.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at <https://www.contributor-covenant.org/version/1/4/code-of-conduct.html>
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
<https://www.contributor-covenant.org/faq>
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

View File

@ -223,12 +223,16 @@
## Numerical Methods
* [Bisection Method](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/bisection_method.cpp)
* [Brent Method Extrema](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/brent_method_extrema.cpp)
* [Composite Simpson Rule](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/composite_simpson_rule.cpp)
* [Durand Kerner Roots](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/durand_kerner_roots.cpp)
* [False Position](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/false_position.cpp)
* [Fast Fourier Transform](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/fast_fourier_transform.cpp)
* [Gaussian Elimination](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/gaussian_elimination.cpp)
* [Golden Search Extrema](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/golden_search_extrema.cpp)
* [Inverse Fast Fourier Transform](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/inverse_fast_fourier_transform.cpp)
* [Lu Decompose](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/lu_decompose.cpp)
* [Lu Decomposition](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/lu_decomposition.h)
* [Midpoint Integral Method](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/midpoint_integral_method.cpp)
* [Newton Raphson Method](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/newton_raphson_method.cpp)
* [Ode Forward Euler](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/ode_forward_euler.cpp)
* [Ode Midpoint Euler](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/ode_midpoint_euler.cpp)

View File

@ -1,22 +1,23 @@
/**
* @brief Check whether a given graph is bipartite or not
* @details
* A bipartite graph is the one whose nodes can be divided into two
* disjoint sets in such a way that the nodes in a set are not
* connected to each other at all, i.e. no intra-set connections.
* The only connections that exist are that of inter-set,
* i.e. the nodes from one set are connected to a subset of nodes
* A bipartite graph is the one whose nodes can be divided into two
* disjoint sets in such a way that the nodes in a set are not
* connected to each other at all, i.e. no intra-set connections.
* The only connections that exist are that of inter-set,
* i.e. the nodes from one set are connected to a subset of nodes
* in the other set.
* In this implementation, using a graph in the form of adjacency
* In this implementation, using a graph in the form of adjacency
* list, check whether the given graph is a bipartite or not.
*
* References used: [GeeksForGeeks](https://www.geeksforgeeks.org/bipartite-graph/)
*
* References used:
* [GeeksForGeeks](https://www.geeksforgeeks.org/bipartite-graph/)
* @author [tushar2407](https://github.com/tushar2407)
*/
#include <iostream> /// for IO operations
#include <queue> /// for queue data structure
#include <vector> /// for vector data structure
#include <cassert> /// for assert
#include <cassert> /// for assert
#include <iostream> /// for IO operations
#include <queue> /// for queue data structure
#include <vector> /// for vector data structure
/**
* @namespace graph
@ -28,62 +29,61 @@ namespace graph {
* @param graph is a 2D matrix whose rows or the first index signify the node
* and values in that row signify the nodes it is connected to
* @param index is the valus of the node currently under observation
* @param visited is the vector which stores whether a given node has been
* @param visited is the vector which stores whether a given node has been
* traversed or not yet
* @returns boolean
*/
bool checkBipartite(
const std::vector<std::vector<int64_t>> &graph,
int64_t index,
std::vector<int64_t> *visited
)
{
std::queue<int64_t> q; ///< stores the neighbouring node indexes in squence
/// of being reached
q.push(index); /// insert the current node into the queue
(*visited)[index] = 1; /// mark the current node as travelled
while(q.size())
{
bool checkBipartite(const std::vector<std::vector<int64_t>> &graph,
int64_t index, std::vector<int64_t> *visited) {
std::queue<int64_t> q; ///< stores the neighbouring node indexes in squence
/// of being reached
q.push(index); /// insert the current node into the queue
(*visited)[index] = 1; /// mark the current node as travelled
while (q.size()) {
int64_t u = q.front();
q.pop();
for(uint64_t i=0;i<graph[u].size();i++)
{
int64_t v = graph[u][i]; ///< stores the neighbour of the current node
if(!(*visited)[v]) /// check whether the neighbour node is
/// travelled already or not
for (uint64_t i = 0; i < graph[u].size(); i++) {
int64_t v =
graph[u][i]; ///< stores the neighbour of the current node
if (!(*visited)[v]) /// check whether the neighbour node is
/// travelled already or not
{
(*visited)[v] = ((*visited)[u]==1)?-1:1; /// colour the neighbouring node with
/// different colour than the current node
q.push(v); /// insert the neighbouring node into the queue
}
else if((*visited)[v] == (*visited)[u]) /// if both the current node and its neighbour
/// has the same state then it is not a bipartite graph
(*visited)[v] =
((*visited)[u] == 1)
? -1
: 1; /// colour the neighbouring node with
/// different colour than the current node
q.push(v); /// insert the neighbouring node into the queue
} else if ((*visited)[v] ==
(*visited)[u]) /// if both the current node and its
/// neighbour has the same state then it
/// is not a bipartite graph
{
return false;
}
}
}
return true; /// return true when all the connected nodes of the current
/// nodes are travelled and satisify all the above conditions
return true; /// return true when all the connected nodes of the current
/// nodes are travelled and satisify all the above conditions
}
/**
* @brief returns true if the given graph is bipartite else returns false
* @param graph is a 2D matrix whose rows or the first index signify the node
* @param graph is a 2D matrix whose rows or the first index signify the node
* and values in that row signify the nodes it is connected to
* @returns booleans
*/
bool isBipartite(const std::vector<std::vector<int64_t>> &graph)
{
std::vector<int64_t> visited(graph.size()); ///< stores boolean values
/// which signify whether that node had been visited or not
for(uint64_t i=0;i<graph.size();i++)
{
if(!visited[i]) /// if the current node is not visited then check
/// whether the sub-graph of that node is a bipartite or not
bool isBipartite(const std::vector<std::vector<int64_t>> &graph) {
std::vector<int64_t> visited(
graph.size()); ///< stores boolean values
/// which signify whether that node had been visited or
/// not
for (uint64_t i = 0; i < graph.size(); i++) {
if (!visited[i]) /// if the current node is not visited then check
/// whether the sub-graph of that node is a bipartite
/// or not
{
if(!checkBipartite(graph, i, &visited))
{
if (!checkBipartite(graph, i, &visited)) {
return false;
}
}
@ -96,39 +96,30 @@ bool isBipartite(const std::vector<std::vector<int64_t>> &graph)
* @brief Self-test implementations
* @returns void
*/
static void test()
{
std::vector<std::vector<int64_t>> graph = {
{1,3},
{0,2},
{1,3},
{0,2}
};
static void test() {
std::vector<std::vector<int64_t>> graph = {{1, 3}, {0, 2}, {1, 3}, {0, 2}};
assert(graph::isBipartite(graph) == true); /// check whether the above
/// defined graph is indeed bipartite
assert(graph::isBipartite(graph) ==
true); /// check whether the above
/// defined graph is indeed bipartite
std::vector<std::vector<int64_t>> graph_not_bipartite = {
{1,2,3},
{0,2},
{0,1,3},
{0,2}
};
{1, 2, 3}, {0, 2}, {0, 1, 3}, {0, 2}};
assert(graph::isBipartite(graph_not_bipartite) == false); /// check whether
/// the above defined graph is indeed bipartite
assert(graph::isBipartite(graph_not_bipartite) ==
false); /// check whether
/// the above defined graph is indeed bipartite
std::cout << "All tests have successfully passed!\n";
}
/**
* @brief Main function
* Instantitates a dummy graph of a small size with
* Instantitates a dummy graph of a small size with
* a few edges between random nodes.
* On applying the algorithm, it checks if the instantiated
* On applying the algorithm, it checks if the instantiated
* graph is bipartite or not.
* @returns 0 on exit
*/
int main()
{
int main() {
test(); // run self-test implementations
return 0;
}

View File

@ -9,14 +9,22 @@
/** Generate an increasingly large number of primes
* and store in a list
*/
std::vector<int> primes(int max) {
max++;
std::vector<int> primes(size_t max) {
std::vector<int> res;
std::vector<bool> numbers(max, false);
for (int i = 2; i < max; i++) {
if (!numbers[i]) {
for (int j = i; j < max; j += i) numbers[j] = true;
res.push_back(i);
std::vector<bool> is_not_prime(max + 1, false);
for (size_t i = 2; i <= max; i++) {
if (!is_not_prime[i]) {
res.emplace_back(i);
}
for (int p : res) {
size_t k = i * p;
if (k > max) {
break;
}
is_not_prime[k] = true;
if (i % p == 0) {
break;
}
}
}
return res;
@ -25,9 +33,9 @@ std::vector<int> primes(int max) {
/** main function */
int main() {
std::cout << "Calculate primes up to:\n>> ";
int n;
int n = 0;
std::cin >> n;
std::vector<int> ans = primes(n);
for (int i = 0; i < ans.size(); i++) std::cout << ans[i] << ' ';
for (int p : ans) std::cout << p << ' ';
std::cout << std::endl;
}

View File

@ -0,0 +1,202 @@
/**
* @file
* @brief Implementation of the Composite Simpson Rule for the approximation
*
* @details The following is an implementation of the Composite Simpson Rule for
* the approximation of definite integrals. More info -> wiki:
* https://en.wikipedia.org/wiki/Simpson%27s_rule#Composite_Simpson's_rule
*
* The idea is to split the interval in an EVEN number N of intervals and use as
* interpolation points the xi for which it applies that xi = x0 + i*h, where h
* is a step defined as h = (b-a)/N where a and b are the first and last points
* of the interval of the integration [a, b].
*
* We create a table of the xi and their corresponding f(xi) values and we
* evaluate the integral by the formula: I = h/3 * {f(x0) + 4*f(x1) + 2*f(x2) +
* ... + 2*f(xN-2) + 4*f(xN-1) + f(xN)}
*
* That means that the first and last indexed i f(xi) are multiplied by 1,
* the odd indexed f(xi) by 4 and the even by 2.
*
* In this program there are 4 sample test functions f, g, k, l that are
* evaluated in the same interval.
*
* Arguments can be passed as parameters from the command line argv[1] = N,
* argv[2] = a, argv[3] = b
*
* N must be even number and a<b.
*
* In the end of the main() i compare the program's result with the one from
* mathematical software with 2 decimal points margin.
*
* Add sample function by replacing one of the f, g, k, l and the assert
*
* @author [ggkogkou](https://github.com/ggkogkou)
*
*/
#include <cassert> /// for assert
#include <cmath> /// for math functions
#include <cstdint> /// for integer allocation
#include <cstdlib> /// for std::atof
#include <functional> /// for std::function
#include <iostream> /// for IO operations
#include <map> /// for std::map container
/**
* @namespace numerical_methods
* @brief Numerical algorithms/methods
*/
namespace numerical_methods {
/**
* @namespace simpson_method
* @brief Contains the Simpson's method implementation
*/
namespace simpson_method {
/**
* @fn double evaluate_by_simpson(int N, double h, double a,
* std::function<double (double)> func)
* @brief Calculate integral or assert if integral is not a number (Nan)
* @param N number of intervals
* @param h step
* @param a x0
* @param func: choose the function that will be evaluated
* @returns the result of the integration
*/
double evaluate_by_simpson(std::int32_t N, double h, double a,
std::function<double(double)> func) {
std::map<std::int32_t, double>
data_table; // Contains the data points. key: i, value: f(xi)
double xi = a; // Initialize xi to the starting point x0 = a
// Create the data table
double temp;
for (std::int32_t i = 0; i <= N; i++) {
temp = func(xi);
data_table.insert(
std::pair<std::int32_t, double>(i, temp)); // add i and f(xi)
xi += h; // Get the next point xi for the next iteration
}
// Evaluate the integral.
// Remember: f(x0) + 4*f(x1) + 2*f(x2) + ... + 2*f(xN-2) + 4*f(xN-1) + f(xN)
double evaluate_integral = 0;
for (std::int32_t i = 0; i <= N; i++) {
if (i == 0 || i == N)
evaluate_integral += data_table.at(i);
else if (i % 2 == 1)
evaluate_integral += 4 * data_table.at(i);
else
evaluate_integral += 2 * data_table.at(i);
}
// Multiply by the coefficient h/3
evaluate_integral *= h / 3;
// If the result calculated is nan, then the user has given wrong input
// interval.
assert(!std::isnan(evaluate_integral) &&
"The definite integral can't be evaluated. Check the validity of "
"your input.\n");
// Else return
return evaluate_integral;
}
/**
* @fn double f(double x)
* @brief A function f(x) that will be used to test the method
* @param x The independent variable xi
* @returns the value of the dependent variable yi = f(xi)
*/
double f(double x) { return std::sqrt(x) + std::log(x); }
/** @brief Another test function */
double g(double x) { return std::exp(-x) * (4 - std::pow(x, 2)); }
/** @brief Another test function */
double k(double x) { return std::sqrt(2 * std::pow(x, 3) + 3); }
/** @brief Another test function*/
double l(double x) { return x + std::log(2 * x + 1); }
} // namespace simpson_method
} // namespace numerical_methods
/**
* \brief Self-test implementations
* @param N is the number of intervals
* @param h is the step
* @param a is x0
* @param b is the end of the interval
* @param used_argv_parameters is 'true' if argv parameters are given and
* 'false' if not
*/
static void test(std::int32_t N, double h, double a, double b,
bool used_argv_parameters) {
// Call the functions and find the integral of each function
double result_f = numerical_methods::simpson_method::evaluate_by_simpson(
N, h, a, numerical_methods::simpson_method::f);
assert((used_argv_parameters || (result_f >= 4.09 && result_f <= 4.10)) &&
"The result of f(x) is wrong");
std::cout << "The result of integral f(x) on interval [" << a << ", " << b
<< "] is equal to: " << result_f << std::endl;
double result_g = numerical_methods::simpson_method::evaluate_by_simpson(
N, h, a, numerical_methods::simpson_method::g);
assert((used_argv_parameters || (result_g >= 0.27 && result_g <= 0.28)) &&
"The result of g(x) is wrong");
std::cout << "The result of integral g(x) on interval [" << a << ", " << b
<< "] is equal to: " << result_g << std::endl;
double result_k = numerical_methods::simpson_method::evaluate_by_simpson(
N, h, a, numerical_methods::simpson_method::k);
assert((used_argv_parameters || (result_k >= 9.06 && result_k <= 9.07)) &&
"The result of k(x) is wrong");
std::cout << "The result of integral k(x) on interval [" << a << ", " << b
<< "] is equal to: " << result_k << std::endl;
double result_l = numerical_methods::simpson_method::evaluate_by_simpson(
N, h, a, numerical_methods::simpson_method::l);
assert((used_argv_parameters || (result_l >= 7.16 && result_l <= 7.17)) &&
"The result of l(x) is wrong");
std::cout << "The result of integral l(x) on interval [" << a << ", " << b
<< "] is equal to: " << result_l << std::endl;
}
/**
* @brief Main function
* @param argc commandline argument count (ignored)
* @param argv commandline array of arguments (ignored)
* @returns 0 on exit
*/
int main(int argc, char** argv) {
std::int32_t N = 16; /// Number of intervals to divide the integration
/// interval. MUST BE EVEN
double a = 1, b = 3; /// Starting and ending point of the integration in
/// the real axis
double h; /// Step, calculated by a, b and N
bool used_argv_parameters =
false; // If argv parameters are used then the assert must be omitted
// for the tst cases
// Get user input (by the command line parameters or the console after
// displaying messages)
if (argc == 4) {
N = std::atoi(argv[1]);
a = (double)std::atof(argv[2]);
b = (double)std::atof(argv[3]);
// Check if a<b else abort
assert(a < b && "a has to be less than b");
assert(N > 0 && "N has to be > 0");
if (N < 16 || a != 1 || b != 3)
used_argv_parameters = true;
std::cout << "You selected N=" << N << ", a=" << a << ", b=" << b
<< std::endl;
} else
std::cout << "Default N=" << N << ", a=" << a << ", b=" << b
<< std::endl;
// Find the step
h = (b - a) / N;
test(N, h, a, b, used_argv_parameters); // run self-test implementations
return 0;
}

View File

@ -0,0 +1,165 @@
/**
* @file
* @brief [A fast Fourier transform
* (FFT)](https://medium.com/@aiswaryamathur/understanding-fast-fouriertransform-from-scratch-to-solve-polynomial-multiplication-8018d511162f)
* is an algorithm that computes the
* discrete Fourier transform (DFT) of a sequence, or its inverse (IDFT).
* @details
* This
* algorithm has application in use case scenario where a user wants to find points of a
* function
* in a short time by just using the coefficients of the polynomial
* function.
* It can be also used to find inverse fourier transform by just switching the
value of omega.
* Time complexity
* this algorithm computes the DFT in O(nlogn) time in comparison to traditional
O(n^2).
* @author [Ameya Chawla](https://github.com/ameyachawlaggsipu)
*/
#include <cassert> /// for assert
#include <cmath> /// for mathematical-related functions
#include <complex> /// for storing points and coefficents
#include <iostream> /// for IO operations
#include <vector> /// for std::vector
/**
* @namespace numerical_methods
* @brief Numerical algorithms/methods
*/
namespace numerical_methods {
/**
* @brief FastFourierTransform is a recursive function which returns list of
* complex numbers
* @param p List of Coefficents in form of complex numbers
* @param n Count of elements in list p
* @returns p if n==1
* @returns y if n!=1
*/
std::complex<double> *FastFourierTransform(std::complex<double> *p, uint8_t n) {
if (n == 1) {
return p; /// Base Case To return
}
double pi = 2 * asin(1.0); /// Declaring value of pi
std::complex<double> om = std::complex<double>(
cos(2 * pi / n), sin(2 * pi / n)); /// Calculating value of omega
auto *pe = new std::complex<double>[n / 2]; /// Coefficients of even power
auto *po = new std::complex<double>[n / 2]; /// Coefficients of odd power
int k1 = 0, k2 = 0;
for (int j = 0; j < n; j++) {
if (j % 2 == 0) {
pe[k1++] = p[j]; /// Assigning values of even Coefficients
} else
po[k2++] = p[j]; /// Assigning value of odd Coefficients
}
std::complex<double> *ye =
FastFourierTransform(pe, n / 2); /// Recursive Call
std::complex<double> *yo =
FastFourierTransform(po, n / 2); /// Recursive Call
auto *y = new std::complex<double>[n]; /// Final value representation list
k1 = 0, k2 = 0;
for (int i = 0; i < n / 2; i++) {
y[i] =
ye[k1] + pow(om, i) * yo[k2]; /// Updating the first n/2 elements
y[i + n / 2] =
ye[k1] - pow(om, i) * yo[k2]; /// Updating the last n/2 elements
k1++;
k2++;
}
if(n!=2){
delete[] pe;
delete[] po;
}
delete[] ye; /// Deleting dynamic array ye
delete[] yo; /// Deleting dynamic array yo
return y;
}
} // namespace numerical_methods
/**
* @brief Self-test implementations
* @details
* Declaring two test cases and checking for the error
* in predicted and true value is less than 0.000000000001.
* @returns void
*/
static void test() {
/* descriptions of the following test */
auto *t1 = new std::complex<double>[2]; /// Test case 1
auto *t2 = new std::complex<double>[4]; /// Test case 2
t1[0] = {1, 0};
t1[1] = {2, 0};
t2[0] = {1, 0};
t2[1] = {2, 0};
t2[2] = {3, 0};
t2[3] = {4, 0};
uint8_t n1 = 2;
uint8_t n2 = 4;
std::vector<std::complex<double>> r1 = {
{3, 0}, {-1, 0}}; /// True Answer for test case 1
std::vector<std::complex<double>> r2 = {
{10, 0}, {-2, -2}, {-2, 0}, {-2, 2}}; /// True Answer for test case 2
std::complex<double> *o1 = numerical_methods::FastFourierTransform(t1, n1);
std::complex<double> *t3=o1; /// Temporary variable used to delete memory location of o1
std::complex<double> *o2 = numerical_methods::FastFourierTransform(t2, n2);
std::complex<double> *t4=o2; /// Temporary variable used to delete memory location of o2
for (uint8_t i = 0; i < n1; i++) {
assert((r1[i].real() - o1->real() < 0.000000000001) &&
(r1[i].imag() - o1->imag() <
0.000000000001)); /// Comparing for both real and imaginary
/// values for test case 1
o1++;
}
for (uint8_t i = 0; i < n2; i++) {
assert((r2[i].real() - o2->real() < 0.000000000001) &&
(r2[i].imag() - o2->imag() <
0.000000000001)); /// Comparing for both real and imaginary
/// values for test case 2
o2++;
}
delete[] t1;
delete[] t2;
delete[] t3;
delete[] t4;
std::cout << "All tests have successfully passed!\n";
}
/**
* @brief Main function
* @param argc commandline argument count (ignored)
* @param argv commandline array of arguments (ignored)
* calls automated test function to test the working of fast fourier transform.
* @returns 0 on exit
*/
int main(int argc, char const *argv[]) {
test(); // run self-test implementations
// with 2 defined test cases
return 0;
}

View File

@ -0,0 +1,161 @@
/**
* @file
* @brief [An inverse fast Fourier transform
* (IFFT)](https://www.geeksforgeeks.org/python-inverse-fast-fourier-transformation/)
* is an algorithm that computes the inverse fourier transform.
* @details
* This algorithm has an application in use case scenario where a user wants find coefficients of
* a function in a short time by just using points generated by DFT.
* Time complexity
* this algorithm computes the IDFT in O(nlogn) time in comparison to traditional O(n^2).
* @author [Ameya Chawla](https://github.com/ameyachawlaggsipu)
*/
#include <cassert> /// for assert
#include <cmath> /// for mathematical-related functions
#include <complex> /// for storing points and coefficents
#include <iostream> /// for IO operations
#include <vector> /// for std::vector
/**
* @namespace numerical_methods
* @brief Numerical algorithms/methods
*/
namespace numerical_methods {
/**
* @brief InverseFastFourierTransform is a recursive function which returns list of
* complex numbers
* @param p List of Coefficents in form of complex numbers
* @param n Count of elements in list p
* @returns p if n==1
* @returns y if n!=1
*/
std::complex<double> *InverseFastFourierTransform(std::complex<double> *p, uint8_t n) {
if (n == 1) {
return p; /// Base Case To return
}
double pi = 2 * asin(1.0); /// Declaring value of pi
std::complex<double> om = std::complex<double>(
cos(2 * pi / n), sin(2 * pi / n)); /// Calculating value of omega
om.real(om.real()/n); /// One change in comparison with DFT
om.imag(om.imag()/n); /// One change in comparison with DFT
auto *pe = new std::complex<double>[n / 2]; /// Coefficients of even power
auto *po = new std::complex<double>[n / 2]; /// Coefficients of odd power
int k1 = 0, k2 = 0;
for (int j = 0; j < n; j++) {
if (j % 2 == 0) {
pe[k1++] = p[j]; /// Assigning values of even Coefficients
} else
po[k2++] = p[j]; /// Assigning value of odd Coefficients
}
std::complex<double> *ye =
InverseFastFourierTransform(pe, n / 2); /// Recursive Call
std::complex<double> *yo =
InverseFastFourierTransform(po, n / 2); /// Recursive Call
auto *y = new std::complex<double>[n]; /// Final value representation list
k1 = 0, k2 = 0;
for (int i = 0; i < n / 2; i++) {
y[i] =
ye[k1] + pow(om, i) * yo[k2]; /// Updating the first n/2 elements
y[i + n / 2] =
ye[k1] - pow(om, i) * yo[k2]; /// Updating the last n/2 elements
k1++;
k2++;
}
if(n!=2){
delete[] pe;
delete[] po;
}
delete[] ye; /// Deleting dynamic array ye
delete[] yo; /// Deleting dynamic array yo
return y;
}
} // namespace numerical_methods
/**
* @brief Self-test implementations
* @details
* Declaring two test cases and checking for the error
* in predicted and true value is less than 0.000000000001.
* @returns void
*/
static void test() {
/* descriptions of the following test */
auto *t1 = new std::complex<double>[2]; /// Test case 1
auto *t2 = new std::complex<double>[4]; /// Test case 2
t1[0] = {3, 0};
t1[1] = {-1, 0};
t2[0] = {10, 0};
t2[1] = {-2, -2};
t2[2] = {-2, 0};
t2[3] = {-2, 2};
uint8_t n1 = 2;
uint8_t n2 = 4;
std::vector<std::complex<double>> r1 = {
{1, 0}, {2, 0}}; /// True Answer for test case 1
std::vector<std::complex<double>> r2 = {
{1, 0}, {2, 0}, {3, 0}, {4, 0}}; /// True Answer for test case 2
std::complex<double> *o1 = numerical_methods::InverseFastFourierTransform(t1, n1);
std::complex<double> *o2 = numerical_methods::InverseFastFourierTransform(t2, n2);
for (uint8_t i = 0; i < n1; i++) {
assert((r1[i].real() - o1[i].real() < 0.000000000001) &&
(r1[i].imag() - o1[i].imag() <
0.000000000001)); /// Comparing for both real and imaginary
/// values for test case 1
}
for (uint8_t i = 0; i < n2; i++) {
assert((r2[i].real() - o2[i].real() < 0.000000000001) &&
(r2[i].imag() - o2[i].imag() <
0.000000000001)); /// Comparing for both real and imaginary
/// values for test case 2
}
delete[] t1;
delete[] t2;
delete[] o1;
delete[] o2;
std::cout << "All tests have successfully passed!\n";
}
/**
* @brief Main function
* @param argc commandline argument count (ignored)
* @param argv commandline array of arguments (ignored)
* calls automated test function to test the working of fast fourier transform.
* @returns 0 on exit
*/
int main(int argc, char const *argv[]) {
test(); // run self-test implementations
// with 2 defined test cases
return 0;
}

View File

@ -0,0 +1,199 @@
/**
* @file
* @brief A numerical method for easy [approximation of
* integrals](https://en.wikipedia.org/wiki/Midpoint_method)
* @details The idea is to split the interval into N of intervals and use as
* interpolation points the xi for which it applies that xi = x0 + i*h, where h
* is a step defined as h = (b-a)/N where a and b are the first and last points
* of the interval of the integration [a, b].
*
* We create a table of the xi and their corresponding f(xi) values and we
* evaluate the integral by the formula: I = h * {f(x0+h/2) + f(x1+h/2) + ... +
* f(xN-1+h/2)}
*
* Arguments can be passed as parameters from the command line argv[1] = N,
* argv[2] = a, argv[3] = b. In this case if the default values N=16, a=1, b=3
* are changed then the tests/assert are disabled.
*
*
* @author [ggkogkou](https://github.com/ggkogkou)
*/
#include <cassert> /// for assert
#include <cmath> /// for math functions
#include <cstdint> /// for integer allocation
#include <cstdlib> /// for std::atof
#include <functional> /// for std::function
#include <iostream> /// for IO operations
#include <map> /// for std::map container
/**
* @namespace numerical_methods
* @brief Numerical algorithms/methods
*/
namespace numerical_methods {
/**
* @namespace midpoint_rule
* @brief Functions for the [Midpoint
* Integral](https://en.wikipedia.org/wiki/Midpoint_method) method
* implementation
*/
namespace midpoint_rule {
/**
* @fn double midpoint(const std::int32_t N, const double h, const double a,
* const std::function<double (double)>& func)
* @brief Main function for implementing the Midpoint Integral Method
* implementation
* @param N is the number of intervals
* @param h is the step
* @param a is x0
* @param func is the function that will be integrated
* @returns the result of the integration
*/
double midpoint(const std::int32_t N, const double h, const double a,
const std::function<double(double)>& func) {
std::map<int, double>
data_table; // Contains the data points, key: i, value: f(xi)
double xi = a; // Initialize xi to the starting point x0 = a
// Create the data table
// Loop from x0 to xN-1
double temp = NAN;
for (std::int32_t i = 0; i < N; i++) {
temp = func(xi + h / 2); // find f(xi+h/2)
data_table.insert(
std::pair<std::int32_t, double>(i, temp)); // add i and f(xi)
xi += h; // Get the next point xi for the next iteration
}
// Evaluate the integral.
// Remember: {f(x0+h/2) + f(x1+h/2) + ... + f(xN-1+h/2)}
double evaluate_integral = 0;
for (std::int32_t i = 0; i < N; i++) evaluate_integral += data_table.at(i);
// Multiply by the coefficient h
evaluate_integral *= h;
// If the result calculated is nan, then the user has given wrong input
// interval.
assert(!std::isnan(evaluate_integral) &&
"The definite integral can't be evaluated. Check the validity of "
"your input.\n");
// Else return
return evaluate_integral;
}
/**
* @brief A function f(x) that will be used to test the method
* @param x The independent variable xi
* @returns the value of the dependent variable yi = f(xi) = sqrt(xi) + ln(xi)
*/
double f(double x) { return std::sqrt(x) + std::log(x); }
/**
* @brief A function g(x) that will be used to test the method
* @param x The independent variable xi
* @returns the value of the dependent variable yi = g(xi) = e^(-xi) * (4 -
* xi^2)
*/
double g(double x) { return std::exp(-x) * (4 - std::pow(x, 2)); }
/**
* @brief A function k(x) that will be used to test the method
* @param x The independent variable xi
* @returns the value of the dependent variable yi = k(xi) = sqrt(2*xi^3 + 3)
*/
double k(double x) { return std::sqrt(2 * std::pow(x, 3) + 3); }
/**
* @brief A function l(x) that will be used to test the method
* @param x The independent variable xi
* @returns the value of the dependent variable yi = l(xi) = xi + ln(2*xi + 1)
*/
double l(double x) { return x + std::log(2 * x + 1); }
} // namespace midpoint_rule
} // namespace numerical_methods
/**
* @brief Self-test implementations
* @param N is the number of intervals
* @param h is the step
* @param a is x0
* @param b is the end of the interval
* @param used_argv_parameters is 'true' if argv parameters are given and
* 'false' if not
*/
static void test(std::int32_t N, double h, double a, double b,
bool used_argv_parameters) {
// Call midpoint() for each of the test functions f, g, k, l
// Assert with two decimal point precision
double result_f = numerical_methods::midpoint_rule::midpoint(
N, h, a, numerical_methods::midpoint_rule::f);
assert((used_argv_parameters || (result_f >= 4.09 && result_f <= 4.10)) &&
"The result of f(x) is wrong");
std::cout << "The result of integral f(x) on interval [" << a << ", " << b
<< "] is equal to: " << result_f << std::endl;
double result_g = numerical_methods::midpoint_rule::midpoint(
N, h, a, numerical_methods::midpoint_rule::g);
assert((used_argv_parameters || (result_g >= 0.27 && result_g <= 0.28)) &&
"The result of g(x) is wrong");
std::cout << "The result of integral g(x) on interval [" << a << ", " << b
<< "] is equal to: " << result_g << std::endl;
double result_k = numerical_methods::midpoint_rule::midpoint(
N, h, a, numerical_methods::midpoint_rule::k);
assert((used_argv_parameters || (result_k >= 9.06 && result_k <= 9.07)) &&
"The result of k(x) is wrong");
std::cout << "The result of integral k(x) on interval [" << a << ", " << b
<< "] is equal to: " << result_k << std::endl;
double result_l = numerical_methods::midpoint_rule::midpoint(
N, h, a, numerical_methods::midpoint_rule::l);
assert((used_argv_parameters || (result_l >= 7.16 && result_l <= 7.17)) &&
"The result of l(x) is wrong");
std::cout << "The result of integral l(x) on interval [" << a << ", " << b
<< "] is equal to: " << result_l << std::endl;
}
/**
* @brief Main function
* @param argc commandline argument count (ignored)
* @param argv commandline array of arguments (ignored)
* @returns 0 on exit
*/
int main(int argc, char** argv) {
std::int32_t N =
16; /// Number of intervals to divide the integration interval.
/// MUST BE EVEN
double a = 1, b = 3; /// Starting and ending point of the integration in
/// the real axis
double h = NAN; /// Step, calculated by a, b and N
bool used_argv_parameters =
false; // If argv parameters are used then the assert must be omitted
// for the test cases
// Get user input (by the command line parameters or the console after
// displaying messages)
if (argc == 4) {
N = std::atoi(argv[1]);
a = std::atof(argv[2]);
b = std::atof(argv[3]);
// Check if a<b else abort
assert(a < b && "a has to be less than b");
assert(N > 0 && "N has to be > 0");
if (N < 4 || a != 1 || b != 3) {
used_argv_parameters = true;
}
std::cout << "You selected N=" << N << ", a=" << a << ", b=" << b
<< std::endl;
} else {
std::cout << "Default N=" << N << ", a=" << a << ", b=" << b
<< std::endl;
}
// Find the step
h = (b - a) / N;
test(N, h, a, b, used_argv_parameters); // run self-test implementations
return 0;
}

View File

@ -1,97 +1,348 @@
#include <iostream>
using namespace std;
/**
* @file
* @brief Implementation for a [Circular Linked
* List](https://www.geeksforgeeks.org/circular-linked-list/).
* @details A Circular Linked List is a variation on the regular linked list, in
* which the last node has a pointer to the first node, which creates a full
* circle. Consequently, this allows any node to be used as the starting point
* for the list.
* @author [Alvin](https://github.com/polarvoid)
*/
struct node {
int val;
node *next;
#include <cassert> /// for assert
#include <iostream> /// for IO operations
#include <vector> /// for std::vector
/**
* @namespace operations_on_datastructures
* @brief Operations on Data Structures
*/
namespace operations_on_datastructures {
/**
* @namespace circular_linked_list
* @brief Functions for the [Circular Linked
* List](https://www.geeksforgeeks.org/circular-linked-list/) implementation
*/
namespace circular_linked_list {
/**
* @brief A Node struct that represents a single Node in a Binary Tree
*/
struct Node {
int64_t data; ///< The value of the Node
Node* next; ///< The Node's successor
/**
* @brief Creates a new Node with some initial data
* @param _data Value of Node
*/
explicit Node(int64_t _data) {
data = _data; ///< Set value of Node data
next = nullptr; ///< Initialize successor
}
/**
* @brief Creates a new Node with initial data and a successor
* @param _data Value of Node
* @param _next Pointer to the next Node
*/
explicit Node(int64_t _data, Node* _next) {
data = _data; ///< Set value of Node data
next = _next; ///< Initialize successor
}
};
node *start;
/**
* @brief A class that implements a Circular Linked List.
*/
class CircularLinkedList {
private:
Node* root; ///< Pointer to the root Node
Node* end{}; ///< Pointer to the last Node
void insert(int x) {
node *t = start;
if (start != NULL) {
while (t->next != start) {
t = t->next;
public:
/**
* @brief Creates an empty CircularLinkedList.
*/
CircularLinkedList() {
root = nullptr;
end = nullptr;
}
/**
* @brief Copy constructor for CircularLinkedList.
*/
CircularLinkedList(const CircularLinkedList& copy) {
erase();
root = nullptr;
Node* node = copy.root;
while (node != nullptr) {
insert(node->data);
node = node->next;
}
node *n = new node;
t->next = n;
n->val = x;
n->next = start;
} else {
node *n = new node;
n->val = x;
start = n;
n->next = start;
}
}
void remove(int x) {
node *t = start;
node *p;
while (t->val != x) {
p = t;
t = t->next;
/**
* @brief Move constructor for CircularLinkedList
* @param source rvalue reference to a Circular Linked List
*/
CircularLinkedList(CircularLinkedList&& source) noexcept {
root = source.root;
end = source.end;
source.root = nullptr;
source.end = nullptr;
}
p->next = t->next;
delete t;
}
void search(int x) {
node *t = start;
int found = 0;
while (t->next != start) {
if (t->val == x) {
cout << "\nFound";
found = 1;
break;
/**
* @brief Copy assignment operator
* @param other Reference to a Circular Linked List
* @returns Reference to CircularLinkedList
*/
CircularLinkedList& operator=(const CircularLinkedList& other) {
erase();
root = nullptr;
Node* node = other.root;
while (node != nullptr) {
insert(node->data);
node = node->next;
}
t = t->next;
return *this;
}
if (found == 0) {
cout << "\nNot Found";
/**
* @brief Move assignment operator
* @param other rvalue reference to a Circular Linked List
* @returns Reference to CircularLinkedList
*/
CircularLinkedList& operator=(CircularLinkedList&& other) noexcept {
root = other.root;
end = other.end;
other.root = nullptr;
other.end = nullptr;
return *this;
}
/**
* @brief Cleans up memory when destroyed
*/
~CircularLinkedList() { erase(); }
/**
* Iteratively frees each node in the Circular Linked List from the heap
*/
void erase() {
if (root == nullptr) {
return;
}
Node* node = root;
do {
Node* temp = node;
node = node->next;
delete (temp);
} while (node != root);
root = nullptr;
end = nullptr;
}
/**
* @brief Inserts all the values from a vector into the Circular Linked List
* @details Goes through each element in the vector sequentially, inserting
* it into the list
* @param values The vector of integer values that is to be inserted
* @returns void
*/
void insert(const std::vector<int64_t>& values) {
for (int64_t value : values) {
insert(value);
}
}
/**
* @brief Inserts a single value into the Circular Linked List
* @details Creates a Node with the given value, pointing to the root Node
* and inserts it into the list
* @param data The integer valus to be inserted
* @returns void
*/
void insert(int64_t data) {
Node* node = new Node(data, root);
insert(node);
}
/**
* @brief Inserts a given Node into the Circular Linked List
* @details Checks wheter the list is empty, and inserts the Node, modifying
* the end pointer
* @param node The Node that is to be inserted
* @returns void
*/
void insert(Node* node) {
if (root == nullptr) {
root = node; ///< Set node as the root
node->next = root; ///< Point node to itself
end = root; ///< Set the end to the root
} else {
end->next = node; ///< Append node to the end
node->next = root; ///< Set the next value to the root
end = node; ///< Make end point to node
}
}
/**
* @brief Prints the values of the Circular Linked List, beginning from the
* root Node
* @details Goes through each Node from the root and prints them out in
* order
* @returns void
*/
void print() { print(root); }
/**
* @brief Prints the values of the Circular Linked List, beginning from a
* given Node to be used as the root
* @details Goes through each Node from the given Node and prints them out
* in order. If the list is empty, it prints the message 'Empty List!'
* @param root The Node to start at
* @returns void
*/
void print(Node* root) {
Node* temp = root;
if (root == nullptr) {
std::cout << "Empty List!\n";
return;
}
do {
std::cout << temp->data << " ";
temp = temp->next;
} while (temp != root);
std::cout << "\n";
}
/**
* @brief Returns a std::vector of the values of the Circular Linked List
* @details Starting from the root Node, appends each value of the list to a
* std::vector and returns it
* @returns A std::vector of the list's values
*/
std::vector<int64_t> values() { return values(root); }
/**
* @brief Returns a std::vector of the values of the Circular Linked List,
* beginning from a given Node
* @details Starting from a given Node, appends each value of the list to a
* std::vector and returns it
* @param root The Node to start at
* @returns A std::vector of the list's values
*/
std::vector<int64_t> values(Node* root) {
std::vector<int64_t> res;
if (root == nullptr) {
return res; ///< Return empty vector
}
Node* temp = root;
do {
res.push_back(temp->data);
temp = temp->next;
} while (temp != root);
return res;
}
};
} // namespace circular_linked_list
} // namespace operations_on_datastructures
/**
* @namespace tests
* @brief Testcases to check Circular Linked List.
*/
namespace tests {
using operations_on_datastructures::circular_linked_list::CircularLinkedList;
using operations_on_datastructures::circular_linked_list::Node;
/**
* @brief A Test to check a single value
* @returns void
*/
void test1() {
std::cout << "TEST CASE 1\n";
std::cout << "Intialized a = {2}\n";
std::cout << "Expected result: {2}\n";
CircularLinkedList a;
std::vector<int64_t> res = {2};
a.insert(2);
assert(a.values() == res);
a.print();
std::cout << "TEST PASSED!\n\n";
}
/**
* @brief A Test to check a few values
* @returns void
*/
void test2() {
std::cout << "TEST CASE 2\n";
std::cout << "Intialized a = {2, 5, 6}\n";
std::cout << "Expected result: {2, 5, 6}\n";
CircularLinkedList a;
std::vector<int64_t> res = {2, 5, 6};
a.insert(2);
a.insert(5);
a.insert(6);
assert(a.values() == res);
a.print();
std::cout << "TEST PASSED!\n\n";
}
/**
* @brief A Test to check an input array
* @returns void
*/
void test3() {
std::cout << "TEST CASE 3\n";
std::cout << "Intialized a = {2, 7, 8, 3, 2, 6}\n";
std::cout << "Expected result: {2, 7, 8, 3, 2, 6}\n";
CircularLinkedList a;
std::vector<int64_t> res = {2, 7, 8, 3, 2, 6};
a.insert({2, 7, 8, 3, 2, 6});
a.print();
assert(a.values() == res);
std::cout << "TEST PASSED!\n\n";
}
/**
* @brief A Test to check using a specific Node as the starting point
* @returns void
*/
void test4() {
std::cout << "TEST CASE 4\n";
std::cout << "Intialized a = {2, 5}\n";
std::cout << "Expected result: {5, 2}\n";
CircularLinkedList a;
std::vector<int64_t> res = {5, 2};
a.insert(2);
Node* start = new Node(5); ///< Node we will start printing from
a.insert(start);
assert(a.values(start) == res);
a.print(start);
std::cout << "TEST PASSED!\n\n";
}
void show() {
node *t = start;
do {
cout << t->val << "\t";
t = t->next;
} while (t != start);
/**
* @brief A Test to check an empty list
* @returns void
*/
void test5() {
std::cout << "TEST CASE 5\n";
std::cout << "Intialized a = {}\n";
std::cout << "Expected result: Empty List!\n";
CircularLinkedList a;
std::vector<int64_t> res = {};
assert(a.values() == res);
a.print();
std::cout << "TEST PASSED!\n\n";
}
} // namespace tests
/**
* @brief Function to test the correctness of the Circular Linked List
* @returns void
*/
static void test() {
tests::test1();
tests::test2();
tests::test3();
tests::test4();
tests::test5();
}
/**
* @brief main function
* @returns 0 on exit
*/
int main() {
int choice, x;
do {
cout << "\n1. Insert";
cout << "\n2. Delete";
cout << "\n3. Search";
cout << "\n4. Print";
cout << "\n\nEnter you choice : ";
cin >> choice;
switch (choice) {
case 1:
cout << "\nEnter the element to be inserted : ";
cin >> x;
insert(x);
break;
case 2:
cout << "\nEnter the element to be removed : ";
cin >> x;
remove(x);
break;
case 3:
cout << "\nEnter the element to be searched : ";
cin >> x;
search(x);
break;
case 4:
show();
break;
}
} while (choice != 0);
test(); // run self-test implementations
return 0;
}