我遇到了这段代码的问题。这是我为旅行商问题写的遗传算法。然而程序崩溃并且没有完成,在调试器中挖掘我发现了我认为错误但是我不确定它在哪里发生。我将发布整个程序,因为我已经倾注了代码,我无法查明错误。感谢。
#include<vector>
#include<algorithm>
#include<time.h>
#include<cmath>
#include<string>
#include<iterator>
const int numcities = 15;
using namespace std;
class City{
public:
int x,y,numcity;
City();
~City();
void setxcoord(int);
void setycoord(int);
int getxcoord();
int getycoord();
void setcitynum(int);
int getcitynum();
};
City::City(){
x = -1;
y = -1;
}
City::~City(){
}
void City::setxcoord(int xcoord){
x = xcoord;
}
void City::setycoord(int ycoord){
y = ycoord;
}
int City::getxcoord(){
return x;
}
int City::getycoord(){
return y;
}
void City::setcitynum(int newcitynum){
numcity = newcitynum;
}
int City::getcitynum(){
return numcity;
}
class resultscontainer{
public:
vector<City> tour;
int i;
vector<City>::iterator it;
resultscontainer();
~resultscontainer();
City findcity(int);
void addcity(City);
int toursize();
};
resultscontainer::resultscontainer(){
i = 0;
}
resultscontainer::~resultscontainer(){};
void resultscontainer::addcity(City newcity){
it = tour.begin() + i;
tour.insert(it,newcity);
i++;
}
City resultscontainer::findcity(int index){
City temp = tour.at(index);
return temp;
}
int resultscontainer::toursize(){
return tour.capacity();
}
class newtour{
public:
vector<City> candidate;
vector<City>::iterator it;
double fitness,distance;
string citylist;
newtour();
~newtour();
void makeindividual(resultscontainer);
double getfitness();
double getdistance();
bool fulltour();
void displaytour();
void setuniquepos(int, City);
City getcityatpos(int);
bool isEmpty(int);
};
newtour::newtour(){
City initvalue;
for(int i =0; i < numcities ; i++){
it = candidate.begin() + i;
candidate.insert(it, initvalue);
}
}
newtour::~newtour(){};
void newtour::makeindividual(resultscontainer citylist){
for (int i = 0; i < numcities; i++){
it = candidate.begin() + i;
candidate.insert(it, citylist.findcity(i));
}
random_shuffle(candidate.begin(), candidate.end());
}
double newtour::getfitness(){
fitness = 1/getdistance();
return fitness;
}
double newtour::getdistance(){
for(int i = 0; i+1 < candidate.capacity(); i++){
City currentcity = candidate.at(i);
City destinationcity = candidate.at(i+1);
distance += sqrt(pow(currentcity.x - destinationcity.x, 2) + pow(currentcity.y - destinationcity.y, 2));
}
return distance;
}
bool newtour::fulltour(){
if(candidate.capacity() == numcities) return true;
else return false;
}
void newtour::displaytour(){
citylist = "Tour is: ";
for(int i = 0; i < candidate.capacity(); i++)citylist += candidate.at(i).getcitynum() + ", ";
}
void newtour::setuniquepos(int i, City newcity){
it = candidate.begin()+i;
candidate.insert(it, newcity);
}
City newtour::getcityatpos(int i){
return candidate.at(i);
}
bool newtour::isEmpty(int i){
if(candidate.at(i).getcitynum() == NULL) return true;
else return false;
}
class population{
public:
vector< newtour > totalpop;
int index,maxpop;
vector< newtour >::iterator it;
population();
~population();
void addtour(newtour);
newtour findtour(int);
newtour findfittest();
int populationsize();
};
population::population(){
index = 0;
maxpop = 10;
}
population::~population(){}
void population::addtour(newtour candidate){
it = totalpop.begin() + index;
totalpop.insert(it, candidate);
index++;
}
newtour population::findtour(int i){
return totalpop.at(i);
}
newtour population::findfittest(){
newtour fittesttour;
for(int i = 0; i+1 < totalpop.capacity(); i++){
newtour currenttour = totalpop.at(i);
newtour nexttour = totalpop.at(i+1);
if(currenttour.getfitness() <= nexttour.getfitness()) fittesttour = nexttour;
}
return fittesttour;
}
int population::populationsize(){
return totalpop.capacity();
}
上面是头文件,下面是实现。
#include"City.h"
#include<vector>
#include<algorithm>
#include<time.h>
#include<cmath>
#include<string>
#include<cstdlib>
#include<iostream>
using namespace std;
const double mutationrate = .1;
const int bracketsize = 5;
newtour bracketselection(population pop){
population temppop;
for(int i = 0; i < bracketsize; i++){
int randomnum = (int) (rand() * pop.populationsize());
temppop.addtour(pop.findtour(randomnum));
}
newtour best = temppop.findfittest();
return best;
}
newtour crossover(newtour mom, newtour dad){
newtour child;
bool inside = false;
int beginning, end;
beginning = (int) (rand() * mom.distance);
end = (int) (rand() * mom.distance);
for(int i = 0; i < numcities; i++){
if(beginning < end && i < end && i >beginning)child.setuniquepos(i, mom.getcityatpos(i));
else if (beginning > end){
if (!(i>end && i < beginning)){
child.setuniquepos(i, mom.getcityatpos(i));
}
}
}
for(int j = 0; j < numcities; j++){
for(int k = 0; k <numcities; k++)if(child.getcityatpos(k).getcitynum() == dad.getcityatpos(j).getcitynum())inside = true;
if(!inside)for(int l = 0; l < numcities; l++)if(child.getcityatpos(l).getcitynum() == NULL){
child.setuniquepos(l,dad.getcityatpos(l));
break;
}
}
return child;
}
void mutation(newtour subject){
for(int i=0; i < numcities; i++){
if(rand()* 5 / rand() < mutationrate){
int j = (int)(bracketsize *8 %5 * rand());
City randcity1 = subject.getcityatpos(i);
City randcity2 = subject.getcityatpos(j);
subject.setuniquepos(j, randcity1);
subject.setuniquepos(i, randcity2);
}
}
}
population evolve(population totalpop){
population nextgen;
nextgen.addtour(totalpop.findfittest());
for(int i = 1; i < nextgen.maxpop; i++){
newtour mom,dad,child;
mom = bracketselection(totalpop);
dad = bracketselection(totalpop);
child = crossover(mom,dad);
nextgen.addtour(child);
}
for (int i =1; i < nextgen.maxpop; i++)mutation(nextgen.findtour(i));
return nextgen;
}
void main(){
City city1,city2,city3,city4,city5,city6,city7,city8,city9,city10,city11,city12,city13,city14,city15;
population thepop;
resultscontainer cities;
city1.setxcoord(5);
city1.setycoord(2);
city1.setcitynum(1);
city2.setxcoord(16);
city2.setycoord(3);
city2.setcitynum(2);
city3.setxcoord(13);
city3.setycoord(5);
city3.setcitynum(3);
city4.setxcoord(15);
city4.setycoord(9);
city4.setcitynum(4);
city5.setxcoord(10);
city5.setycoord(10);
city5.setcitynum(5);
city6.setxcoord(4);
city6.setycoord(9);
city6.setcitynum(6);
city7.setxcoord(6);
city7.setycoord(12);
city7.setcitynum(7);
city8.setxcoord(12);
city8.setycoord(13);
city8.setcitynum(8);
city9.setxcoord(9);
city9.setycoord(14);
city9.setcitynum(9);
city10.setxcoord(16);
city10.setycoord(20);
city10.setcitynum(10);
city11.setxcoord(18);
city11.setycoord(18);
city11.setcitynum(11);
city12.setxcoord(2);
city12.setycoord(5);
city12.setcitynum(12);
city13.setxcoord(7);
city13.setycoord(5);
city13.setcitynum(13);
city14.setxcoord(2);
city14.setycoord(16);
city14.setcitynum(14);
city15.setxcoord(11);
city15.setycoord(18);
city15.setcitynum(15);
cities.addcity(city1);
cities.addcity(city2);
cities.addcity(city3);
cities.addcity(city4);
cities.addcity(city5);
cities.addcity(city6);
cities.addcity(city7);
cities.addcity(city8);
cities.addcity(city9);
cities.addcity(city10);
cities.addcity(city11);
cities.addcity(city12);
cities.addcity(city13);
cities.addcity(city14);
cities.addcity(city15);
thepop = evolve(thepop);
for (int i = 0; i < 50 ; i++){
thepop = evolve(thepop);
}
newtour bestroute = thepop.findfittest();
cout << "The fittest route had a fitness of: " <<bestroute.fitness<< endl;
cout << "The algorithm determined that the best route is :" << endl;
bestroute.displaytour();
cout << "With a total distance of: " << bestroute.getdistance();
}
答案 0 :(得分:2)
我相信你正在使用rand()。 例如:
int randomnum = (int) (rand() * pop.populationsize());
temppop.addtour(pop.findtour(randomnum));
randomnum将是完全无意义的,并且最有可能访问pop中的界限。
我想你想要像(int)(rand() % pop.populationsize())
还要学习VS中的调试(只需查看调用堆栈,单步执行代码并查看变量值) 也可以在add ...()函数中使用push_back而不是insert。
答案 1 :(得分:1)
您应该使用size()
来获取容器中的元素数量,而不是capacity()
。正如我在上面的评论中提到的那样,循环也是如此,但population::populationsize()
也是如此。
您拨打rand()
并将其乘以人口规模。我认为你期望rand()
将浮点值从0返回到1,但它实际上返回一个从0到RAND_MAX的整数(至少是32767)。而不是将它乘以人口规模,你应该按人口规模对其进行模数计算:
int randomnum = rand() % pop.populationsize();
模数减零会使程序崩溃,就像除以零一样,因此在生成上面#2中的随机数之前,需要测试pop.populationsize()
是否为非。
在newtour::displaytour()
中,您尝试将字符串与整数candidate.at(i).getcitynum()
连接起来。这不起作用;你需要先将整数转换为字符串。我建议使用ostringstream
main()
必须返回int
。 MSVC可能会允许您使用void main()
,但它不符合标准且GCC拒绝接受它。
通过这些修复程序,您的程序将提供以下输出:
最适合的路线的适应度为:5.50124e + 306
算法确定最佳路线是:
总距离:1.81777e-307
对我而言看起来并不合适,但至少它会编译。
答案 2 :(得分:0)
你问题的很大一部分似乎是对矢量如何运作的误解 - 或者只是缺乏理解。您似乎也喜欢将矢量迭代器存储为类成员而不是使用局部变量的危险做法。
让我们快速浏览一下你如何使用vector:
#include <iostream>
#include <string>
#include <vector>
struct Address
{
int m_doorNo;
std::string m_street;
Address() : m_doorNo(-1), m_street("Limbo")
{
std::cout << "Address() default ctor called\n";
}
Address(int doorNo, const std::string& street)
: m_doorNo(doorNo), m_street(street)
{}
};
// So we can << an Address object.
static std::ostream& operator << (std::ostream& os, const Address& address)
{
os << address.m_doorNo << " " << address.m_street.c_str();
return os;
}
// Give our *usage* of a vector a friendly name.
typedef std::vector<Address> AddressBook;
int main()
{
AddressBook book;
if (book.empty())
std::cout << "book starts empty, it has size() of " << book.size() << '\n';
book.push_back(Address(70, "1st Street"));
std::cout << "First address added, book.size = " << book.size() << '\n';
book.push_back(Address(123, "Hope Avenue"));
std::cout << "Second address added, book.size = " << book.size() << '\n';
std::cout << "address[0] is: " << book[0] << '\n';
std::cout << "address.at(1) is: " << book.at(1) << '\n';
std::cout << "*address.begin() is: " << *(book.begin()) << '\n';
std::cout << "address.front() is: " << book.front() << '\n';
std::cout << "address.back() is: " << book.back() << '\n';
// couple more addresses.
book.insert(book.begin(), Address(3, "Disco Alley"));
book.insert(book.begin() + 1, Address(5, "Mortimer Lane"));
// overshoot, place an extra address at the end of the vector.
book.insert(book.end(), Address(999, "Hellfire Drive"));
// oops, lets erase that.
book.pop_back();
std::cout << "Done shuffling. Size = " << book.size() << " while capacity = " << book.capacity() << '\n';
const size_t numAddrs = book.size();
for (size_t i = 0; i < numAddrs; ++i) {
std::cout << i << ": " << book[i] << '\n';
}
// and lastly, lets use a reverse iterator.
std::cout << "backwards:" << '\n';
// instead of std::vector<Address>::iterator etc, we can say AddressBook::iterator
for (AddressBook::reverse_iterator it = book.rbegin(); it != book.rend(); ++it) {
std::cout << *it << '\n';
}
// 'reserve' adjusts the capacity, it tells the vector to go ahead and
// allocate space for N entries, but don't make them available yet.
book.reserve(999);
// 'resize' changes the size, if the new size is smaller than the capacity,
// it forces a call to reserve to allocate more memory.
// after that, it goes ahead and grows the array storage by default-
// initializing any new entries.
book.resize(9);
std::cout << "book.size = " << book.size() << " but cap = " << book.capacity() << '\n';
// at this point, it is safe to say:
book[6].m_doorNo = 555;
book[7].m_street = "Nowhere";
book[8] = Address(10101, "Binary Bend");
for (auto it = book.begin(); it != book.end(); ++it) {
std::cout << *it << '\n';
}
return 0;
}