mirror of
https://github.com/libretro/cpp-cheat.git
synced 2025-04-14 09:10:25 +00:00
cpp: improved constexpr, added struct, improved tuple, data_structure: improved graph
This commit is contained in:
parent
5d73516a57
commit
fdeb187369
78
boost/graph.cpp
Normal file
78
boost/graph.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
//=======================================================================
|
||||
// Copyright 2001 Jeremy G. Siek, Andrew Lumsdaine, Lie-Quan Lee,
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//=======================================================================
|
||||
#include <boost/config.hpp>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include <boost/graph/dijkstra_shortest_paths.hpp>
|
||||
#include <boost/property_map/property_map.hpp>
|
||||
|
||||
using namespace boost;
|
||||
|
||||
int
|
||||
main(int, char *[])
|
||||
{
|
||||
typedef adjacency_list < listS, vecS, directedS,
|
||||
no_property, property < edge_weight_t, int > > graph_t;
|
||||
typedef graph_traits < graph_t >::vertex_descriptor vertex_descriptor;
|
||||
typedef graph_traits < graph_t >::edge_descriptor edge_descriptor;
|
||||
typedef std::pair<int, int> Edge;
|
||||
|
||||
const int num_nodes = 5;
|
||||
enum nodes { A, B, C, D, E };
|
||||
char name[] = "ABCDE";
|
||||
Edge edge_array[] = { Edge(A, C), Edge(B, B), Edge(B, D), Edge(B, E),
|
||||
Edge(C, B), Edge(C, D), Edge(D, E), Edge(E, A), Edge(E, B)
|
||||
};
|
||||
int weights[] = { 1, 2, 1, 2, 7, 3, 1, 1, 1 };
|
||||
int num_arcs = sizeof(edge_array) / sizeof(Edge);
|
||||
graph_t g(edge_array, edge_array + num_arcs, weights, num_nodes);
|
||||
property_map<graph_t, edge_weight_t>::type weightmap = get(edge_weight, g);
|
||||
std::vector<vertex_descriptor> p(num_vertices(g));
|
||||
std::vector<int> d(num_vertices(g));
|
||||
vertex_descriptor s = vertex(A, g);
|
||||
|
||||
dijkstra_shortest_paths(g, s,
|
||||
predecessor_map(boost::make_iterator_property_map(p.begin(), get(boost::vertex_index, g))).
|
||||
distance_map(boost::make_iterator_property_map(d.begin(), get(boost::vertex_index, g))));
|
||||
|
||||
std::cout << "distances and parents:" << std::endl;
|
||||
graph_traits < graph_t >::vertex_iterator vi, vend;
|
||||
for (boost::tie(vi, vend) = vertices(g); vi != vend; ++vi) {
|
||||
std::cout << "distance(" << name[*vi] << ") = " << d[*vi] << ", ";
|
||||
std::cout << "parent(" << name[*vi] << ") = " << name[p[*vi]] << std::
|
||||
endl;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
std::ofstream dot_file("figs/dijkstra-eg.dot");
|
||||
|
||||
dot_file << "digraph D {\n"
|
||||
<< " rankdir=LR\n"
|
||||
<< " size=\"4,3\"\n"
|
||||
<< " ratio=\"fill\"\n"
|
||||
<< " edge[style=\"bold\"]\n" << " node[shape=\"circle\"]\n";
|
||||
|
||||
graph_traits < graph_t >::edge_iterator ei, ei_end;
|
||||
for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) {
|
||||
graph_traits < graph_t >::edge_descriptor e = *ei;
|
||||
graph_traits < graph_t >::vertex_descriptor
|
||||
u = source(e, g), v = target(e, g);
|
||||
dot_file << name[u] << " -> " << name[v]
|
||||
<< "[label=\"" << get(weightmap, e) << "\"";
|
||||
if (p[v] == u)
|
||||
dot_file << ", color=\"black\"";
|
||||
else
|
||||
dot_file << ", color=\"grey\"";
|
||||
dot_file << "]";
|
||||
}
|
||||
dot_file << "}";
|
||||
return EXIT_SUCCESS;
|
||||
}
|
31
boost/main.cpp
Normal file
31
boost/main.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
Boost is the most important C++ utilities library.
|
||||
|
||||
It has very widespread use, and some of its features have been included or are candidates for inclusion
|
||||
on newer versions of the STL.
|
||||
|
||||
Full list of libs: <http://www.boost.org/doc/libs/>
|
||||
|
||||
Some of boost libraries may be in separate packages / shared objects than others.
|
||||
|
||||
The convention is: `-lboost_XXX` to include libs in gcc, for exapmle `-lboost_graph`
|
||||
*/
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/iterator/counting_iterator.hpp>
|
||||
|
||||
using namespace boost;
|
||||
|
||||
int main(int, char *[])
|
||||
{
|
||||
//#counting_iterator
|
||||
{
|
||||
std::vector<int> v(boost::counting_iterator<int>(0), boost::counting_iterator<int>(3));
|
||||
assert((v == std::vector<int>{0, 1, 2}));
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
1
boost/makefile
Symbolic link
1
boost/makefile
Symbolic link
@ -0,0 +1 @@
|
||||
../makefile.individual_out
|
2
boost/makefile_params
Normal file
2
boost/makefile_params
Normal file
@ -0,0 +1,2 @@
|
||||
LIBS := -lboost_graph -lm
|
||||
PHONY := install-deps-ubuntu
|
4
boost/makefile_targets
Normal file
4
boost/makefile_targets
Normal file
@ -0,0 +1,4 @@
|
||||
install-deps-ubuntu:
|
||||
sudo apt-get install -y libboost-dbg
|
||||
sudo apt-get install -y libboost-doc
|
||||
sudo apt-get install -y libboost-graph-dev
|
122
c/c.c
122
c/c.c
@ -396,12 +396,14 @@ int setjmp_func( bool jmp, jmp_buf env_buf )
|
||||
If those are used for documentation purposes, they don't need to match those of the definition.
|
||||
This is highly confusing however.
|
||||
|
||||
Definitions need parameter names.
|
||||
Definitions need parameter names. This rule changes in C++.
|
||||
*/
|
||||
|
||||
void decl_def_args( int, float, char c );
|
||||
void decl_def_args( int i, float f, char d ){}
|
||||
|
||||
//void def_no_argname( int ){}
|
||||
|
||||
/* One major application of forward declarations is to break loops */
|
||||
|
||||
int factorial2Funcs1(int);
|
||||
@ -3006,12 +3008,14 @@ int main( int argc, char **argv )
|
||||
assert( ( 1 && 1 ) == 1 );
|
||||
|
||||
/*
|
||||
For `||` and `&&`, the second side is only evaluated if needed.
|
||||
#short circuit evaluation
|
||||
|
||||
On this example:
|
||||
For operators `||`, `&&` and `?`, the second side is only evaluated if needed.
|
||||
|
||||
- 1 is evaulated to true
|
||||
- || does not need to go any further, so i++ is not evaluated
|
||||
On this example:
|
||||
|
||||
- 1 is evaulated to true
|
||||
- || does not need to go any further, so i++ is not evaluated
|
||||
*/
|
||||
{
|
||||
int i = 0;
|
||||
@ -3658,9 +3662,35 @@ int main( int argc, char **argv )
|
||||
}
|
||||
|
||||
/*
|
||||
store array length in variables
|
||||
#store array length in variables
|
||||
|
||||
Before C99, it was not possible to store array length in variables,
|
||||
not even if they are const.
|
||||
|
||||
The two workarounds were:
|
||||
|
||||
- enum
|
||||
- macros
|
||||
|
||||
C99 introduces VLA which allows that.
|
||||
|
||||
In C++, this changes, even if there is no VLA as of C++11.
|
||||
*/
|
||||
{
|
||||
{
|
||||
//int n = 2;
|
||||
//int isVla[n] = { 1, 2 };
|
||||
//ERROR
|
||||
//cannot be initialized
|
||||
}
|
||||
|
||||
{
|
||||
//const int n = 2;
|
||||
//int isVla[n] = { 1, 2 };
|
||||
//ERROR
|
||||
//cannot be initialized
|
||||
}
|
||||
|
||||
//enum
|
||||
{
|
||||
enum M {M=3};
|
||||
@ -3668,12 +3698,15 @@ int main( int argc, char **argv )
|
||||
is[2] = 1;
|
||||
}
|
||||
|
||||
//define
|
||||
/*
|
||||
macro
|
||||
|
||||
Shares the disadvantage of every macro of having no scope.
|
||||
|
||||
Use enum instead.
|
||||
*/
|
||||
{
|
||||
#define DEFINESIZE 3
|
||||
//BAD
|
||||
//*no scope*, so you can't use N anymore.
|
||||
//use enum instead
|
||||
int is[DEFINESIZE];
|
||||
is[2] = 1;
|
||||
}
|
||||
@ -3697,20 +3730,6 @@ int main( int argc, char **argv )
|
||||
//OK
|
||||
int isVla[n];
|
||||
}
|
||||
|
||||
{
|
||||
//int n = 2;
|
||||
//int isVla[n] = { 1, 2 };
|
||||
//ERROR
|
||||
//cannot be initialized
|
||||
}
|
||||
|
||||
{
|
||||
//const int n = 2;
|
||||
//int isVla[n] = { 1, 2 };
|
||||
//ERROR
|
||||
//cannot be initialized
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4387,19 +4406,58 @@ int main( int argc, char **argv )
|
||||
{
|
||||
//#if
|
||||
{
|
||||
if ( -1 )
|
||||
{
|
||||
assert( 1 );
|
||||
}
|
||||
if ( 0 )
|
||||
{
|
||||
// Only 0 counts as false.
|
||||
if ( 0 ) {
|
||||
assert( 0 );
|
||||
}
|
||||
if ( 1 )
|
||||
{
|
||||
|
||||
if (1){
|
||||
assert( 1 );
|
||||
}
|
||||
|
||||
if (-1) {
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (-1) {
|
||||
} else if (0) {
|
||||
assert(0);
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
//can ommit braces for single statements
|
||||
{
|
||||
{
|
||||
if (0) assert(0);
|
||||
if (0)
|
||||
assert(0);
|
||||
if (0) { assert(0); }
|
||||
}
|
||||
|
||||
{
|
||||
if (0)
|
||||
assert(0);
|
||||
else
|
||||
assert(1);
|
||||
}
|
||||
|
||||
//possible but very ugly to use only one pair of braces
|
||||
{
|
||||
if (0) {
|
||||
assert(0);
|
||||
} else
|
||||
assert(1);
|
||||
|
||||
if (0)
|
||||
assert(0);
|
||||
else {
|
||||
assert(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//scope
|
||||
{
|
||||
int i = 0;
|
||||
|
@ -2,12 +2,14 @@
|
||||
but sketches of how to implement data structures.
|
||||
|
||||
The goal of those implementations is only educational.
|
||||
Obviously, don't reimplement standard data structers, but use the existing STL ones instead.
|
||||
It is a great exercise to try and implement the fundamental data structures yourself,
|
||||
as you will probably meet new needs and difficulties which will lead you to learn more C++.
|
||||
Obviously, don't reimplement existing STL data structers but use the existing ones instead.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath> //ceil
|
||||
#include <limits>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
@ -418,7 +420,7 @@ class BST : Map<KEY,VAL>
|
||||
|
||||
- if the node is found
|
||||
|
||||
- if it is not the current node, its parent
|
||||
- if it is not the current node, its pasrent
|
||||
- else, NULL
|
||||
|
||||
- else, the last searched parent node
|
||||
@ -700,26 +702,130 @@ class Hash {
|
||||
};
|
||||
|
||||
/**
|
||||
Represents a graph via adjency lists.
|
||||
Graph
|
||||
|
||||
Implementation notes:
|
||||
|
||||
- undirected: store edges only once on the edge with smaller index.
|
||||
*/
|
||||
|
||||
/**
|
||||
Represents a directed graph via adjency lists.
|
||||
*/
|
||||
class GraphList {
|
||||
|
||||
public:
|
||||
typedef std::vector<int>::size_type EdgeNumberType ;
|
||||
class Edge {
|
||||
public:
|
||||
Edge(){}
|
||||
Edge( EdgeNumberType to, int weight ) : to(to), weight(weight) {}
|
||||
|
||||
GraphList(){
|
||||
// To which vertex this edge goes to.
|
||||
EdgeNumberType to;
|
||||
int weight;
|
||||
};
|
||||
typedef std::pair<EdgeNumberType,std::vector<Edge> > NodeEdgesPair;
|
||||
|
||||
GraphList() {}
|
||||
GraphList(std::initializer_list<NodeEdgesPair> pairs) {
|
||||
for (auto& pair : pairs)
|
||||
this->add( pair );
|
||||
}
|
||||
|
||||
/**
|
||||
Adds a node / edges pair to the graph.
|
||||
|
||||
If the node number is larger than the current number of nodes, the current number of
|
||||
nodes is increased to fit that new list of edges.
|
||||
|
||||
No error check is done to see if one of the edges points to a destination node that is not in the graph,
|
||||
If you add such an edge, you must also explicitly add the node afterwards, even if it has no edges coming
|
||||
out of it for example via:
|
||||
|
||||
graph.add({1234, {}});
|
||||
*/
|
||||
void add(NodeEdgesPair pair) {
|
||||
EdgeNumberType node_number = pair.first;
|
||||
if (nodes.size() < node_number + 1) {
|
||||
nodes.resize(node_number + 1);
|
||||
}
|
||||
nodes[node_number] = pair.second;
|
||||
}
|
||||
|
||||
std::string str() const {
|
||||
std::stringstream ss;
|
||||
for (EdgeNumberType i = 0; i < nodes.size(); ++i) {
|
||||
ss << i << ": ";
|
||||
for (auto& edge : nodes[i]) {
|
||||
ss << edge.to << "," << edge.weight << " ";
|
||||
}
|
||||
ss << std::endl;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/**
|
||||
Calculates the shortest path from one node to another.
|
||||
|
||||
Recommended for dense graphs (unordered list implementation).
|
||||
|
||||
@param[out] path contains the shortest from from to to
|
||||
|
||||
@return true iff a path was found. The path may not exist in case of a non connex input.
|
||||
This algorithm can detect that case.
|
||||
*/
|
||||
bool dijikstra(const EdgeNumberType& from,
|
||||
const EdgeNumberType& to,
|
||||
std::vector<EdgeNumberType>& path) {
|
||||
std::list<EdgeNumberType> not_visited(nodes.size(), false);
|
||||
std::vector<int> distances(nodes.size(), std::numeric_limits<int>::max());
|
||||
std::vector<EdgeNumberType> previous(nodes.size());
|
||||
EdgeNumberType cur(from);
|
||||
distances[cur] = 0;
|
||||
for (EdgeNumberType i = 0; i < nodes.size(); ++i)
|
||||
not_visited.push_back(i);
|
||||
while (true) {
|
||||
// Find non visited min and make it current.
|
||||
auto it = std::min_element(not_visited.begin(), not_visited.end());
|
||||
previous[*it] = cur;
|
||||
cur = *it;
|
||||
not_visited.erase(it);
|
||||
if (cur == to)
|
||||
break;
|
||||
if (not_visited.empty())
|
||||
return false;
|
||||
// Update weights of nodes neighbour to cur.
|
||||
for (auto& edge : nodes[cur]) {
|
||||
//if (!not_visited[edge.to]) { //could maintain a visited array
|
||||
//this would prevent useless new_distance calculations
|
||||
//however this is not worth it as it would use more memory
|
||||
//and require that that array be kept up to date
|
||||
int new_distance = distances[cur] + edge.weight;
|
||||
if (new_distance < distances[edge.to]) {
|
||||
distances[edge.to] = new_distance;
|
||||
}
|
||||
//}
|
||||
}
|
||||
}
|
||||
// Rebuild the path.
|
||||
path = std::vector<EdgeNumberType>();
|
||||
cur = to;
|
||||
path.push_back(cur);
|
||||
while (cur != from) {
|
||||
cur = previous[cur];
|
||||
path.push_back(cur);
|
||||
}
|
||||
std::reverse(path.begin(), path.end()); //TODO with a push_front container this would not be necessary.
|
||||
//so what to do? force the users to give push_front containers?
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::vector<Edge> > nodes;
|
||||
|
||||
std::vector<int> lists;
|
||||
};
|
||||
|
||||
class GraphMatrix {
|
||||
|
||||
public:
|
||||
|
||||
private:
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const GraphList& rhs) {
|
||||
return os << rhs.str();
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char** argv)
|
||||
@ -727,12 +833,12 @@ int main(int argc, char** argv)
|
||||
typedef Hash<int,int> map_t;
|
||||
//map_t mapOrig(0, 1);
|
||||
map_t mapOrig{
|
||||
std::pair<int,int>(0,1),
|
||||
std::pair<int,int>(1,2),
|
||||
std::pair<int,int>(2,3),
|
||||
std::pair<int,int>(3,4),
|
||||
std::pair<int,int>(4,5),
|
||||
std::pair<int,int>(-1,0),
|
||||
{ 0, 1},
|
||||
{ 1, 2},
|
||||
{ 2, 3},
|
||||
{ 3, 4},
|
||||
{ 4, 5},
|
||||
{-1, 0},
|
||||
};
|
||||
map_t map;
|
||||
map_t mapExpect;
|
||||
@ -790,7 +896,7 @@ int main(int argc, char** argv)
|
||||
map = mapOrig;
|
||||
assert( map == mapOrig );
|
||||
|
||||
map.add( 5, 6);
|
||||
map.add(5, 6);
|
||||
assert( map != mapOrig );
|
||||
|
||||
|
||||
@ -814,10 +920,10 @@ int main(int argc, char** argv)
|
||||
|
||||
//add at powers of 2 the 0 hash so they clutter at hash 0
|
||||
map = map_t( 0, 1 );
|
||||
map.add( 1, 2 );
|
||||
map.add( 2, 3 );
|
||||
map.add( 4, 5 );
|
||||
map.add( 8, 9 );
|
||||
map.add( 1, 2 );
|
||||
map.add( 2, 3 );
|
||||
map.add( 4, 5 );
|
||||
map.add( 8, 9 );
|
||||
map.add( 16, 17 );
|
||||
|
||||
//find
|
||||
@ -829,9 +935,49 @@ int main(int argc, char** argv)
|
||||
assert( ! map.find( 0, val ) );
|
||||
}
|
||||
|
||||
/*
|
||||
// Graphs.
|
||||
{
|
||||
GraphList g;
|
||||
// Dijikstra tests.
|
||||
{
|
||||
// Input graphs and origin dest pair and expected output shortest paths.
|
||||
std::tuple<GraphList,
|
||||
std::pair<GraphList::EdgeNumberType,GraphList::EdgeNumberType>,
|
||||
std::vector<GraphList::EdgeNumberType> >in_outs[]{
|
||||
{
|
||||
{
|
||||
{0, {{0, 1}}},
|
||||
{1, {}},
|
||||
},
|
||||
{0, 1},
|
||||
{0, 1}
|
||||
},
|
||||
{
|
||||
{
|
||||
{0, {{0, 1}}},
|
||||
{1, {{1, 2}}},
|
||||
{2, {{2, 3}}},
|
||||
{3, {}},
|
||||
},
|
||||
{0, 3},
|
||||
{0, 1, 2, 3}
|
||||
},
|
||||
};
|
||||
for (auto& in_out : in_outs) {
|
||||
auto& graph = std::get<0>(in_out);
|
||||
auto& origin_destination = std::get<1>(in_out);
|
||||
auto& expected_path = std::get<2>(in_out);
|
||||
std::vector<GraphList::EdgeNumberType> path;
|
||||
std::cout << graph << std::endl;
|
||||
std::cout << "dijikstra path:" << std::endl;
|
||||
graph.dijikstra(origin_destination.first, origin_destination.second, path);
|
||||
for (auto& node_number : path)
|
||||
std::cout << node_number << std::endl;
|
||||
std::cout << std::endl;
|
||||
assert(path == expected_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user