简体   繁体   中英

C++ classes - the most frequent object in an array

I have implemented 3 classes: Location, Address, Route. The Address class contains a Location object, and the Route class contains an array of Address objects. In the main function I've created an array of Route objects. What I want to do is to find the most frequent 5 addresses appearing in the Route array. I think I should use a frequency vector, but I'm not sure how implementation should be done. I would be very grateful if someone could give me a solution Below is the code:

#include <iostream>
#include <string.h>
using namespace std;

class Location
{
    double lat, lon;

    char *emi;
public:
    Location(double = 0, double = 0, char* = NULL);
    virtual ~Location();
    Location& operator= (const Location &);
    Location(const Location&);
    friend ostream& operator<< (ostream&, const Location &);
    void operator! ();
    void print1() const;
    char* getem()
    {
        return emi;
    }
protected:
private:
};
Location::Location(double lat, double lon, char *emi)
{
    this->lat = lat;
    this->lon = lon;
    if (emi != NULL)
    {
        this->emi = new char[strlen(emi) + 1];
        strcpy(this->emi, emi);
    }

}
Location&Location::operator= (const Location &l)
{
    if (this != &l)
    {
        this->lon = l.lon;
        this->lat = l.lat;
        if (l.emi != NULL)
        {
            this->emi = new char[strlen(l.emi) + 1];
            strcpy(this->emi, l.emi);
        }
    }
    return *this;
}
Location::Location(const Location &la)
{
    lat = la.lat;
    lon = la.lon;
    if (la.emi != NULL)
    {
        emi = new char[strlen(la.emi) + 1];
        strcpy(emi, la.emi);
    }
}
Location::~Location()
{
    if (emi != NULL)
        delete[]emi;
}
void Location::operator! ()
{
    if (!(strcmp(this->emi, "north")))
    {
        delete[]this->emi;
        this->emi = new char[strlen("south") + 1];
        strcpy(this->emi, "south");
    }
    else
    {
        delete[]this->emi;
        this->emi = new char[strlen("north") + 1];
        strcpy(this->emi, "north");
    }
}
void Location::print1() const
{
    cout << "lon: " << this->lon << endl;
    cout << "lat: " << this->lat << endl;
    cout << "emi: " << this->emi << endl;
    cout << endl;
}

ostream& operator<< (ostream &os, const Location &l)
{
    os << "lon: " << l.lon << endl;
    os << "lat: " << l.lat << endl;
    os << "emi: " << l.emi << endl;
    os << endl;
    return os;
}
class Address
{

