Hi, guys, I need some help to figure out how to get my program working.

Program description: The purpose of this program is to all the user to input
names of city and their (x, y) coordinates on a 2D map. Once more than 2
different cities are entered, the user has the option to calculate the distance
between any 2 cities. If the user chooses the same 2 cities, then they are
prompted to change cities. On the other hand, if the user has reached the
maximum city allowed in the list, then they are given the option to delete a
city in order to enter another one. Finally, the user has the option to view
all the cities entered.

Here is my code:

Header file:

#ifndef CLASSES_HEADER_INCLUDED
#define CLASSES_HEADER_INCLUDED

class City
{
    private:
            string city_name;
            Point p;
    public:
            double distance(City other) const
                { return location.distance(other.location); }
};

class City_List
{
            vector<City> L;
            Point p;

     private:
            string input(string prompt);
            string name_entry(string& name);
            bool valid_entry(string name);
            bool get_name();
            bool get_x();
            bool get_y();

    public:
            void Display();
            void Add_City(City c) {L.push_back(c);};
            bool Delete(vector<City>::size_type index);
            bool Find(City c, string name);


};

class Point                
{
             double x, y;

    public:

            Point(void);
            Point(double new_x, double new_y);
            Point(const Point & p);

            void Output(void) const;
            void Input(void);

            double distance (const Point & other) const;

            double get_x(void) const {return x;)
            double get_y(void) const {return y;)

            void set_x(double new_x);
            void set_y(double new_y);

};                    

#endif

Implementation file:

#include "cityclasses.h"

#include <cmath>
#include <iostream>


using namespace std;

void Point::Input(void)
{
    char dummy;
    cin >> dummy >> x >> dummy >> y >> dummy;
    return;
}

void Point::Output(void) const
{
    cout << '(' << x << ", " << y << ')';
    return;
}

double Point::distance(const Point & other) const
{
    return sqrt(pow(x-other.x, 2.0) + pow(other.y-y, 2.0));
}

void Point::set_x(double new_x)
{
    x = new_x;
    return;
}

void Point::set_y(double new_y)
{
    y = new_y;
    return;
}

Point::Point(const Point & p)
{
    x = p.x;
    y = p.y;
}

Point::Point(void)
{
    x = y = 0.0;
}

Point::Point(double new_x, double new_y)
{
    set_x(new_x);
    set_y(new_y);
}


bool City_List::valid_entry(string name)
{
    bool rv=true;
    for (int i = 0; i < L.size(); i++)
        if(L[i].city_name == name)
            rv = false;
    return rv;
}

void City_List::Display()
{
    if(L.empty() == 0)
    {
        cout << "List is empty" << endl;
    }
    else {

        for (short i=o; i < L.size(); i++)
        {
            cout << L[i].city_name;
            cout << "Point:" << L[i].p.x << endl;
            cout << "Point:" << L[i].p.y << endl;
            cout << endl;
        }
    }
}

string City_List::input(string prompt)
{
    cin.ignore(INT_MAX, '\n');
    cout << prompt;
    string response;
    getline (cin, response);

    return response;
}

bool City_List::Delete(int index)
{
    bool rv=true;
    if(index >= 0 && index < L.size())
    {
        for(int i = index; i < L.size() - 1; i++)
        {
            L[i] = L[i+1];
            L.pop_back();
        }
    }
    else {
        cerr >> "Bad index" << endl;
        rv = false;
    }

    return rv;
}


vector<City>::size_type City_List::Find(string name)
{
    vector<City>::size_type i = 0;
    while( i < L.size() && L[i].city_name != name)
    {
        i++;
    }
    return i;
}  


Main file:

#include <iostream>
#include <cmath>
#include <string>
#include <cctype>       
#include "cityclasses.h"


using namespace std;


int main()
{
    Point p;
    City c;
    char ltr;
    string name_delete;
    City_List L;
    char CAPS;

    do
    {
        cout << "Please choose from the following options below:" << endl;
        cout << "1. Add a City information \n 2. Calculate Distance between cities \n 3. Print all cities \n 4. Delete a city \n 5. Quit \n";
        cin >> ltr;

        cin.ignore(INT_MAX, '\n');
        if(isalpha(ltr))
            CAPS = toupper(ltr);

        if(ltr == '1' || CAPS == 'A' || CAPS == 'B')
        {
            L.input_city();
        }

        else if (ltr == '2' || CAPS == 'C' || CAPS == 'D')
        {
            L.distance();
        }

        else if (ltr == '3' || CAPS == 'P')
        {
            L.Display();
        }

        else if (ltr == '4')
        {
            name_Delete = L.input("Which city do you want to delete" << endl);

            if(!L.Find(c, name_Delete))
            {
                cerr << "City not found" << endl;
            }
        }
                //cerr << "The city name was not found" << endl;

        else if (ltr == '5')
        {
            cout << "Goodbye" << endl;
        }

    }

    while (ltr != '5');

    return 0;
}        

Where I am having trouble is the Class City (public part), how can I use this function to calculate the distance between 2 cities once they are entered.

If someone can check my code and help me, that would be very helpful.

Thanks

Your coding work can be made SO MUCH easier ... if you JUST use a vector to hold the cites ... in the main program.

(Then you can use the STL supplied vector iterators, etc..)

See this running start:

(Note all the code (sections) that has (have) /* not used here */ around it, as that code (section) is not needed to do the jobs requested.

// distanceTwoCities.cpp //

#include <iostream>
//#include <fstream>
#include <string>
#include <vector>
#include <cmath>
//#include <cctype>

using namespace std;


const string MENU = "Please choose from the following options below: \n"
                    "1. Add a city \n"
                    "2. Calculate distance between cities \n"
                    "3. Print all cities \n"
                    "4. Delete a city \n"
                    "5. Quit \n";

class Point
{
public:
    Point(void);

/*
    Point(double new_x, double new_y);
    Point(const Point & p);

    void set_x(double new_x) { x = new_x; }
    void set_y(double new_y) { y = new_y; }

    double get_x(void) const { return x; }
    double get_y(void) const { return y; }
*/
    void takeIn(void);

    double distance (const Point & other) const;

private:
    double x, y;
    friend ostream& operator << ( ostream& os, const Point& p )
    {
        return os << p.x << ", " << p.y;
    }
} ;

Point::Point(void)
{
    x = y = 0.0;
}
/*
Point::Point(double new_x, double new_y)
{
    x = new_x;
    y = new_y;
}
Point::Point(const Point & p)
{
    x = p.x;
    y = p.y;
}
*/
void Point::takeIn(void)
{
    char comma;
    for( ; ; )
    {
        cout << "Enter point x,y (enter comma also) :  ";
        cin >> x >> comma >> y;
        if( cin.good() ) break;
        cin.clear();
        cin.sync();
        cout << "\b***Only NUMBERS valid*** here ... Try again!\n";
    }

    string dummy;
    getline( cin, dummy ); // eat '\n' etc at end ...
}

double Point::distance(const Point & other) const
{
    return sqrt( pow(x-other.x, 2.0) + pow(other.y-y, 2.0) );
}


class City
{
public:
    void takeIn_city_name()
    {
        cout << "Enter city name: " << flush;
        getline( cin, city_name );
    }
    void takeIn_p()
    {
        p.takeIn();
    }

    string get_city_name() const { return city_name; }
    //Point get_p() const { return p; }

    double distance( const City& other ) const
    { return p.distance(other.p); }

private:
    string city_name;
    Point p;
    friend ostream& operator << ( ostream& os, const City& c )
    {
        return os << c.city_name << ", (" << c.p << ")";
    }
} ;

// utilities used here ...
int takeInChar( const string& msg )
{
    cout << msg << flush;
    string reply;
    getline( cin, reply );
    if( reply.size() )
        return reply[0];
    // else ...
    return 0;
}
/*
bool more()
{
    if( tolower( takeInChar( "More (y/n) ? " )) == 'n' )
        return false;
    // else ...
    return true;
}
*/

void takeInCity( vector < City >& c )
{
    City cty;
    cty.takeIn_city_name();
    cty.takeIn_p();
    c.push_back( cty );
}

void showDistance( const vector < City >& c )
{
    City a, b;
    a.takeIn_city_name();

    vector < City > :: const_iterator it, ita, itb;

    ita = c.end(); // set default to NOT found
    for( it = c.begin(); it != c.end(); ++it )
    {
        if( it->get_city_name() == a.get_city_name() )
        {
            ita = it;
            break; // out right now since found ...
        }
    }
    if( ita == c.end() ) // NOT found ...
    {
        cout << a.get_city_name() << " NOT found.\n";
        return;
    }

    b.takeIn_city_name();

    itb = c.end(); // set default to NOT found ...
    for( it = c.begin(); it != c.end(); ++it )
    {
        if( it->get_city_name() == b.get_city_name() )
        {
            itb = it;
            break; // out right now since found ...
        }
    }
    if( itb == c.end() ) // NOT found ...
    {
        cout << b.get_city_name() << " NOT found.\n";
        return;
    }

    cout << "\nThe distance from " << a.get_city_name()
         << " to " << b.get_city_name()
         << " is " << ita->distance( *itb ) << endl << endl;
}

void printAll( const vector < City >& c )
{
    cout << "\nAll cites listed:\n";
    vector < City > :: const_iterator it;
    for( it = c.begin(); it != c.end(); ++it ) cout << *it << endl;
    cout << endl;
}

int main()
{
    vector< City > cities;
    int reply = 0;
    do
    {
        cout << MENU << flush;
        reply = takeInChar( "\nEnter your choice (1..5) :  " );

        switch( reply )
        {
            case '1' : takeInCity( cities ); break;
            case '2' : showDistance( cities ); break;
            case '3' : printAll( cities ); break;

            case '4' : cout << "\n\nNot implemented yet ...\n\n"; break;

            case '5' : cout << "\nExiting now ... \n"; break;
            default  : cout << "\nInvalid entry ... try again ...\n";
        }
    }
    while( reply != '5' );
}

Edited 2 Years Ago by David W: added words to clear up meaning

can I leave the point class and pointList class in the program, need to incorporate it to receive full credit.

How do I go about doing that?

Thanks

Just pull the respect code parts out ...

and put them into a ...

.h file (with appropriate 'guards')

and a ...

.cpp file that includes the .h file

Then include the .h file in your main (test program)

Edited 2 Years Ago by David W: fixed spelling typo

SO will the above code you provided do what my program describes in the first post.

What am I suppose to put where the //else... is?

int takeInChar( const string& msg )
{
    cout << msg << flush;
    string reply;
    getline( cin, reply );
    if( reply.size() )
        return reply[0];
    // else ...
    return 0;

Have you tested the code to see if it works?

Thanks

So my program requirements are to have 2 classes (Point and City) and if I add another class for City_list I get more points.

How can I add the 3rd class?

Here is some questions I asked regarding the sort:

"Hi, I am in your csc 122 class and had a question regarding the lab
where you are supposed to compare 2 strings. For the 2 and 3 extra
points, the program is supposed to sort the letter/numbers.
>
Not truly sort, but compare such that the sort would work as desired. Recall that during any sort algorithm we've ever studied (or probably conceived of), two elements are compared to determine their appropriate order relative to one another. You are trying to fix your string comparison function so that it will not only be insensitive to case, but also intuitively order strings with aligned numeric sub-sequences. That way, your function could be used from within a sort to order such number-containing strings in a manner amenable to human desires.

Regarding
this, am I supposed to include a txt file (which the program is calling)
in which the program reads and sorts it for you (like your example in
this lab) or does this sorting suppose to only work when the user inputs
data?

Your driver could use a sort to test your function, but that is not required. You just have to make sure your function works. Similarly you could use a file to house many test string pairs, but this is not required. Just make sure your program can test as many pairs of strings as deemed necessary by the person doing the testing."

  1. re.

    int takeInChar( const string& msg )
    {
        cout << msg << flush;
        string reply;
        getline( cin, reply );
        if( reply.size() )
            return reply[0];
        // else ... if did NOT return above ... then
        return 0;
    }
    

This is a (slightly more) efficent code than:

   int takeInChar( const string& msg )
    {
        cout << msg << flush;
        string reply;
        getline( cin, reply );
        if( reply.size() )
            return reply[0];
        else return 0;
    }

Edited 2 Years Ago by David W: change code indents

  • re. class City_list version ...

See how easy it is to get to that ... (working from the example already given) ...

// distanceTwoCitiesList.cpp //

#include <iostream>
//#include <fstream>
#include <string>

//#include <vector> // replaced here by list to make deletes fast and easy //
#include <list>
#include <cmath>
//#include <cctype>

using namespace std;


const string MENU = "Please choose from the following options below: \n"
                    "1. Add a city \n"
                    "2. Calculate distance between cities \n"
                    "3. Print all cities \n"
                    "4. Delete a city \n"
                    "5. Quit \n";

class Point
{
public:
    Point(void);

/*
    Point(double new_x, double new_y);
    Point(const Point & p);

    void set_x(double new_x) { x = new_x; }
    void set_y(double new_y) { y = new_y; }

    double get_x(void) const { return x; }
    double get_y(void) const { return y; }
*/
    void takeIn(void);

    double distance (const Point & other) const;

private:
    double x, y;
    friend ostream& operator << ( ostream& os, const Point& p )
    {
        return os << p.x << ", " << p.y;
    }
} ;

Point::Point(void)
{
    x = y = 0.0;
}
/*
Point::Point(double new_x, double new_y)
{
    x = new_x;
    y = new_y;
}
Point::Point(const Point & p)
{
    x = p.x;
    y = p.y;
}
*/
void Point::takeIn(void)
{
    char comma;
    for( ; ; )
    {
        cout << "Enter point x,y (enter comma also) :  ";
        cin >> x >> comma >> y;
        if( cin.good() ) break;
        cin.clear();
        cin.sync();
        cout << "\b***Only NUMBERS valid*** here ... Try again!\n";
    }

    string dummy;
    getline( cin, dummy ); // eat '\n' etc at end ...
}

double Point::distance(const Point & other) const
{
    return sqrt( pow(x-other.x, 2.0) + pow(other.y-y, 2.0) );
}


class City
{
public:
    void takeIn_city_name()
    {
        cout << "Enter city name: " << flush;
        getline( cin, city_name );
    }
    void takeIn_p()
    {
        p.takeIn();
    }

    string get_city_name() const { return city_name; }
    //Point get_p() const { return p; }

    double distance( const City& other ) const
    { return p.distance(other.p); }

private:
    string city_name;
    Point p;
    friend ostream& operator << ( ostream& os, const City& c )
    {
        return os << c.city_name << ", (" << c.p << ")";
    }
} ;

// utilities used here ...
int takeInChar( const string& msg )
{
    cout << msg << flush;
    string reply;
    getline( cin, reply );
    if( reply.size() )
        return reply[0];
    // else ...
    return 0;
}
/*
bool more()
{
    if( tolower( takeInChar( "More (y/n) ? " )) == 'n' )
        return false;
    // else ...
    return true;
}
*/

// THESE are NOW not used here ...
// (See how easily they are included in the new class City_list)
/*
void takeInCity( list < City >& c )
{
    City cty;
    cty.takeIn_city_name();
    cty.takeIn_p();
    c.push_back( cty );
}

void showDistance( const list < City >& c )
{
    City a, b;
    a.takeIn_city_name();

    list < City > :: const_iterator it, ita, itb;

    ita = c.end(); // set default to NOT found
    for( it = c.begin(); it != c.end(); ++it )
    {
        if( it->get_city_name() == a.get_city_name() )
        {
            ita = it;
            break; // out right now since found ...
        }
    }
    if( ita == c.end() ) // NOT found ...
    {
        cout << a.get_city_name() << " NOT found.\n";
        return;
    }

    b.takeIn_city_name();

    itb = c.end(); // set default to NOT found ...
    for( it = c.begin(); it != c.end(); ++it )
    {
        if( it->get_city_name() == b.get_city_name() )
        {
            itb = it;
            break; // out right now since found ...
        }
    }
    if( itb == c.end() ) // NOT found ...
    {
        cout << b.get_city_name() << " NOT found.\n";
        return;
    }

    cout << "\nThe distance from " << a.get_city_name()
         << " to " << b.get_city_name()
         << " is " << ita->distance( *itb ) << endl << endl;
}

void printAll( const list < City >& c )
{
    cout << "\nAll cites listed:\n";
    list < City > :: const_iterator it;
    for( it = c.begin(); it != c.end(); ++it ) cout << *it << endl;
    cout << endl;
}
*/

// wrapper class for list of cites ...
class City_list
{
public:
    void takeInCity()
    {
        City c;
        c.takeIn_city_name();
        c.takeIn_p();
        myCities.push_back( c );
    }
    void showDistance() const
    {
        City a, b;
        a.takeIn_city_name();

        list < City > :: const_iterator it, ita, itb;

        ita = myCities.end(); // set default to NOT found
        for( it = myCities.begin(); it != myCities.end(); ++it )
        {
            if( it->get_city_name() == a.get_city_name() )
            {
                ita = it;
                break; // out right now since found ...
            }
        }
        if( ita == myCities.end() ) // NOT found ...
        {
            cout << a.get_city_name() << " NOT found.\n";
            return;
        }

        b.takeIn_city_name();

        itb = myCities.end(); // set default to NOT found ...
        for( it = myCities.begin(); it != myCities.end(); ++it )
        {
            if( it->get_city_name() == b.get_city_name() )
            {
                itb = it;
                break; // out right now since found ...
            }
        }
        if( itb == myCities.end() ) // NOT found ...
        {
            cout << b.get_city_name() << " NOT found.\n";
            return;
        }

        cout << "\nThe distance from " << a.get_city_name()
             << " to " << b.get_city_name()
             << " is " << ita->distance( *itb ) << endl << endl;
    }

    void print() const
    {
        cout << "\nAll cites listed:\n";
        list < City > :: const_iterator it;
        for( it = myCities.begin(); it != myCities.end(); ++it )
            cout << *it << endl;
        cout << endl;
    }

private:
    list < City > myCities;
} ;

int main()
{
    City_list cities; // call default constructor
    int reply = 0;
    do
    {
        cout << MENU << flush;
        reply = takeInChar( "\nEnter your choice (1..5) :  " );

        switch( reply )
        {
            case '1' : cities.takeInCity(); break;
            case '2' : cities.showDistance(); break;
            case '3' : cities.print(); break;
            case '4' : cout << "\n\nNot implemented yet ...\n\n"; break;
            case '5' : cout << "\nExiting now ... \n"; break;
            default  : cout << "\nInvalid entry ... try again ...\n";
        }
    }
    while( reply != '5' );
}

Edited 2 Years Ago by David W: fix typo

re. if you want to add a sort function to sort by
1. names
or
2. points

to sort a C++ list, just call the STL sort provided

list < City > c;
// after taking in cities, c holds list of cities

// make sure you have already defined, 
// your GLOBAL desired compare function
bool cmpNames( const City& c1, const City& c2 )
{
   // to sort on name field ...
   return c1.get_city_name() < c2.get_city_name(); 
}

...

//call list sort
c.sort( cmpNames );

And ... of course ... update your MENU to include the added sort choice(s).

Edited 2 Years Ago by David W: Added text ...

Hi David, am confused about what I have to put into the header file? And regarding the city_list class and Point class, can I just use the /* */ (comments) like you did above while keeping the code in the program?

Thanks

Recall when using

/* ... */

that ...

/* 
    code here does NOT GET COMPILED 
    into executable code  
*/

So you can add comments ...

or ...

comment OUT CODE blocks that you think you might use in an alternate version of the program ...

or ...

just delete ... in your final version ... all the code blocks that you are not using.

If you can not use C++ string in your program, and need a class String, you might like to see this freshly just fixed-up demo student version, (with 3 demo 'test.cpp' files ...that illustrate the use of that class String) ... at this next link:

Edited 2 Years Ago by David W: fixed some text

quick question regarding the const menu you posted, should that go in the same file where I put the menu(in your case switch statments) or another file (where the functions are defined)

Thanks

My code works exactly as you mentioned above, I need help with the following:

  1. Make sure you allow them to choose their options by both the number and the capitalized letter(s) of the choice.

  2. If your list is full and they choose to enter another city, have them choose to either NOT enter the new city or to overwrite one of the earlier cities (they choose which one). Print the list of cities for them to choose from. (Remember, you still can't exceed your maximum list size!)

  3. add a submenu to sort the city list. The submenu should allow the user to choose whether to sort by name, x coordinate, or y coordinate. (Note: You can't simply sort by location since there is no way to compare 2D points without reference to a common line.) Just like the main menu, your submenu choices should be choosable by either their number or their capitalized letter. Have a fourth option to return to the main menu. (Implying that you'll stay in the submenu until they choose that option.)

  4. let user load and save city information from/to files. You can decide the format of the city information file. Note: you'll have to add a save option to the menu (or a question under 'print') and you'll have to ask if entry should come from the keyboard or a file. (Hint: You shouldn't need a new function to handle loading from a file — your current entry function should work fine with a little tweaking of the argument(s).)

Any help regarding the above would be great.

Thank you so much

My code works exactly as you mentioned above, I need help with the following:

Make sure you allow them to choose their options by both the number and the capitalized letter(s) of the choice.

case '1' : case 'A' : // rest of code ...

If your list is full and they choose to enter another city, have them choose to either NOT enter the new city or to overwrite one of the earlier cities (they choose which one). Print the list of cities for them to choose from. (Remember, you still can't exceed your maximum list size!)

Again ... you seem to NOT be using the C++ STL list container here ... if you use the STL list, you can just push_back all new objects to add to the list ... as long as there is still memory available.

add a submenu to sort the city list. The submenu should allow the user to choose whether to sort by name, x coordinate, or y coordinate.

(Note: You can't simply sort by location since there is no way to compare 2D points without reference to a common line.)

Not exactly true ... you COULD define a compare function.

Just like the main menu, your submenu choices should be choosable by either their number or their capitalized letter.

See above ...

Have a fourth option to return to the main menu. (Implying that you'll stay in the submenu until they choose that option.)

If your sub-menu is a function call from the main menu. it will drop back into the main menu ... when you exit that function call.

let user load and save city information from/to files. You can decide the format of the city information file. Note: you'll have to add a save option to the menu (or a question under 'print') and you'll have to ask if entry should come from the keyboard or a file. (Hint: You shouldn't need a new function to handle loading from a file — your current entry function should work fine with a little tweaking of the argument(s).)

Ok ... so you need to design a 'getCites' function (maybe with a flag that defaults to file) to use for file data entry AND user (with prompts) data entry.

Maybe something like:

bool takeInCites( list < Cities >& myCities, bool file = true );

You could perhaps use a Global file name to access the file, if needed.

#define FNAME "myCities.txt"

Edited 2 Years Ago by David W

Maybe something like this ...
(that uses C++ string, stringstream objects, etc...)

// distanceTwoCitiesList_sort3.cpp // // 2014-03-04 //

#include <iostream>
#include <fstream>
#include <string>
#include <sstream> // re. istringstream objects ...

//#include <vector> // replaced here by list to make deletes fast and easy //
#include <list>
#include <cmath>
//#include <cctype>

using namespace std;

/*
    Make sure you allow them to choose their options
    by both the number and the capitalized letter(s) of the choice.

    If your list is full and they choose to enter another city,
    have them choose to either NOT enter the new city or to overwrite
    one of the earlier cities (they choose which one).
    Print the list of cities for them to choose from.
    (Remember, you still can't exceed your maximum list size!)

*/
#define MAX_SIZE 10  // can use this and change size here as needed ...

/*
    add a submenu to sort the city list. The submenu should allow
    the user to choose whether to sort by name, x coordinate,
    or y coordinate. (Note: You can't simply sort by location since
    there is no way to compare 2D points without reference to
    a common line.) Just like the main menu, your submenu choices
    should be choosable by either their number or their capitalized
    letter. Have a fourth option to return to the main menu.
    (Implying that you'll stay in the submenu until they choose that
    option.)

    let user load and save city information from/to files.
    You can decide the format of the city information file.
    Note: you'll have to add a save option to the menu
    (or a question under 'print') and you'll have to ask if entry
    should come from the keyboard or a file.
    (Hint: You shouldn't need a new function to handle loading
    from a file — your current entry function should work
    fine with a little tweaking of the argument(s).)

*/
// 3 Global varibles used here to ease coding ... //
bool From_User = false;
bool To_Screen = true;
bool Update_Changes = false;

// constants ...
#define FNAME "myCities.txt"
const string MENU = "\nPlease choose from the following options below: \n"
                    /* "0. L oad all cites in file \n" */
                    "1. A dd a city \n"
                    "2. C alculate distance between cities \n"
                    "3. P rint all cities \n"
                    "4. D elete a city \n"
                    "5. S ort (by names or points) \n"
                    /* "6. W rite to file \n" */
                    "7. Q uit (and update file if needed) \n";


class Point
{
public:
    Point();

/*
    Point(double new_x, double new_y);
    Point(const Point & p);

    void set_x(double new_x) { x = new_x; }
    void set_y(double new_y) { y = new_y; }
*/
    double get_x(void) const { return x; }
    double get_y(void) const { return y; }

    void takeIn( istream& );

    double distance (const Point & other) const;

private:
    double x, y;
    friend ostream& operator << ( ostream& os, const Point& p )
    {
        return os << p.x << ',' << p.y;
    }
} ;

Point::Point(void)
{
    x = y = 0.0;
}
/*
Point::Point(double new_x, double new_y)
{
    x = new_x;
    y = new_y;
}
Point::Point(const Point & p)
{
    x = p.x;
    y = p.y;
}
*/
void Point::takeIn( istream& is )
{
    if( From_User ) cout << "Enter point x,y (enter comma also) :  ";

    string line;
    getline( is, line );
    stringstream iss( line );
    char comma;
    iss >> x >> comma >> y;
}

double Point::distance(const Point & other) const
{
    return sqrt( pow(x-other.x, 2.0) + pow(other.y-y, 2.0) );
}


class City
{
public:
    void takeIn_p( istream& is )
    {
        p.takeIn( is );
    }
    void takeIn_city_name( istream& is )
    {
        if( From_User ) cout << "Enter city name :  " << flush;

        getline( is, city_name );
    }

    string get_city_name() const { return city_name; }
    Point get_p() const { return p; }

    double distance( const City& other ) const
    { return p.distance(other.p); }

private:
    string city_name;
    Point p;
    friend ostream& operator << ( ostream& os, const City& c )
    {
        os << c.p;
        if( To_Screen ) os << ' ' << c.city_name;
        else os << '\n' << c.city_name;
        return os;
    }
} ;


// add here ... to compare cities ny name ...
bool cmpNames( const City& c1, const City& c2 )
{
   return c1.get_city_name() < c2.get_city_name(); // to sort on name field
}

bool cmpPoints_x( const City& c1, const City& c2)
{
    return c1.get_p().get_x() < c2.get_p().get_x();
}

bool cmpPoints_y( const City& c1, const City& c2 )
{
    return c1.get_p().get_y() < c2.get_p().get_y();
}



// utilities used here ...
// NOTE: In C/C++ char's are stored as 'int' values //
// see ...
// http://www.cplusplus.com/reference/istream/istream/get/
int takeInChar( const string& msg )
{
    cout << msg << flush;
    string reply; // taking in whole line to deal with '\n' char at end //
    getline( cin, reply );
    if( reply.size() )
        return reply[0];
    // else ...
    return 0;
}

// wrapper class for list of cites ...
class City_list
{
public:

    typedef list < City > :: const_iterator const_CL_iter;

    void takeInCity( istream& is )
    {
        City c;
        c.takeIn_p( is );
        c.takeIn_city_name( is );
        myCities.push_back( c );
    }
    void showDistance() const
    {
        City a, b;
        From_User = true;

        a.takeIn_city_name( cin );

        const_CL_iter it, ita, itb;

        ita = myCities.end(); // set default to NOT found
        for( it = myCities.begin(); it != myCities.end(); ++it )
        {
            if( it->get_city_name() == a.get_city_name() )
            {
                ita = it;
                break; // out right now since found ...
            }
        }
        if( ita == myCities.end() ) // NOT found ...
        {
            cout << a.get_city_name() << " NOT found.\n";
            return;
        }

        b.takeIn_city_name( cin );

        itb = myCities.end(); // set default to NOT found ...
        for( it = myCities.begin(); it != myCities.end(); ++it )
        {
            if( it->get_city_name() == b.get_city_name() )
            {
                itb = it;
                break; // out right now since found ...
            }
        }
        if( itb == myCities.end() ) // NOT found ...
        {
            cout << b.get_city_name() << " NOT found.\n";
            return;
        }

        cout << "\nThe distance from " << a.get_city_name()
             << " to " << b.get_city_name()
             << " is " << ita->distance( *itb ) << endl << endl;
    }

    void print() const
    {
        cout << "\nAll cites listed:\n";
        list < City > :: const_iterator it;
        for( it = myCities.begin(); it != myCities.end(); ++it )
            cout << *it << endl;
    }

    void sort()
    {
        switch( takeInChar( "Sort on 1. Name, 2. X 3. Y :  " ) )
        {
            case '1' : case 'N' : case 'n' : myCities.sort( cmpNames ); break;
            case '2' : case 'X' : case 'x' : myCities.sort( cmpPoints_x ); break;
            case '3' : case 'Y' : case 'y' : myCities.sort( cmpPoints_y ); break;
            default : cout << "\nNot implemented here ... \n";
        }
    }

    const_CL_iter begin() const { return myCities.begin() ; }
    const_CL_iter end() const { return myCities.end() ; }

    size_t size() const { return myCities.size() ; }

private:
    list < City > myCities;

    void sortNames()
    {
        myCities.sort( cmpNames );
    }
    void sortPoints_x()
    {
        myCities.sort( cmpPoints_x );
    }
    void sortPoints_y()
    {
        myCities.sort( cmpPoints_y );
    }
} ;




int main()
{
    City_list cities; // call default constructor

    ifstream fin( FNAME );
    if( fin )
    {
        while( !fin.eof() ) // load file into list till EOF
        {
            cities.takeInCity( fin );
        }
        fin.close();
        cout << "There were " << cities.size()
             << " cites loaded in from file.\n";
    }

    int reply = 0;
    do
    {
        cout << MENU << flush;
        reply = takeInChar( "\nEnter your choice (0..7) :  " );

        switch( reply )
        {
            case '1' : case 'A' : case 'a' :
                 From_User = true;
                 cities.takeInCity( cin );
                 Update_Changes = true;
                 break;
            case '2' : case 'C' : case 'c' : cities.showDistance(); break;
            case '3' : case 'P' : case 'p' : cities.print(); break;
            case '4' : case 'D' : case 'd' : cout << "\n\nNot implemented yet ...\n\n"; break;
            case '5' : case 'S' : case 's' : cities.sort(); break;

            case '7' : case 'Q' : case 'q' : cout << "\nExiting now ... \n"; break;
            default  : cout << "\nInvalid entry ... try again ...\n";
        }
    }
    while( reply != '7'  &&  reply != 'Q'  &&  reply != 'q' );

    if( Update_Changes )
    {
        // to be coded ...
        ofstream fout( FNAME );
        if ( fout )
        {
            list < City > :: const_iterator it;
            To_Screen = false;
            for( it = cities.begin() ; it != cities.end() ; ++it )
                fout << *it << endl;
            cout << cities.size() << " cites were written to file.\n";
        }
    }
}

Edited 2 Years Ago by David W: fixed typos

Hi david was wondering if you can provide some place where I can read about what code from above would go in the implementation file, main file and header file. Kind of lost on what goes where.

Thanks

Firstly ... you need to recode each class into two files:

The .h file with appropriate 'guards' (prototypes)
and ...
The .cpp file ... (include .h files needed, and any other library header definition <header_file> needed.)

Then compile main() ... as a project ... with includes (of any headers needed.)

Edited 2 Years Ago by David W: added punctuation

Is there any way I can instead of using pointers and iterators, I can use vectors for my code? How?

Yes ... you could use a vector (instead of a list) ...

But using iterators makes your code much easier to re-code (to use a vector or to use other STL containers ...)

Also ... if you are doing a lot of deletes ... using a list container makes the deletes very efficent.

This example illustrates a way to organize a project ...

Click Here

Edited 2 Years Ago by David W: changed comments

the only reason I ask is because my teacher wants us to use vectors for this project as this is what we are learning.

here is the fixed code:

#include <iostream>
#include <fstream>
#include <string>
#include <sstream> 
#include <vector> 
#include <list>
#include <cmath>
#include <cctype>

using namespace std;

#define MAX_SIZE 10  

bool From_User = false;
bool To_Screen = true;
bool Update_Changes = false;


#define FNAME "myCities.txt"



class Point
{

public:
Point();

/*
Point(double new_x, double new_y);
Point(const Point & p);
void set_x(double new_x) { x = new_x; }
void set_y(double new_y) { y = new_y; }
*/

double get_x(void) const { return x; }
double get_y(void) const { return y; }
void takeIn(istream&);
double distance(const Point & other) const;

private:
double x, y;

};

void Point :: operator<<(ostream& os) //dont need to pass it a point you will have to use a point object to call the method.
{
double x = get_x();
double y = get_y();
os << x << "," << y;
}   
Point::Point(void)
{
x = y = 0.0;
}
/*
Point::Point(double new_x, double new_y)
{
x = new_x;
y = new_y;
}
Point::Point(const Point & p)
{
x = p.x;
y = p.y;
}
*/
void Point::takeIn(istream& is)
{
if (From_User) cout << "Enter point x,y (enter comma also) :  ";
string line;
getline(is, line);
stringstream iss(line);
char comma;
iss >> x >> comma >> y;
}
double Point::distance(const Point & other) const
{
return sqrt(pow(x - other.x, 2.0) + pow(other.y - y, 2.0));
}






class City
{
public:
void takeIn_p(istream& is)
{
p.takeIn(is);
}
void takeIn_city_name(istream& is)
{
if (From_User) cout << "Enter city name :  " << flush;
getline(is, city_name);
}
string get_city_name() const { return city_name; }
Point get_p() const { return p; }
double distance(const City& other) const
{
return p.distance(other.p);
}
private:
string city_name;
Point p;
friend ostream& operator << (ostream& os, const City& c)
{
os << c.p;
if (To_Screen) os << ' ' << c.city_name;
else os << '\n' << c.city_name;
return os;
}
};

bool cmpNames(const City& c1, const City& c2)
{
return c1.get_city_name() < c2.get_city_name();
}
bool cmpPoints_x(const City& c1, const City& c2)
{
return c1.get_p().get_x() < c2.get_p().get_x();
}
bool cmpPoints_y(const City& c1, const City& c2)
{
return c1.get_p().get_y() < c2.get_p().get_y();
}






class City_list
{
public:
typedef vector < City > ::const_iterator const_CL_iter;
vector < City > myCities; 
void takeInCity(istream& is)
{
City c;
c.takeIn_p(is);
c.takeIn_city_name(is);
myCities.push_back(c);
}
void showDistance() const
{
City a, b;
From_User = true;
a.takeIn_city_name(cin);
const_CL_iter it, ita, itb;
ita = myCities.end(); // set default to NOT found
for (it = myCities.begin(); it != myCities.end(); ++it)
{
if (it->get_city_name() == a.get_city_name())
{
ita = it;
break; // out right now since found ...
}
}
if (ita == myCities.end()) // NOT found ...
{
cout << a.get_city_name() << " NOT found.\n";
return;
}
b.takeIn_city_name(cin);
itb = myCities.end(); // set default to NOT found ...
for (it = myCities.begin(); it != myCities.end(); ++it)
{
if (it->get_city_name() == b.get_city_name())
{
itb = it;
break; // out right now since found ...
}
}
if (itb == myCities.end()) // NOT found ...
{
cout << b.get_city_name() << " NOT found.\n";
return;
}
cout << "\nThe distance from " << a.get_city_name()
<< " to " << b.get_city_name()
<< " is " << ita->distance(*itb) << endl << endl;
}
void print() const
{
cout << "\nAll cites listed:\n";
vector <City> ::const_iterator it;
for (it = myCities.begin(); it != myCities.end(); ++it)  //I think this will increment before the loop runs. Meaning you will start at the
cout << *it << endl;     //1 position not the 0 position like I think you are intending to do.
}
void sort()  //I am not sure if you should inline a function with a switch statement inside. I think this falls under the same category as loops.
{
switch (takeInChar("Sort on 1. Name, 2. X 3. Y :  "))
{
case '1': case 'N': case 'n': myCities.sort(cmpNames); break;
case '2': case 'X': case 'x': myCities.sort(cmpPoints_x); break;
case '3': case 'Y': case 'y': myCities.sort(cmpPoints_y); break;
default: cout << "\nNot implemented here ... \n";
}
}
const_CL_iter begin() const { return myCities.begin(); }
const_CL_iter end() const { return myCities.end(); }
size_t size() const { return myCities.size(); }

private:

void sortNames()
{
myCities.sort(cmpNames);
}
void sortPoints_x()
{
myCities.sort(cmpPoints_x);
}
void sortPoints_y()
{
myCities.sort(cmpPoints_y);
}
};
void City_list :: operator <<(ostream& os)
{
vector<cities>::iterator pos;
pos = MyCities.begin();
while (pos != MyCities.end())
{
os << (*pos).get_city_name();  
os << (*pos).get_p();  
pos++;
}
}




int main()
{
City_list cities;
ifstream fin(FNAME);
if (fin)
{
while (!fin.eof()) // load file into list till EOF
{
cities.takeInCity(fin);
}
fin.close();
cout << "There were " << cities.size()
<< " cites loaded in from file.\n";
}
int reply = 0;
do
{
cout << MENU << flush;
reply = takeInChar("\nEnter your choice (0..7) :  ");
switch (reply)
{
case '1': case 'A': case 'a':
From_User = true;
cities.takeInCity(cin);
Update_Changes = true;
break;
case '2': case 'C': cities.showDistance(); break;
case '3': case 'P': cities.print(); break;
case '4': case 'D': cout << "\n\nNot implemented yet ...\n\n"; break;
case '5': case 'S': cities.sort(); break;
case '7': case 'Q': cout << "\nExiting now ... \n"; break;
default: cout << "\nInvalid entry ... try again ...\n";
}
} while (reply != '7'  &&  reply != 'Q'  &&  reply != 'q');
if (Update_Changes)
{
// to be coded ...
ofstream fout(FNAME);
if (fout)
{
vector < City > ::const_iterator it;
To_Screen = false;
for (it = cities.begin(); it != cities.end(); ++it)
fout << *it << endl;
cout << cities.size() << " cites were written to file.\n";
}
}
}

So I need your help with using vectors instead of iterators/pointers even though it may be efficient, I would like to learn how to do it with vectors for City_List.

Thanks

Please see my recent post in the C forum, that shows an easy way to submit code and preserve the indentation.

KEEP indentation

A copy below:

It seems you still have NOT mastered a 'basic' here at Dani... i.e. submitting code in such a way as to preserve the indentation formatting ...

Please learn how ... right away!

The way I do it ... is like this:

->select and copy your source code (as you do already)

->click on the < / > Code > icon at the top of the Dani submit window ... and that opens up a submission window

->at the top of your web browser click on Edit and then paste the code you selected and copied into that Dani code submission window

->at the bottom of the Dani code window click on the accept icon

Now you will see all your code indented (one tab in more) ... and with all the original indentations preserved.

After checking that it worked ok ... you can submit
(and edit, it again for about the next 1/2 hour if changes are needed.)

Here is a recent student request ... reworked a little ... to show the ease of moving between STL containers ... (if you use iterators ... and typedef the container used.)

This may give you some ideas HOW (easy it is) to convert from a list to a vector (using iterators) ... and then, if you wish ... you can further modify the vector program ... to use [] operator to access vector elements.

The original student demo was a sort of a list of stuct's read in from file ... (here re-worked a little, to use a 'typedef' to make the change to a different STL container a breeze) ...

// sort_listOfStructFromFile.cpp //  // 2014-02-24 //

/*

    The text file I need to read from is:

Bugs Bunny Jr. 1234 1001.01
Dr. Wiley Coyote 2345 1002.02
Taco Speedy Gonzales 3456 1003.03
Billy the Goat 4567 1004.04
Porky Pig 5678 1005.05

    Some have 2 names and some have 3 ...

*/

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <list>
#include <cctype>  // re. isdigit

using namespace std ;

#define FNAME "names.txt"


struct Person
{
    string name[3]; // ary to hold 1st, 2nd, and possible 3rd name(s)
    int id;
    float bal;
    Person() : id(0), bal(0) {}
    friend ostream& operator << ( ostream& os, const Person& p )
    {
        os << p.name[0] << ' ' << p.name[1] << ' ';
        if( p.name[2].size() ) os << p.name[2] << ' ';
        os << p.id << ' ' << p.bal;
        return os;
    }
} ;


// typedef used to EASE CHANGE TO using other STL containers
typedef list < Person > myContainer;

ostream& operator << ( ostream& os, const myContainer& mc )
{
    myContainer::const_iterator it;
    for( it = mc.begin(); it != mc.end(); ++it )
        os << *it << endl;
    return os;
}

bool myCmp( const Person& a, const Person& b )
{
    return a.name[0]+a.name[1]+a.name[2] < b.name[0]+b.name[1]+b.name[2] ;
}
// top down sorted ...
bool myCmpBal( const Person& a, const Person& b )
{
    return b.bal < a.bal;
}

template < typename T >
T convert( const string& s )
{
    istringstream iss( s );
    T tmp;
    iss >> tmp;
    return tmp;
}

void pause( const char* msg )
{
    cout << msg << flush;
    while( cin.get()  != '\n' ) ;
}


int main()
{
    ifstream fin( FNAME );
    if( fin )
    {
        myContainer mc;
        string line;

        while( getline( fin, line ) )
        {
            int i = 0, j = 0;
            Person p;
            string word;
            istringstream iss( line );
            while( iss >> word )
            {
                if( !isdigit( word[0] ) && i < 3 )  { p.name[i] = word; ++i; }
                else
                {
                    if( j == 0 ) p.id = convert < int > ( word );
                    else if( j == 1 ) p.bal = convert < float > ( word );
                    ++j;
                }
            }
            mc.push_back( p );
        }
        fin.close();

        // show list ...
        cout << "Unsorted list ...\n";
        cout << mc << endl;

        cout << "Now sorting on names ...\n";
        mc.sort( myCmp );
        cout << mc << endl;

        cout << "Now sorting on bal's ...\n";
        mc.sort( myCmpBal );
        cout << mc << endl;
    }
    else cerr << "\nThere was a problem opening file "
              << FNAME << endl;

    pause( "Press 'Enter' to continue/exit ... " );
}

Ok ... see the minimal edits ... (note the slight change in the vector sort call, that use <algorithm> library) ...

// sort_vectorOfStrictFromFile.cpp //  // 2014-03-11 //

/*

    The text file I need to read from is:

Bugs Bunny Jr. 1234 1001.01
Dr. Wiley Coyote 2345 1002.02
Taco Speedy Gonzales 3456 1003.03
Billy the Goat 4567 1004.04
Porky Pig 5678 1005.05

    Some have 2 names and some have 3 ...

*/

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <algorithm> // needed for vector sorts ... //
#include <cctype>  // re. isdigit

using namespace std ;

#define FNAME "names.txt"


struct Person
{
    string name[3]; // ary to hold 1st, 2nd, and possible 3rd name(s)
    int id;
    float bal;
    Person() : id(0), bal(0) {}
    friend ostream& operator << ( ostream& os, const Person& p )
    {
        os << p.name[0] << ' ' << p.name[1] << ' ';
        if( p.name[2].size() ) os << p.name[2] << ' ';
        os << p.id << ' ' << p.bal;
        return os;
    }
} ;


// typedef used to EASE CHANGE TO using other STL containers
typedef vector < Person > myContainer;



ostream& operator << ( ostream& os, const myContainer& mc )
{
    myContainer::const_iterator it;
    for( it = mc.begin(); it != mc.end(); ++it )
        os << *it << endl;
    return os;
}

bool myCmp( const Person& a, const Person& b )
{
    return a.name[0]+a.name[1]+a.name[2] < b.name[0]+b.name[1]+b.name[2] ;
}
// top down sorted ...
bool myCmpBal( const Person& a, const Person& b )
{
    return b.bal < a.bal;
}

template < typename T >
T convert( const string& s )
{
    istringstream iss( s );
    T tmp;
    iss >> tmp;
    return tmp;
}

void pause( const char* msg )
{
    cout << msg << flush;
    while( cin.get()  != '\n' ) ;
}


int main()
{
    ifstream fin( FNAME );
    if( fin )
    {
        myContainer mc;
        string line;

        while( getline( fin, line ) )
        {
            int i = 0, j = 0;
            Person p;
            string word;
            istringstream iss( line );
            while( iss >> word )
            {
                if( !isdigit( word[0] ) && i < 3 )  { p.name[i] = word; ++i; }
                else
                {
                    if( j == 0 ) p.id = convert < int > ( word );
                    else if( j == 1 ) p.bal = convert < float > ( word );
                    ++j;
                }
            }
            mc.push_back( p );
        }
        fin.close();

        // show list ...
        cout << "Unsorted list ...\n";
        cout << mc << endl;

        cout << "Now sorting on names ...\n";
        sort( mc.begin(), mc.end(), myCmp );
        cout << mc << endl;

        cout << "Now sorting on bal's ...\n";
        sort( mc.begin(), mc.end(),  myCmpBal );
        cout << mc << endl;
    }
    else cerr << "\nThere was a problem opening file "
              << FNAME << endl;

    pause( "Press 'Enter' to continue/exit ... " );
}

Edited 2 Years Ago by David W: fixed spelling ... added comments

Now re. your distance between two cities problem, you like to see the list and vector examples here ...

CitiesListType_sort3.cpp

CitiesVectorType_sort3.cpp

list or vector type

Edited 2 Years Ago by David W: fixed spelling

Hi, again, so I almost completed my code. Need some help with the Remove a City portion of the code.

Also I need help with implementing XML format.

*Add (Level 3) more if your 'labeled' format is XML (or at least XML-like). XML uses a system of tags similar to HTML. The example file from the related lab might look like this as XML:

<student>
<name>Jason James</name>
<id>123456</id>
<gpa>9.2</gpa>
<grade>B</grade>
</student>
<student>
<name>Tammy James</name>
<gpa>11.2</gpa>
<grade>A</grade>
<id>123457</id>
</student>
<student>
<name>Henry Ramirez</name>
<gpa>12.3</gpa>
<id>111888</id>
<major>ChE</major>
<class>soph</class>
</student>
<student>
<id>788531</id>
<name>Suzie Shah</name>
<grade>Q</grade>
</student>

I have attached my code so far.

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include <list>
#include <cmath>
#include <cctype>

using namespace std;

#define MAX_SIZE 10  

bool From_User = false;
bool To_Screen = true;
bool Update_Changes = false;



class Point
{

public:
    Point();

    /*
    Point(double new_x, double new_y);
    Point(const Point & p);
    void set_x(double new_x) { x = new_x; }
    void set_y(double new_y) { y = new_y; }
    */

    double get_x(void) const { return x; }
    double get_y(void) const { return y; }
    void takeIn(istream&);
    double distance(const Point & other) const;

private:
    double x, y;

};

ostream& operator<<(ostream& os, const Point & p) 
{
    double x = p.get_x();
    double y = p.get_y();
    return os << x << "," << y;
}

Point::Point(void) : x(0.0), y(0.0)
{
//    x = y = 0.0;
}

/*
Point::Point(double new_x, double new_y)
{
    x = new_x;
    y = new_y;
}

Point::Point(const Point & p)
{
    x = p.x;
    y = p.y;
}
*/

void Point::takeIn(istream& is)
{
    if (From_User) cout << "Enter point x,y (enter comma also) :  ";
    string line;
    getline(is, line);
    stringstream iss(line);
    char comma;
    iss >> x >> comma >> y;
}

double Point::distance(const Point & other) const
{
    return sqrt(pow(x - other.x, 2.0) + pow(other.y - y, 2.0));
}




class City
{

    public:
    City() : city_name(), p() {}

    void takeIn_p(istream& is)
{
    p.takeIn(is);
}

void takeIn_city_name(istream& is)
{
    if (From_User) cout << "Enter city name :  " << flush;
    getline(is, city_name);
}

string get_city_name() const { return city_name; }

Point get_p() const { return p; }

double distance(const City& other) const
{
    return p.distance(other.p);
}

private:
    string city_name;
    Point p;
    friend ostream& operator << (ostream& os, const City& c)
    {

    os << c.p;
    if (To_Screen) os << ' ' << c.city_name;
    else os << '\n' << c.city_name;
    return os;

    }
};

short cmpNames(const City& c1, const City& c2)
{
    return c1.get_city_name().compare(c2.get_city_name());
}

double cmpPoints_x(const City& c1, const City& c2)
{
    return c1.get_p().get_x() - c2.get_p().get_x();
}

double cmpPoints_y(const City& c1, const City& c2)
{
    return c1.get_p().get_y() - c2.get_p().get_y();
}


int takeInChar(const string&  msg)
{
    cout << msg << flush;
    string reply;
    getline(cin, reply);
    if(reply.size())
        return reply[0];
    else
        return 0;
}



class City_list
{
    public:

        City_list() : myCities() {}   
        typedef vector < City > ::const_iterator const_CL_iter;
        vector < City > myCities;


void takeInCity(istream& is)
{
    City c;
    c.takeIn_p(is);
    c.takeIn_city_name(is);
    myCities.push_back(c);
}

void showDistance() const
{
    City a, b;
    From_User = true;
    a.takeIn_city_name(cin);
    const_CL_iter it, ita, itb;
    ita = myCities.end(); 
        for (it = myCities.begin(); it != myCities.end(); ++it)
        {
            if (it->get_city_name() == a.get_city_name())
            {
                ita = it;

            }
        }

if (ita == myCities.end())
{
    cout << a.get_city_name() << " NOT found.\n";
    return;
}

b.takeIn_city_name(cin);
itb = myCities.end(); 

for (it = myCities.begin(); it != myCities.end(); ++it)
{
    if (it->get_city_name() == b.get_city_name())
{
    itb = it;


}
}

void Remove()
{

if (itb == myCities.end()) 
{
    cout << b.get_city_name() << " NOT found.\n";
    return;
}

cout << "\nThe distance from " << a.get_city_name() << " to " << b.get_city_name() << " is " << ita->distance(*itb) << endl << endl;
}


void print() const
{
    cout << "\nAll cites listed:\n";
    vector <City> ::const_iterator it;
    for (it = myCities.begin(); it != myCities.end(); ++it)  
    cout << *it << endl; 
}

void sort()  
{

switch (takeInChar("Sort on 1. Name, 2. X 3. Y :  "))
{
    case '1': case 'N': case 'n': sortNames(); break;
    case '2': case 'X': case 'x': sortPoints_x(); break;
    case '3': case 'Y': case 'y': sortPoints_y(); break;
    default: cout << "\nNot implemented here ... \n";
}
}

const_CL_iter begin() const { return myCities.begin(); }
const_CL_iter end() const { return myCities.end(); }
size_t size() const { return myCities.size(); }

private:

void sortNames();
void sortPoints_x();
void sortPoints_y();

};
ostream& operator <<(ostream& os, const City_list & cl)
{
    vector<City>::const_iterator pos;
    pos = cl.myCities.begin();

    while (pos != cl.myCities.end())
    {
        os << pos->get_city_name();  
        os << pos->get_p();  
        pos++;
    }
    return os;
}


inline void swap(vector<City>::iterator a, vector<City>::iterator b)
{
    City c = *a;
    *a = *b;
    *b = c;
    return;
}



int main()
{
    City_list cities;
    int reply = 0;
    bool quitting = false;


do
{
    cout << "Please choose from the following options below:" << endl;
    cout << "1.  Add a city \n 2.  Print all cities \n 3.  calculate Distance between cities \n 4.  Remove a city \n 5.  Sort (by names or points) \n 6.  Quit";
    reply = takeInChar("\nEnter your choice (0..7) :  ");
    //cin.ignore(INT_MAX, '\n');


switch(reply)
{
    case '1': case 'A':
    From_User = true;
    cities.takeInCity(cin);
    Update_Changes = true;
    break;

    case '2': case 'P': cities.showDistance(); break;

    case '3': case 'D': cities.print(); break;

    case '4': case 'R': cout << "\n\nNot implemented yet ...\n\n"; break;

    case '5': case 'S': cities.sort(); break;

    case '6': case 'Q': quitting = true; cout << "\nExiting now ... \n"; break;

    default: cout << "\nInvalid entry ... try again ...\n";
}

} while ( ! quitting );
return 0;

}

void City_list::sortNames()
{
    vector<City>::size_type c;
    bool no_swaps;
    vector<City>::iterator p;
    no_swaps = false;
    c = 0;
    while (c != myCities.size()-1 && ! no_swaps)
    {
        no_swaps = true;
        for (p = myCities.begin(); p+1+1 != myCities.end(); p++)
        {

            if (p->get_city_name() > (p+1)->get_city_name())  //(cmpNames(*p,*(p+1)) > 0)
            {
                swap(p, p+1);
                no_swaps = false;
            }
        }
        c++;
    }
    return;
}

void City_list::sortPoints_x()
{
    vector<City>::size_type c;
    bool no_swaps;
    vector<City>::iterator p;
    no_swaps = false;
    c = 0;
    while (c != myCities.size()-1 && ! no_swaps)
    {
        no_swaps = true;
        for (p = myCities.begin(); p+1+1 != myCities.end(); p++)
        {

            if (p->get_p().get_x() > (p+1)->get_p().get_x())
            {
                swap(p, p+1);
                no_swaps = false;
            }
        }
        c++;
    }
    return;
}

void City_list::sortPoints_y()
{
    vector<City>::size_type c;
    bool no_swaps;
    vector<City>::iterator p;
    no_swaps = false;
    c = 0;
    while (c != myCities.size()-1 && ! no_swaps)
    {
        no_swaps = true;
        for (p = myCities.begin(); p+1+1 != myCities.end(); p++)
        {

            if (p->get_p().get_y() > (p+1)->get_p().get_y())
            {
                swap(p, p+1);
                no_swaps = false;
            }
        }
        c++;
    }
    return;
}

Ok ...

I would recommend a few revisions ...

If you were to use function pointers, (for the compare functions in your 3 different bubble sorts), you could vastly reduce and re-use the bubble sort code.

    void City_list::sortBy( bool (*cmp) (const City& a, const City& b) )
    {
        bubble_sort( cmp );
    }

Take a look ...

typedef vector < City > ::const_iterator const_iter;
typedef vector < City > ::iterator iter;

class City_list
{
public:

    City_list() : myCities() {}

    void takeInCity(istream& is)
    {
        City c;
        c.takeIn_p(is);
        c.takeIn_city_name(is);
        myCities.push_back(c);
    }

    void showDistance() const
    {
        City a, b;
        From_User = true;
        a.takeIn_city_name(cin);
        const_iter it, ita, itb;
        ita = myCities.end();
        for (it = myCities.begin(); it != myCities.end(); ++it)
        {
            if (it->get_city_name() == a.get_city_name())
            {
                ita = it;
            }
        }

        if (ita == myCities.end())
        {
            cout << a.get_city_name() << " NOT found.\n";
            return;
        }

        b.takeIn_city_name(cin);
        itb = myCities.end();

        for (it = myCities.begin(); it != myCities.end(); ++it)
        {
            if (it->get_city_name() == b.get_city_name())
            {
                itb = it;
            }
        }

        if (itb == myCities.end())
        {
            cout << b.get_city_name() << " NOT found.\n";
            return;
        }

        cout << "\nThe distance from " << a.get_city_name() 
             << " to " << b.get_city_name() 
             << " is " << ita->distance(*itb) 
             << endl << endl;
    }


    void print() const
    {
        cout << "\nAll cites listed:\n";
        const_iter it; // using typedef //
        for (it = myCities.begin(); it != myCities.end(); ++it)
            cout << *it << endl;
    }

    void sort()
    {
        switch ( takeInChar("Sort on 1. Name, 2. X 3. Y :  ") )
        {
        case '1':
        case 'N':
        case 'n':
            sortBy( cmpNames );
            break;
        case '2':
        case 'X':
        case 'x':
            sortBy( cmpPoints_x );
            break;
        case '3':
        case 'Y':
        case 'y':
            sortBy( cmpPoints_y );
            break;
        default:
            cout << "\nNot implemented here ... \n";
        }
    }

    const_iter begin() const 
    {
        return myCities.begin();
    }
    const_iter end() const 
    {
        return myCities.end();
    }
    size_t size() const 
    {
        return myCities.size();
    }

    bool erase()
    {
        cout << "Enter city name of city to erase: " << flush;
        string name;
        getline( cin, name );
        iter it;
        for( it = myCities.begin(); it != myCities.end(); ++it )
        {
            if( it->get_city_name() == name )
            {
                myCities.erase( it );
                return true;
            }
        }
        // else ... if reach here ...
        return false;       
    }

private:

    vector < City > myCities;

    void bubble_sort( bool (*cmp )(const City& a, const City& b) ) 
    {
        size_t size = myCities.size();
        bool swap;
        do
        {
            swap = false;
            for( size_t i = 1; i < size; ++i )
            {
                //if( myCities[i-1] > myCities[i] ) // swap //
                if( cmp(myCities[i-1], myCities[i]) )// swap //
                {
                    City tmp = myCities[i-1];
                    myCities[i-1] = myCities[i];
                    myCities[i] = tmp;
                    swap = true;
                }
            }
            --size;
        }
        while( swap );
    }

    void sortBy( bool (*)( const City&, const City& ) );

    friend ostream& operator << ( ostream&, const City_list& );
} ;



ostream& operator << ( ostream& os, const City_list & cl )
{

    const_iter pos = cl.myCities.begin();

    while ( pos != cl.myCities.end() )
    {
        os << pos->get_city_name();
        os << pos->get_p();
        pos++;
    }
    return os;
}


void City_list::sortBy( bool (*cmp) (const City& a, const City& b) )
{
    bubble_sort( cmp );
}

And see example here ...

example bubble sort with function pointers

Edited 2 Years Ago by David W: changed code/comments

So I need some help with getting the File.

Add (Level 2.5) to let them both load and save city information from/to files. You can decide the format of the city information file. Note: you'll have to add a save option to the menu (or a question under 'print') and you'll have to ask if entry should come from the keyboard or a file. (Hint: You shouldn't need a new function to handle loading from a file — your current entry function should work fine with a little tweaking of the argument(s).)

I can't use global variabe like you showed me before. Any help would be great.

Thanks

Maybe ...

You could 'wrap' the 'flag' variables in their own namespace ...

namespace MyFlags
{
    bool from_User = false;
    bool to_Screen = true;
    bool update_Changes = false;
}

Edited 2 Years Ago by David W

This article has been dead for over six months. Start a new discussion instead.