I have implemented a Binary Search Tree in C++ which support dynamically creating and deleting nodes. To visualize the tree, I firstly tried displaying edges with / and \. However, this gives really awful visualization, as the position of / and \ needs to be calculated precisely. The current figures are as follows:
So I found a tool called Graphviz. The raw language supported by Graphviz is dot language, which I am not familiar with.
I read the documentation and found the dot language easy to write and read, but I still want to use my C++ code to generate the tree as this contains much content such as inserting according to user's input.
Is there any chance to use some function to generate the dot file?
The code of my binary tree:
//BTNode.h
#include <iostream>
using namespace std;
template<class T>
struct BTNode{
BTNode(){
lChild = rChild = NULL;
}
BTNode(const T& x){
element = x;
lChild = rChild = NULL;
}
BTNode(const T& x, BTNode<T>* l, BTNode<T>* r){
element = x;
lChild = l;
rChild = r;
}
T element;
int digit, row;
BTNode<T>* lChild, *rChild;
};
//BSTree.h
#include"ResultCode.h"
#include "BTNode.h"
#include "seqqueue.h"
#include <math.h>
template <class T>
class BSTree
{
public:
BSTree(){ root = NULL; }
ResultCode SearchByRecursion(T& x)const;
ResultCode Insert(T& x);
ResultCode Remove(T& x);
void InOrder(void(*Visit)(T& x));
ResultCode SearchByIteration(T& x);
void GradeOrder(void(*Visit)(T &x), BTNode<T> *t, int height);
BTNode<T>* root;
void printSpace(int num);
int GetHeight();
int GetHeight(BTNode<T> *t);
int **A;
private:
ResultCode SearchByRecursion(BTNode<T> *p, T& x)const;
void InOrder(void(*Visit)(T& x), BTNode<T> *t);
};
template <class T>
ResultCode BSTree<T>::SearchByRecursion(T &x)const{
return SearchByRecursion(root, x);
}
template <class T>
ResultCode BSTree<T>::SearchByRecursion(BTNode<T> *p, T& x)const{
if (!p) return NotPresent;
else if (x < p->element) return SearchByRecursion(p->lChild, x);
else if (x > p->element) return SearchByRecursion(p->rChild, x);
else{
x = p->element;
return Success;
}
}
template <class T>
ResultCode BSTree<T>::SearchByIteration(T& x){
BTNode<T> *p = root;
while (p)
if (x < p->element) p = p->lChild;
else if (x > p->element) p = p->rChild;
else{
x = p->element;
return Success;
}
return NotPresent;
}
template<class T>
ResultCode BSTree<T>::Insert(T& x){
BTNode<T> *p = root, *q = NULL;
while (p){
q = p;
if (x < p->element) p = p->lChild;
else if (x > p->element) p = p->rChild;
else { x = p->element; return Duplicate; }
}
p = new BTNode<T>(x);
if (!root) root = p;
else if (x < q->element) q->lChild = p;
else q->rChild = p;
return Success;
}
template <class T>
ResultCode BSTree<T>::Remove(T& x){
BTNode<T> *c, *s, *r, *p = root, *q = NULL;
while (p && p->element != x){
q = p;
if (x < p->element) p = p->lChild;
else p = p->rChild;
}
if (!p) return NotPresent;
x = p->element;
if (p->lChild&&p->rChild)
{
s = p->rChild;
r = p;
while (s->lChild){
r = s; s = s->lChild;
}
p->element = s->element;
p = s; q = r;
}
if (p->lChild)
c = p->lChild;
else c = p->rChild;
if (p == root)
root = c;
else if (p == q->lChild)
q->lChild = c;
else q->rChild = c;
delete p;
return Success;
}
template <class T>
void BSTree<T>::InOrder(void(*Visit)(T &x)){
InOrder(Visit, root);
}
template <class T>
void BSTree<T>::InOrder(void(*Visit)(T &x), BTNode<T> *t){
if (t){
InOrder(Visit, t->lChild);
Visit(t->element);
InOrder(Visit, t->rChild);
}
}
template <class T>
void BSTree<T>::GradeOrder(void(*Visit)(T &x), BTNode<T> *t, int height)
{
A = new int*[height];
for (int i = 0; i < height; i++){
A[i] = new int[(int)pow(2, height) - 1];
}
for (int i = 0; i < height; i++)
for (int j = 0; j < (int)pow(2, height) - 1; j++){
A[i][j] = -1;
}
SeqQueue<BTNode<T>*> OrderQueue(10);
BTNode<T> * loc = t;
loc->row = 0;
loc->digit = 0;
if (loc){
OrderQueue.EnQueue(loc);
A[loc->row][loc->digit] = loc->element;
}
while (!OrderQueue.IsEmpty())
{
OrderQueue.Front(loc);
OrderQueue.DeQueue();
if (loc->lChild)
{
A[(loc->row) + 1][2 * (loc->digit)] = loc->lChild->element;
loc->lChild->row = (loc->row) + 1;
(loc->lChild->digit) = (loc->digit) * 2;
OrderQueue.EnQueue(loc->lChild);
}
if (loc->rChild)
{
A[(loc->row) + 1][2 * (loc->digit) + 1] = loc->rChild->element;
loc->rChild->row = (loc->row) + 1;
(loc->rChild->digit) = (loc->digit) * 2 + 1;
OrderQueue.EnQueue(loc->rChild);
}
}
cout << endl;
int total = (int)(pow(2, height)) - 1;
for (int i = 0; i < height; i++){
if (i != 0){
cout << endl;
}
int space1 = (total / (int)(pow(2, i + 1)));
int space2;
if (i == 0){
space2 = 0;
}
else{
space2 = (total - 2 * space1 - (int)pow(2, i)) / (int)(pow(2, i) - 1);
}
printSpace(space1);
for (int j = 0; j < (int)pow(2, i); j++){
if (A[i][j] != -1){
cout << A[i][j];
}
else{
cout << " ";
}
printSpace(space2);
}
printSpace(space1);
cout << endl;
}
}
template <class T>
void BSTree<T>::printSpace(int num){
for (int i = 0; i < num; i++){
cout << " ";
}
}
template<class T>
int BSTree<T>::GetHeight()
{
return GetHeight(root);
}
template<class T>
int BSTree<T>::GetHeight(BTNode<T> *t)
{
if (!t)return 0;
if ((!t->lChild) && (!t->rChild)) return 1;
int lHeight = GetHeight(t->lChild);
int rHeight = GetHeight(t->rChild);
return (lHeight > rHeight ? lHeight : rHeight) + 1;
}
template <class T>
void Visit(T& x){
cout << x << " ";
}
//main.cpp
#include <iostream>
#include "BSTree4.h"
#include<Windows.h>
int getDigit(int x);
int main(){
BSTree<int> bt;
int number;
// char choice;
cout << "Welcome to BSTree System, to begin with, you need to create a tree!(Press enter to continue...)" << endl;
getchar();
cout << "Please enter the size of the Binary Search Tree:";
cin >> number;
int *ToBeInserted = new int[number];
cout << "Enter the number of each Node(size:" << number << "):";
for (int i = 0; i < number; i++){
cin >> ToBeInserted[i];
}
cout << "OK,now the tree will be created!" << endl;
for (int i = 0; i < number; i++){
cout << "Inserting Node " << i;
for (int k = 0; k < 3; k++){
cout << ".";
//Sleep(200);
}
showResultCode(bt.Insert(ToBeInserted[i]));
//Sleep(500);
}
cout << "Done." << endl;
//Sleep(500);
int height = bt.GetHeight();
bt.GradeOrder(Visit, bt.root,height);
int a;
cout << "please enter the number to search:";
cin>>a;
showResultCode(bt.SearchByRecursion(a));
bt.GradeOrder(Visit, bt.root,height);
if (bt.SearchByRecursion(a) == 7){
cout << "Now delete the number" << "..." << endl;
showResultCode(bt.Remove(a));
bt.GetHeight();
cout << "Deleted!Now the tree is:" << endl;
bt.GradeOrder(Visit, bt.root, height);
bt.InOrder(Visit);
cout << endl;
}
return 0;
}
//resultcode.h
#include<iostream>
using namespace std;
enum ResultCode{ NoMemory, OutOfBounds, Underflow, Overflow, Failure,
NotPresent, Duplicate, Success };
void showResultCode(ResultCode result)
{
int r = (int)result;
switch (result)
{
case 0:cout << "NoMemory" << endl; break;
case 1:cout << "OutOfBounds" << endl; break;
case 2:cout << "Underflow" << endl; break;
case 3:cout << "Overflow" << endl; break;
case 4:cout << "Failure" << endl; break;
case 5:cout << "NotPresent" << endl; break;
case 6:cout << "Duplicate" << endl; break;
case 7:cout << "Success" << endl; break;
default: cout << "Exception occured:unknown resultcode" << endl;
}
}
Update: I have solved the problem myself, check the answer below.
The key elements in dot language file in this problem are nodes and edges. Basically the dot file structure for a binary tree would be like the following:
digraph g {
//all the nodes
node0[label="<f0>|<f1> value |<f2>"]
node1[label="<f0>|<f1> value |<f2>"]
node2[label="<f0>|<f1> value |<f2>"]
...
//all the edges
"node0":f2->"node4":f1;
"node0":f0->"node1":f1;
"node1":f0->"node2":f1;
"node1":f2->"node3":f1;
...
}
The following output of the dot file can be used to understand the structure:
Explanation for the dot file:
For the node part node0[label="<f0>|<f1> value |<f2>"] means the node called node0 has three parts: <f0> is the left part, <f1> is the middle part with a value, <f2> is the right part. This just corresponds to leftchild, value and rightchild in a binary node.
For the edges part, "node0":f2->"node4":f1; means the right part of node0(i.e.<f2>) points to the middle part of node4 (i.e. <f1>).
Therefore, the way to generate the dot file is simply through a traverse of a binary tree. Any method is fine. (BFS,DFS...) All we need is to add the code to write the nodes and corresponding edges into file when we do the traverse. I personally used BFS with level order traverse of a binary tree to implement which is shown below as a function called showTree.
void showTree(BSTree<int> &bst,int total,int *Inserted){
char filename[] = "D:\\a.gv"; // filename
ofstream fout(filename);
fout << "digraph g{" << endl;
fout << "node [shape = record,height = .1];" << endl;
SeqQueue<BTNode<int>*> OrderQueue(1000);
BTNode<int> * loc = bst.root;
loc->row = 0;
loc->digit = 0;
int num = 0;
if (loc){
OrderQueue.EnQueue(loc);
loc->ID = num++;
fout << " node" << loc->ID << "[label = \"<f0> |<f1>" << loc->element << "|<f2>\"];" << endl;
}
while (!OrderQueue.IsEmpty())
{
OrderQueue.Front(loc);
OrderQueue.DeQueue();
if (loc->lChild)
{
loc->lChild->row = (loc->row) + 1;
(loc->lChild->digit) = (loc->digit) * 2;
OrderQueue.EnQueue(loc->lChild);
loc->lChild ->ID= (num++);
fout << " node" << loc->lChild->ID << "[label = \"<f0> |<f1>" << loc->lChild->element << "|<f2>\"];" << endl;
//cout << loc->ID;
}
if (loc->rChild)
{
loc->rChild->row = (loc->row) + 1;
(loc->rChild->digit) = (loc->digit) * 2 + 1;
OrderQueue.EnQueue(loc->rChild);
loc->rChild->ID = (num++);
fout << " node" << loc->rChild->ID << "[label = \"<f0> |<f1>" << loc->rChild->element << "|<f2>\"];" << endl;
//cout << loc->ID;
}
}
//begin to draw!
SeqQueue<BTNode<int>*> OrderQueue2(1000);
BTNode<int> * loc2 = bst.root;
loc2->row = 0;
loc2->digit = 0;
if (loc2){
OrderQueue2.EnQueue(loc2);
}
while (!OrderQueue2.IsEmpty())
{
OrderQueue2.Front(loc2);
OrderQueue2.DeQueue();
if (loc2->lChild)
{
loc2->lChild->row = (loc2->row) + 1;
(loc2->lChild->digit) = (loc2->digit) * 2;
OrderQueue2.EnQueue(loc2->lChild);
cout << "\"node" << loc2->ID << "\":f0->\"node" << loc2->lChild->ID << "\":f1;" << endl;
cout << loc2->lChild->element << endl;
fout << "\"node" << loc2->ID << "\":f0->\"node" << loc2->lChild->ID << "\":f1;" << endl;
}
if (loc2->rChild)
{
loc2->rChild->row = (loc2->row) + 1;
(loc2->rChild->digit) = (loc2->digit) * 2 + 1;
OrderQueue2.EnQueue(loc2->rChild);
cout << "\"node" << loc2->ID << "\":f2->\"node" << loc2->rChild->ID << "\":f1;" << endl;
cout << loc2->rChild->element << endl;
fout << "\"node" << loc2->ID << "\":f2->\"node" << loc2->rChild->ID << "\":f1;" << endl;
}
}
fout << "}" << endl;
}
And the final output:
Related
I have send this trough the mailing list but it seems not to be fully working at the moment so I am posting it here instead. The issue I am having is that I am trying to expand a periodic mesh and have it returned in a new c3t3 structure instead of having to save a .mesh file and load it afterwards. For this I have tried modifying the File_medit.h found in the Periodic_3_mesh_3/IO folder but am having a few issues. First of all, the tetrahedrals seem to not be properly added when I call the build_triangulation function although the finite_cell vector has all collected values in it. I am having a similar issue with the border_facets, although in this case I am also not sure what data I am supposed to place in surface_patch_id and if perhaps this is causing the issues. I have included the code I am using bellow. Any help is appreciated.
Regards, Kim
/* ==========================================================================
* Based on CGAL's File_medit.h. See CGAL Periodic_3_mesh_3/IO.
* ==========================================================================*/
#ifndef CGAL_PERIODIC_REPLICATOR_H
#define CGAL_PERIODIC_REPLICATOR_H
#include <CGAL/license/Periodic_3_mesh_3.h>
#include <CGAL/Mesh_3/io_signature.h>
#include <CGAL/Mesh_3/tet_soup_to_c3t3.h>
//
#include <CGAL/array.h>
#include <CGAL/assertions.h>
#include <CGAL/IO/File_medit.h>
#include <boost/unordered_map.hpp>
#include <algorithm>
#include <fstream>
#include <iostream>
#include <cstring>
#include <sstream>
#include <cstring>
#include <map>
namespace CGAL {
namespace periodic_replicator {
/**
* \brief expands a periodic mesh to the c3t3 variable
* \param c3t3_periodic the mesh
* \param occurrence_count the number of copies that are printed
* \param distinguish_copies if set to `true`, each copy is assigned a unique color.
* Otherwise, all domains are drawn with subdomain index-based colors.
* \param rebind if set to `true`, labels of cells are rebinded into [1..nb_of_labels]
* \param c3t3 the output mesh
*/
template <class C3T3_Periodic, class C3T3, bool rebind, bool no_patch> ////template <class C3T3_Periodic>
void replicate_periodic_mesh(const C3T3_Periodic& c3t3_periodic,
int occurrence_count[3],
const bool distinguish_copies,
C3T3& c3t3)
{
#ifdef CGAL_MESH_3_IO_VERBOSE
std::cerr << "Output to medit:\n";
#endif
CGAL_precondition(c3t3_periodic.triangulation().is_1_cover());
typedef CGAL::Mesh_3::Medit_pmap_generator<C3T3_Periodic, rebind, no_patch> Generator;
typedef typename Generator::Cell_pmap Cell_pmap;
typedef typename Generator::Facet_pmap Facet_pmap;
typedef typename Generator::Facet_pmap_twice Facet_pmap_twice;
typedef typename Generator::Vertex_pmap Vertex_pmap;
//Generator().print_twice();
Cell_pmap cell_pmap(c3t3_periodic);
Facet_pmap facet_pmap(c3t3_periodic, cell_pmap);
Facet_pmap_twice facet_pmap_twice(c3t3_periodic, cell_pmap);
Vertex_pmap vertex_pmap(c3t3_periodic, cell_pmap, facet_pmap);
// const Facet_index_property_map_twice& facet_twice_pmap = Facet_index_property_map_twice(),
const bool print_each_facet_twice = false;//Generator().print_twice();
CGAL_precondition(occurrence_count[0] >= 1 && occurrence_count[1] >= 1 && occurrence_count[2] >= 1);
// Periodic typedef
typedef typename C3T3_Periodic::Triangulation Triangulation_periodic;
typedef Triangulation_periodic Tr_periodic;
typedef typename Tr_periodic::Bare_point Bare_point;
typedef typename Tr_periodic::Weighted_point Weighted_point;
typedef typename C3T3_Periodic::Vertex_handle Vertex_handle;
typedef typename C3T3_Periodic::Cell_handle Cell_handle;
typedef typename Tr_periodic::Vertex_iterator Vertex_iterator;
typedef typename C3T3_Periodic::Facet_iterator Facet_iterator;
typedef typename C3T3_Periodic::Cell_iterator Cell_iterator;
typedef typename Tr_periodic::Offset Offset;
const Triangulation_periodic& tr_periodic = c3t3_periodic.triangulation();
// Non-periodic typedef
typedef typename C3T3::Triangulation Triangulation;
typedef Triangulation Tr;
typedef typename Tr::Point Point_3;
typedef std::array<int, 3> Facet; // 3 = id
typedef std::array<int, 5> Tet_with_ref; // first 4 = id, fifth = reference
//
std::vector<Point_3> points;
//std::map<Facet, typename Tr::Cell::Surface_patch_index> border_facets_;
std::map<Facet, typename C3T3::Surface_patch_index> border_facets;
std::vector<Tet_with_ref> finite_cells;
//
int number_of_vertices = static_cast<int>(tr_periodic.number_of_vertices());
int number_of_facets = static_cast<int>(c3t3_periodic.number_of_facets());
int number_of_cells = static_cast<int>(c3t3_periodic.number_of_cells());
// number of reproductions over the different axes
int Ox_rn = ceil(occurrence_count[0]);
int Oy_rn = ceil(occurrence_count[1]);
int Oz_rn = ceil(occurrence_count[2]);
int occ_mult = Ox_rn * Oy_rn * Oz_rn;
#ifdef CGAL_PERIODIC_3_MESH_3_VERBOSE
std::cerr << "Expanding periodic mesh... " << std::endl;
std::cerr << "occurrences over each axis: "
<< Ox_rn << " " << Oy_rn << " " << Oz_rn << std::endl;
std::cerr << number_of_vertices << " vertices" << std::endl;
std::cerr << number_of_facets << " facets" << std::endl;
std::cerr << number_of_cells << " cells" << std::endl;
#endif
std::ofstream os("output_control.mesh");
os << std::setprecision(17);
// Vertices
int medit_number_of_vertices = (Ox_rn + 1) * (Oy_rn + 1) * (Oz_rn + 1) * number_of_vertices;
os << "MeshVersionFormatted 1\n"
<< "Dimension 3\n"
<< "Vertices\n" << medit_number_of_vertices << std::endl;
// Build the set of points that is needed to draw all the elements.
// On each axis, we repeat n+1 times the point, where 'n' is the number of
// instances of the mesh that will be printed over that axis. This is because
// a cell 'c' might have point(c,i) that is equal to v with an offset 2
boost::unordered_map<Vertex_handle, int> V;
int inum = 1; // '1' because medit ids start at 1
for(int i=0; i<=Oz_rn; ++i) {
for(int j=0; j<=Oy_rn; ++j) {
for(int k=0; k<=Ox_rn; ++k) {
for(Vertex_iterator vit = tr_periodic.vertices_begin(); vit != tr_periodic.vertices_end(); ++vit) {
if(i == 0 && j == 0 && k == 0)
V[vit] = inum++;
const Offset off(k, j, i);
const Weighted_point& p = tr_periodic.point(vit);
const Bare_point bp = tr_periodic.construct_point(p, off);
int id;
if(i >= 1 || j >= 1 || k >= 1)
id = 7;
else
id = tr_periodic.off_to_int(off);
os << CGAL::to_double(bp.x()) << ' '
<< CGAL::to_double(bp.y()) << ' '
<< CGAL::to_double(bp.z()) << ' ';
if(!distinguish_copies || occ_mult == 1)
os << get(vertex_pmap, vit) << '\n';
else
os << 32 * id + 1 << '\n';
points.push_back(Point_3(CGAL::to_double(bp.x()),
CGAL::to_double(bp.y()),
CGAL::to_double(bp.z())));
}
}
}
}
// Triangles
int medit_number_of_triangles = occ_mult * number_of_facets;
if(print_each_facet_twice)
medit_number_of_triangles *= 2;
os << "Triangles\n" << medit_number_of_triangles << std::endl;
for(int i=0; i<Oz_rn; ++i) {
for(int j=0; j<Oy_rn; ++j) {
for(int k=0; k<Ox_rn; ++k) {
const Offset off(k, j, i);
for(Facet_iterator fit = c3t3_periodic.facets_begin(); fit != c3t3_periodic.facets_end(); ++fit) {
typename Tr::Cell::Surface_patch_index surface_patch_id;
Facet facet;
for(int l=0; l<4; ++l) {
if(l == fit->second)
continue;
Cell_handle c = fit->first;
Vertex_handle v = c->vertex(l);
const Offset combined_off = tr_periodic.combine_offsets(
off, tr_periodic.int_to_off(c->offset(l)));
const int vector_offset = combined_off.x() +
combined_off.y() * (Ox_rn + 1) +
combined_off.z() * (Ox_rn + 1) * (Oy_rn + 1);
const int id = vector_offset * number_of_vertices + V[v];
CGAL_assertion(1 <= id && id <= medit_number_of_vertices);
os << id << " ";
//facet[l] = id;
int temp_ = id;
facet[l] = temp_;
}
// For multiple copies, color to distinguish copies rather than to distinguish subdomains
//int temptest;
if(!distinguish_copies || occ_mult == 1){
os << get(facet_pmap, *fit) << '\n';
} else {
os << 1 + k + 3*j + 9*i << '\n';
}
surface_patch_id.first = 0;
surface_patch_id.second = 1;
border_facets.insert(std::make_pair(facet, surface_patch_id));
// Print triangle again if needed
if(print_each_facet_twice) {
for(int l=0; l<4; ++l) {
if(l == fit->second)
continue;
Cell_handle c = fit->first;
Vertex_handle v = c->vertex(l);
const Offset combined_off = tr_periodic.combine_offsets(
off, tr_periodic.int_to_off(c->offset(l)));
const int vector_offset = combined_off.x() +
combined_off.y() * (Ox_rn + 1) +
combined_off.z() * (Ox_rn + 1) * (Oy_rn + 1);
const int id = vector_offset * number_of_vertices + V[v];
CGAL_assertion(1 <= id && id <= medit_number_of_vertices);
os << id << " ";
int temp_ = id;
facet[l] = temp_;
}
if(!distinguish_copies || occ_mult == 1)
os << get(facet_pmap_twice, *fit) << '\n';
else
os << 1 + k + 3*j + 9*i << '\n';
//surface_patch_id = ???;
//border_facets.insert(std::make_pair(facet, surface_patch_id));
}
}
}
}
}
// Tetrahedra
os << "Tetrahedra\n" << occ_mult * number_of_cells << std::endl;
for(int i=0; i<Oz_rn; ++i) {
for(int j=0; j<Oy_rn; ++j) {
for(int k=0; k<Ox_rn; ++k) {
const Offset off(k, j, i);
for(Cell_iterator cit = c3t3_periodic.cells_begin(); cit !=c3t3_periodic.cells_end(); ++cit) {
Tet_with_ref t;
for(int l=0; l<4; ++l) {
const Offset combined_off = tr_periodic.combine_offsets(
off, tr_periodic.int_to_off(cit->offset(l)));
const int vector_offset = combined_off.x() +
combined_off.y() * (Ox_rn + 1) +
combined_off.z() * (Ox_rn + 1) * (Oy_rn + 1);
const int id = vector_offset * number_of_vertices + V[cit->vertex(l)];
CGAL_assertion(1 <= id && id <= medit_number_of_vertices);
os << id << " ";
t[l] = id - 1;
}
// For multiple copies, color to distinguish copies rather than to distinguish subdomains
if(!distinguish_copies || occ_mult == 1) {
os << get(cell_pmap, cit) << '\n';
t[4] = get(cell_pmap, cit);
} else {
os << 1 + k + 3*j + 9*i << '\n';
t[4] = 1 + k + 3*j + 9*i;
}
finite_cells.push_back(t);
}
}
}
}
os << "End" << std::endl;
//
//std::vector<typename Tr::Vertex_handle> vertices(0);
std::vector<typename Tr::Vertex_handle> vertices(points.size() + 1);
bool is_well_built = build_triangulation<Tr, true>(c3t3.triangulation(), points, finite_cells, border_facets, vertices, true/*verbose*/, false/*replace_domain*/);
// Check
std::cout << points.size() << " points" << std::endl;
std::cout << border_facets.size() << " border facets" << std::endl;
std::cout << finite_cells.size() << " cells" << std::endl;
std::cout << c3t3.number_of_facets() << " border facets expanded c3t3" << std::endl;
std::cout << c3t3.number_of_cells() << " cells expanded c3t3" << std::endl;
}
#ifdef CGAL_MESH_3_IO_VERBOSE
std::cerr << "done.\n";
#endif
} // namespace periodic_replicator
} // namespace CGAL
#endif // CGAL_PERIODIC_REPLICATOR_H
I get garbage value on this jagged array, that takes input size from another array's last value which must be -111(if not ten add one index to put in -111).
i know i have missed some cout statements but dont know why i get garbage vals
'''
int jaggedArr(int** arr2, int r, int c)
{
int* numbers = nullptr;
numbers = new int[r]; /// array to store no of columns
int** jagArr = new int* [r]; /// jagged array
for (int i = 0; i < r; i++)
{
int tempNum;
for (int j = 0; j < c; j++)
{ //store size of cols in arr4 to put int new array (arr3)
if (arr2[i][j] == -111)
{
tempNum = j;
numbers[i] = tempNum;//if -111 is present then dont change size just copy
}
else if (arr2[i][j] != -111)
{
tempNum = j + 1;
numbers[i] =tempNum;//else if -111 is not present then dont change size just copy
}
tempNum = 0;
}
}
for (int i = 0; i < r; i++)
{
jagArr[i] = new int[numbers[i]];
}
for (int i = 0; i < r; i++)
{
for (int j = 0; j < 10; j++)//remove 10
{
jagArr[i] = new int[numbers[i]];
}
}
cout << "Showing all the Inputed data in a matrix form" << endl;
for (int i = 0; i < r; i++) {
for (int j = 0; j < numbers[i]; j++)
{
//if (jagArr[i][j] >= 0 && jagArr[i][j] <= 9)
//{
// cout << jagArr[i][j] << " |";
//}
//else if (jagArr[i][j] == -111)
//{
// cout << jagArr[i][j] << "|";
//}
//else
//{
// cout << jagArr[i][j] << " |";
//}
cout << jagArr[i][j];
}
cout << "\n";
}
return **arr2;
}
'''
I am trying to save the data the user inputted inside a linked-list and then store those data inside a file so that I can retrieve them back when I enter the 2nd option(as per in the int main()). Unfortunately, after I wrote the data into the file and check back the file, I found out that my data is missing and the file is filled with garbage.so I cant retrieve the data back. Is there any solution to this problem?? Thank you.
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<fstream>
using namespace std;
fstream fp;
class List{
private:
struct node{
string name;
string surname;
int idNum;
string nationality;
int number;
node *next;
}nod;
node* head;
node* curr;
node* temp;
public:
List();
bool isEmpty(node *head){
if(head==NULL){
return true;
}
else
return false;
}
void AddNode(string addName,string addsurName,int addId,string addNation,int addNumber);
void insertAsFirst(string addName,string addsurName,int addId,string addNation,int addNum);
//void DeleteNode(int delData);
void printList();
void write_linky(string name,string surName,int idNum,string nation,int number);
void read_linky();
}lb;
List::List(){
head=NULL;
curr=NULL;
temp=NULL;
}
void List::insertAsFirst(string addName,string addsurName,int addId, string addNation,int addNum){
node *n = new node;
n->name=addName;
n->surname=addsurName;
n->idNum=addId;
n->nationality=addNation;
n->number=addNum;
n->next = NULL;
head = n;
//last = temp;
}
void List::AddNode(string addName,string addsurName,int addId,string addNation,int addNum){
if(isEmpty(head)){
insertAsFirst(addName,addsurName,addId,addNation,addNum);
}
else{
node* n = new node;
n->next=NULL;
n->name=addName;
n->surname=addsurName;
n->idNum=addId;
n->nationality=addNation;
n->number=addNum;
curr = head;
while(curr->next != NULL){
curr = curr->next;
}
curr->next = n;
}
}
void List::printList(){
curr=head;
cout << "\n\t\t\t\t CUSTOMER INFO" << endl << endl;
cout <<"NAME" << setw(20) << "SURNAME" << setw(20) << "ID NO. " << setw(20) << "NATIONALLITY" << setw(20) << "TELEPHONE" << endl << endl;
while(curr != NULL){
cout << curr -> name << setw(20) << curr -> surname << setw(20) << curr -> idNum << setw(20) << curr -> nationality << setw(20) << curr -> number << endl << endl;
curr=curr->next;
/*cout<<curr->number << endl;
cout<<curr->age << endl;
cout<<curr->idNum << endl;
cout<<curr->name<< endl;
cout<<curr->surname << endl;
cout<<curr->nationality << endl;
curr = curr->next;
}
*/
}
}
void List::write_linky(string name,string surName,int idNum,string nation,int number)
{
fp.open("Link.dat",ios::out|ios::app);
lb.AddNode(name,surName,idNum,nation,number);
lb.printList();
fp.write((char*)&nod,sizeof(node));
fp.close();
cout<<"\n\nThe Data Has Been Added ";
}
void List::read_linky(){
fp.open("Link.dat",ios::in);
while(fp.read((char*)&nod,sizeof(node)))
{
lb.printList();
//cout<<"\n\n=====================================================\n";
//getch();
}
fp.close();
//getch();
}
int main(){
List lb;
int idNum,number;
string name,surname,nationality;
char choice,ch;
cout<<"Please select your choice"<<endl;
cout<<"1.Book ticket"<<endl;
cout<<"2.view details"<<endl;
cin>>ch;
switch(ch){
case '1':
do{
cout<< "Enter name: ";
cin>>name;
cout<< "Enter surname: ";
cin>>surname;
cout<< "Enter identification number: ";
cin>>idNum;
cout<< "Enter your nationality: ";
cin>>nationality;
cout<< "Enter contact number: ";
cin>>number;
lb.write_linky(name,surname,idNum,nationality,number);
//lb.AddNode(number,age,idNum,name,surname,nationality);
cout<<"\n\nDo you want to add more entry?";
cin>>choice;
}while(choice=='y');
break;
case '2':
lb.read_linky();
break;
}
}
//lb.printList();
I've never done this but I'd guess string is a complex structure that doesn't lend itself to being written to disk like this. As a test change these to (say) char[255] and it might be happier.
So far i have this code that is suppose to be an ad hoc scanner, im not sure where exactly the problem is because i get a very odd error in the output.txt file. it all starts when the program hits the left parenthesis, is there somthing wrong with my checkforoperators function? i have looked but have found little and have even asked others, but no reall luck as to what the problem is.
the input file contains this
read A1
read A2
sum:=(A1-33)+A2*5.5
write sum
write (A1+A2)/2
and the output file is SUPPOSE to look like this
read
A1
read
A2
Sum
:=
(
A1
-
33
)
+
A2
*
5.5
write
sum
write
(
A1
+
A2
)
/
2
heres the main file
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
// This program is an ad-hoc scanner.
// It will recognize tokens and seperate them.
// this language will NOT DISTINGUISH between uppercase or lowercase.
void stripSpacing(string &);
void checkForCommands();
void checkForLetters();
void checkForOperators();
void checkForAssignment();
void checkForDecimal();
void checkForDigit();
int x1 = 0;
int x2 = 0;
int vars[10];
// Only for demonstration purposes, we could use a dynamic array for larger purposes.
string holder;
// used to hold the current string before processing.
fstream handling;
// file handling from other libraries.
fstream output;
char temp1[1];
char temp2[1];
int x = 0;
int xtemp = 0;
int main()
{
output.open("output.txt");
handling.open("input.txt");
if (handling.is_open())
{
while (!handling.eof())
{
dcom:
getline (handling,holder);
if(holder[x] == '/' && holder[x+1] == '/')
{
cout << "This line has only comments.... REMOVED :)" << endl;
//do nothing :)
goto dcom;
}
cout << endl;
stripSpacing(holder);
cout << "The line is this long after removing spaces: " << holder.length() << endl;
cout << "The line contains: " << holder << endl;
cout << endl;
while(holder.length() != x)
{
// let's check for commands, such as read write or sum.
checkForOperators();
checkForAssignment();
checkForDecimal();
checkForDigit();
checkForCommands();
checkForLetters();
}
output << "\n";
x=0;
}
handling.close();
output.close();
return 0;
}
}
void stripSpacing(string &str)
{
for (int i=0; i<str.length(); i++)
if (str[i]==' ')
{
str.erase(i,1);
i--;
}
}
void checkForOperators()
{
if(holder[x] == '(' || holder[x] == ')'|| holder[x] == '+' || holder[x] == '-' || holder[x] == '*' ||holder[x] == '/')
{
output << holder[x] + "\n";
x++;
}
cout << "checkForOpertors" << endl;
}
void checkForCommands()
{
xtemp = x;
if(holder[x] == 'w')
{
x++;
if(holder[x] == 'r')
{
x++;
if(holder[x] == 'i')
{
x++;
if(holder[x] == 't')
{
x++;
if(holder[x] == 'e')
{
x++;
output << "write\n"; goto stop;
}else{x=xtemp; goto stop;}
}else{x=xtemp; goto stop;}
}else{x=xtemp; goto stop;}
}else{x=xtemp; goto stop;}
}
if(holder[x] == 'r')
{
x++;
if(holder[x] == 'e')
{
x++;
if(holder[x] == 'a')
{
x++;
if(holder[x] == 'd')
{
x++;
output << "read\n"; goto stop;
}else{x=xtemp; goto stop;}
}else{x=xtemp; goto stop;}
}else{x=xtemp; goto stop;}
}
if(holder[x] == 's')
{
x++;
if(holder[x] == 'u')
{
x++;
if(holder[x] == 'm')
{
x++;
output << "sum\n"; goto stop;
}else{x=xtemp; goto stop;}
}else{x=xtemp; goto stop;}
}
stop:
cout << "checkForCommand" << endl;
}
void checkForLetters()
{
if(isalpha(holder[x]))
{
output << holder[x];
x++;
}
cout << "checkForLetters" << endl;
}
void checkForAssignment()
{
if(holder[x] == ':')
{
x++;
if(holder[x] == '=')
{
output << ":=\n";
x++;
}
else
{
cout << "ERROR!!! NO : BEFORE =" << endl;
}
}
cout << "checkForAssign" << endl;
}
void checkForDecimal()
{
if(holder[x] == '.')
{
x++;
if(isdigit(holder[x]))
{
output << '.';
x--;
}
}
cout << "checkForDeci" << endl;
}
void checkForDigit()
{
if(isdigit(holder[x]))
{
output << holder[x];
x++;
}
cout << "checkForDig" << endl;
}
I have a class (contains a few scalar values and a vector of floats) and I want to read and write an instance as the value of another map.
// write
out << YAML::Key << "my_queue" << YAML::Value << my_queue;
// read (other code cut out...)
for (YAML::Iterator it=doc.begin();it!=doc.end();++it)
{
std::string key, value;
it.first() >> key;
it.second() >> value;
if (key.compare("my_queue") == 0) {
*it >> my_queue;
}
}
Writing this class works perfectly, but I can't seem to read it no matter what I do. It keeps throwing an InvalidScalar.
Caught YAML::InvalidScalar yaml-cpp: error at line 20, column 13: invalid scalar
and this is that the output (written with yaml-cpp without it reporting any errors) looks like:
Other Number: 80
my_queue:
size: 20
data:
- 3.5
- -1
- -1.5
- 0.25
- -24.75
- -5.75
- 2.75
- -33.55
- 7.25
- -11
- 15
- 37.5
- -3.75
- -28.25
- 18.5
- 14.25
- -36.5
- 6.75
- -0.75
- 14
max_size: 20
mean: -0.0355586
stdev: 34.8981
even_more_data: 1277150400
The documentation seems to say this is supported usage, a nested map, in this case with a sequence as one of the values. It complains about it being an InvalidScalar, even though the first thing I do it tell it that this is a map:
YAML::Emitter& operator << ( YAML::Emitter& out, const MeanStd& w )
{
out << YAML::BeginMap;
out << YAML::Key << "size";
out << YAML::Value << w.size();
out << YAML::Key << "data";
out << YAML::Value << YAML::BeginSeq;
for(Noor::Number i=0; i<w.size(); ++i) {
out << w[i];
}
out << YAML::EndSeq;
out << YAML::Key << "max_size";
out << YAML::Value << w.get_max_size();
out << YAML::Key << "mean";
out << YAML::Value << w.mean();
out << YAML::Key << "stdev";
out << YAML::Value << w.stdev();
out << YAML::EndMap;
return out;
}
Does anyone see a problem with this?
When you're reading the YAML:
std::string key, value;
it.first() >> key;
it.second() >> value; // ***
if (key.compare("my_queue") == 0) {
*it >> my_queue;
}
The marked line tries to read the value of the key/value pair as a scalar (std::string); that's why it tells you that it's an invalid scalar. Instead, you want:
std::string key, value;
it.first() >> key;
if (key.compare("my_queue") == 0) {
it.second() >> my_queue;
} else {
// ...
// for example: it.second() >> value;
}
YAML::Node internalconfig_yaml = YAML::LoadFile(configFileName);
const YAML::Node &node = internalconfig_yaml["config"];
for(const auto& it : node )
{
std::cout << "\nnested Key: " << it.first.as<std::string>() << "\n";
if (it.second.Type() == YAML::NodeType::Scalar)
{
std::cout << "\nnested value: " << std::to_string(it.second.as<int>()) << "\n";
}
if (it.second.Type() == YAML::NodeType::Sequence)
{
std::vector<std::string> temp_vect;
const YAML::Node &nestd_node2 = it.second;
for(const auto& it2 : nestd_node2)
{
if (*it2)
{
std::cout << "\nnested sequence value: " << it2.as<std::string>() << "\n";
temp_vect.push_back(it2.as<std::string>());
}
}
std::ostringstream oss;
std::copy(temp_vect.begin(), temp_vect.end(),
std::ostream_iterator<std::string>(oss, ","));
std::cout << "\nnested sequence as string: " <<oss.str() << "\n";
}
}
if (it2.second.Type() == YAML::NodeType::Map)
{
// Iterate Recursively again !!
}