    char *desc;
    Location l;
    char *country;
    public`:
        Address(char *, const Location &, char *);
    virtual ~Address();
    friend ostream& operator<< (ostream&, const Address &);
    void print();
    bool em();
    char *getDesc()
    {
        return desc;
    };

protected:
private:
};
Address::Address(char *desc, const Location &loc1, char *country)
{
    if (desc != NULL)
    {
        this->desc = new char[strlen(desc) + 1];
        strcpy(this->desc, desc);
    }
    if (country != NULL)
    {
        this->country = new char[strlen(country) + 1];
        strcpy(this->country, country);
    }
    this->l = loc1;
}
Address::~Address()
{
    if (country != NULL)
        delete[]country;
    if (desc != NULL)
        delete[]desc;
}
ostream& operator<< (ostream &os, const Address&a)
{
    os << "desc: " << a.desc << endl;
    os << "country: " << a.country << endl;
    a.l.print1();
    return os;
}
void Address::print()
{
    cout << "desc: " << desc << endl;
    cout << "country: " << country << endl;
    this->l.print1();
}
bool Address::em()
{
    return (!(strcmp(l.getem(), "south")));
}

class Route
{
    Address **r;
    int dim_max;
    int dim_curr;
public:
    Route(int = 9);
    void print2();
    void add(char *, double, double, char *, char*);
    virtual ~Route();
    int lRoute();

protected:
private:
};
Route::Route(int d)
{
    this->dim_max = d;
    dim_curr = 0;
    r = new Address *[dim_max];
}
void Route::add(char *d, double l, double l2, char *em, char *t)
{
    r[dim_curr] = new Address(d, Location(l, l2, em), t);
    dim_curr++;
}
Route::~Route()
{
    for (int i = 0; i < dim_curr; i++)
        delete r[i];
    delete[]r;
}
void Route::print2()
{
    int i;
    for (i = 0; i < dim_curr; i++)
        r[i]->print();
}
int Route::lRoute()
{
    return dim_curr;
}

int main()
{

    Route **sirR;
    sirR = new Route *[5];
    sirR[0] = new Route(3);
    sirR[1] = new Route(3);
    sirR[2] = new Route(2);
    sirR[3] = new Route(4);
    sirR[4] = new Route(2);
    sirR[0]->add(" Address 1", 23.43, 21.43, "south", "country1");
    sirR[0]->add("Address 2", 23.431, 21.443, "south", "country2");
    sirR[0]->add("Address 3", 43.23, 13.42, "north", "country3");
    sirR[1]->add("Address 4", 13.431, 123.432, "south", "country4");
    sirR[1]->add("Address 5", 324.123, 43.13, "north", "country5");
    sirR[1]->add("Address 6", 43.123, 43.12, "south", "country 6");
    sirR[2]->add("Address 7", 23.31, 321.32, "north", "country 7");
    sirR[2]->add("Address 8", 43.12, 43.12, "south", "country 8");
    sirR[3]->add("Address 9", 23.42, 64.21, "north", "country 9");
    sirR[3]->add("Address 10", 64.23, 75.21, "south", "country 10");
    sirR[3]->add("Address 11", 75.13, 75.124, "north", "country 11");
    sirR[3]->add("Address 12", 75.12, 54.342, "south", "country 12");
    sirR[4]->add("Address 13", 543.245, 34.24, "north", "country 13");
    sirR[4]->add("Address 14", 54.123, 84.12, "south", "country 14");
    sirR[4]->print2();
    return 0;
}

PS: I don't use strings because the teacher told me to use char.

I'll show you how to use a standard map to get the address counts. You could then find the top five of these. It will pull out some propblems with the design and ways to strip back the code.

Consider using const char * in the constructors of your objects, rather than just char * . In fact, consider asking why you were told to use char * rather than const char * - make sure you know the difference first though.

Also,

Route **sirR;
sirR = new Route *[5];
sirR = new Route *[5];
sirR[0] = new Route(3);
sirR[1] = new Route(3);
sirR[2] = new Route(2);
sirR[3] = new Route(4);
sirR[4] = new Route(2);

could just be

Route sirR[5];

end use

sirR[0].add(" Address 1", 23.43, 21.43, "south", "country1");

instead of

sirR[0]->add(" Address 1", 23.43, 21.43, "south", "country1");

and so on - as it stands you don't delete the array you new ed.


As it stands the only way to get information back out of your route array is by printing to standard out.

You need to give some thought to what makes addresses equal. The class needs an equals operator, or other way to compare addresses.

In order to use std::map we need to define a less than operator. This will get you started, if you add it inside Address :

bool operator < (const Address & lhs) const
{
    return strcmp(desc, lhs.desc) < 0;
}

It's not using all the fields - you can think how to extend it.

If we now include the map header

#include <map>

we can use a map. This isn't the best or only way to do this, but it will show the problems we have trying to find the addresses out.

Your addresses get made in the routes, when you call add , so we can track them there if all the routes can see the same map.

class Route
{
    static std::map<Address, size_t> frequency; //<- keep track
    Address **r;
    int dim_max;
    int dim_curr;
public:
    Route(int = 9);
    void print2();
    void add(const char *, double, double, const char *, const char*);
    virtual ~Route();
    int lRoute();
    std::map<Address, size_t> frequencies() //<- so we can find use these in main
    {
        return frequency;
    }

protected:
private:
};
std::map<Address, size_t> Route::frequency;//<-- define the static data member

This is a hack to work round not being able to query the addresses after they go in a route.

Now, using this hack, the add function can populate the map:

void Route::add(const char *d, double l, double l2, const char *em, const char *t)
{
    r[dim_curr] = new Address(d, Location(l, l2, em), t);
    ++frequency[*r[dim_curr]]; //count addresses
    dim_curr++;
}

Whenever you make an address it gets counted now.

At the end of main, before you return 0, you can add code to see all the counts:

for(auto & items : sirR[0].frequencies())
{
    std::cout << items.first << ' ' << items.second << '\n';
}

For your data they are all unqiue. For other data you could then count the top few. I haven't explicitly done this for you.

As your code stands, you can't see the addresses in the routes. You can only print them. You need to change your code around to be able to access these.

If you are avoiding standard data structures and making your own as a learning exercise, you could have an array of names and a matching array of counts, and sweep through the names each time you add a new address and increment the matching count.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM