原创:TSP问题解决方案-----禁忌搜索算法C实现
本文着重于算法的实现,对于理论部分可自行查看有关资料可以简略参考该博文:http://blog.csdn.net/u013007900/article/details/50379135
本文代码部分基于C实现,源码如下:
/*****************************************************************************
** Copyright: NEW NEU laboratory
** File name: CTSP
** Description:禁忌搜索算法解决TSP问题
** Author: 1702-GCJ
** Version: 1.1
** Date: 2017/10/3
** History: 无
** Modification: IsFindTabu(Queue * Q,const Tabu *item)
*****************************************************************************/
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
#include "time.h"
#define CityNum 31 //城市的数量
#define TabuLength 21 //禁忌表长度(根号下的 种类)
#define Neighbor 400 //邻居个数
#define MaxNG 400 //迭代次数
; //当前迭代次数
; //渴望水平 (即最短距离)
typedef int ElementType;
ElementType **Distance; //存储各个城市之间的距离矩阵的指针 数据都是取整的
/***************************************************************************************读取数据区******************************************/
/*************************************************
**Function: MemBlockCity
**Description: 申请存储城市距离空间
**Calls: 无
**Called By: ReadDataTxt()
**Input: 无
**Output: 无
**Return: 指向存储城市距离空间的指针
**Others: 用完需要释放掉相应内存
*************************************************/
ElementType ** MemBlockCity();
/*************************************************
**Function: PrintCityDistance
**Description: 显示Distance信息
**Calls: 无
**Called By: main()
**Input: Distance 全局变量的指针
**Output: 无
**Return: void
**Others: 无
*************************************************/
void PrintCityDistance( ElementType ** distance);
/*************************************************
**Function: ReadDataTxt
**Description: 从txt文档中读取数据
**Calls: MemBlockCity()
**Called By: main
**Input: 无
**Output: 无
**Return: void
**Others: 里面直接用的全局变量 指针Distance
*************************************************/
void ReadDataTxt();
/*************************************************
**Function: WriteDataTxt
**Description: 将Distance全局数组数据写到txt文档中去
**Calls: 无
**Called By: main()
**Input: 无
**Output: 无
**Return: void
**Others: 里面用到了宏值CityNum值
*************************************************/
void WriteDataTxt();
/**********************************************************************************禁忌表操作区*******************************************/
typedef struct _Tabu{
int smallNum;
int bigNum; //存储数量大的元素
}Tabu; //禁忌表结构
typedef struct _Queue{
Tabu *tabuList;//队列空间指针
int rear; //指向尾部
int front; //指向队列的头部
int maxSize; //记录队列的最大个数
int count; //记录资源个数 判断队列空满
int tabuIndex; //在禁忌表中找到禁忌元素时 存储该值在禁忌表中的位置
}Queue;//循环队列的形式
/*************************************************
**Function: CreateQueue
**Description: malloc一个禁忌表队列并初始化
**Calls: 无
**Called By: main()
**Input: tabuLength 禁忌表数据长度
**Output: 无
**Return: Queue * 队列变量
**Others: 里面用到了宏值CityNum值 ,用完需要释放掉相应内存
*************************************************/
Queue * CreateQueue(int tabuLength);
/*************************************************
**Function: UpdateTabu
**Description: 更新禁忌表
**Calls: IsFindTabu()
**Called By: TSP()
**Input: Q 禁忌表队列 item 加入禁忌表的Tabu结构的变量
**Output: 无
**Return: void
**Others:
*************************************************/
void UpdateTabu(Queue *Q,Tabu *item);
/*************************************************
**Function: IsFindTabu
**Description: 禁忌表中是否找到这个元素
**Calls: 无
**Called By: UpdateTabu() TSP()
**Input: Q 禁忌表队列 item 判断其是否在禁忌表中的Tabu结构的变量的指针
**Output: 无
**Return: 0 没有找到这个元素 1 找到这个元素了
**Others:
*************************************************/
static int IsFindTabu(Queue * Q,const Tabu *item);
/****************************************************************************2Opt邻域+TSp核心算法*********************************************/
//定义解的存储类型 向量形式
typedef struct _Solve{
ElementType *initSolution; //初始解
ElementType *currentSolution; //当前解
ElementType * optimalSolution; //最优解
ElementType *tempSolution; //临时解
ElementType lastdistance; //上次记录的总距离
ElementType initdistance; //定义初始距离
}StrSolve;
typedef struct _MotionTable{
Tabu tabu; //存储改变的元素
ElementType changedistance; //改变的距离
}MotionTable;//记录2opt邻域移动信息
StrSolve * SolutionSpace ; //解空间(包含当前解和初始解)指针
MotionTable *motionTable; //移动元素信息 (一个表格)
/*************************************************
**Function: CreateMotionStruct
**Description: 创建并初始化2-Opt 移动信息表格
**Calls: 无
**Called By: Init2Opt()
**Input: neighbor 邻居数量
**Output: 无
**Return: MotionTable *指针变量
**Others: 不用这块内存的时候要释放掉 !
*************************************************/
MotionTable* CreateMotionStruct(int neighbor);
/*************************************************
**Function: CreateSolutionSpace
**Description: 创建并初始化解空间
**Calls: 无
**Called By: Init2Opt()
**Input: cityNum 城市数量
**Output: 无
**Return: StrSolve *指针变量
**Others: 不用这块内存的时候要逐一释放掉 !
*************************************************/
StrSolve *CreateSolutionSpace(int cityNum);
/*************************************************
**Function: GetInitSolution
**Description: 获得初始解
**Calls: 无
**Called By: Init2Opt()
**Input: StrSolve * 指针变量
**Output: 无
**Return: StrSolve *指针变量
**Others: 这里在初始化解的时候可以用其他元启发式算法得出一个较好的解 !
*************************************************/
void GetInitSolution(StrSolve * strSolve);
/*************************************************
**Function: Init2Opt
**Description: 初始化TSP需要用的值
**Calls: CreateMotionStruct() CreateSolutionSpace() GetInitSolution()
**Called By: main
**Input: 无
**Output: 无
**Return: void
**Others: 这里在初始化解的时候可以用其他元启发式算法得出一个较好的解 ! 不知道为什么只能在Main函数中调用否则 会出现段错误
*************************************************/
void Init2Opt();
/*************************************************
**Function: FindPosition
**Description: 在数组中找到指定元素值的位置
**Calls:
**Called By: Get2OptChangeDistance() TSP()
**Input: solution 一维数组指针 tabu Tabu结构指针
**Output: 无
**Return: void
**Others: 这里是从solution[1]开始查找到的!
*************************************************/
static void FindPosition(const ElementType * solution,Tabu *tabu);
/*************************************************
**Function: FindPosition
**Description: 获得2邻域变化值
**Calls: FindPosition()
**Called By: Get2optSolution()
**Input: tabu Tabu结构指针 solution 一维数组指针
**Output: 无
**Return: ElementType 2邻域城市变化值
**Others: 返回的值越小越好 !
*************************************************/
static ElementType Get2OptChangeDistance(Tabu * tabu,const ElementType * solution);
/*************************************************
**Function: Get2optSolution
**Description: 得到1个2邻域解 将移动元素,及其导致路径的变化值 存储到移动表中
**Calls: Get2OptChangeDistance()
**Called By: TSP()
**Input: strSolve 解空间指针 motiontable 移动表指针
**Output: 无
**Return: void
**Others: 随机数要注意!
*************************************************/
void Get2optSolution(const StrSolve * strSolve,MotionTable *motiontable );
/*************************************************
**Function: Insert_Sort
**Description: 按从小到大排序 插入排序 将制定的类数组变量 的内容进行排序
**Calls: 无
**Called By: FindBestMotionValue()
**Input: motiontable 移动表指针 n为类数组 元素个数
**Output: 无
**Return: void
**Others:
*************************************************/
void Insert_Sort (MotionTable * motiontable,int n);
/*************************************************
**Function: FindBestMotionValue
**Description: 找到移动表中最小的值 即为最优值
**Calls: Insert_Sort()
**Called By: TSP()
**Input: motiontable 移动表指针
**Output: 无
**Return: MotionTable *型的指针 存储移动表中最好值的表格指针
**Others:
*************************************************/
MotionTable * FindBestMotionValue( MotionTable * motiontable);
/*************************************************
**Function: GetInitLevel
**Description: 获取初始解的渴望水平
**Calls:
**Called By: TSP()
**Input: distance 存储城市的矩阵指针 initSolution 初始解指针
**Output: 无
**Return: 初始解的渴望水平
**Others:
*************************************************/
int GetInitLevel( ElementType **distance,ElementType * initSolution);
/*************************************************
**Function: TSP
**Description: TSP核心算法
**Calls: GetInitLevel()
**Called By: TSP() Get2optSolution() FindBestMotionValue() UpdateTabu() FindPosition() memcpy()
**Input: distance 存储城市的矩阵指针 solutionSpace 解空间指针 motiontable 移动表 desireLevel 渴望水平 queue 禁忌表队列指针
**Output: 最优解信息
**Return: void
**Others:
*************************************************/
void TSP( ElementType **distance, StrSolve * solutionSpace ,MotionTable *motiontable,int *desireLevel,Queue *queue);
/*************************************************
**Function: MemFree
**Description: 释放申请的动态内存
**Calls: free()
**Called By: main()
**Input: distance 存储城市距离的变量指针 queue 禁忌表队列 motiontable 移动表的指针 strSolve 解空间的指针
**Output: 无
**Return: void
**Others: 这里也可以一步一步的释放掉 各自的指针 因为就用一个.c所以释放内存的操作都在这里进行
*************************************************/
void MemFree(ElementType ** distance,Queue *queue,MotionTable *motiontable,StrSolve *strSolve);
/*******************************************************************************MAIN函数*************************************/
int main(int argc,char *argv[])
{
// Tabu item;
clock_t start, finish;
double duration;
Queue * queue = CreateQueue(TabuLength); //创建一个禁忌表队列 本身就初始化好了
Init2Opt();//初始化相关
// 设置随机数种子 为以后使用rand()做准备
srand((unsigned ));
start = clock();
ReadDataTxt(Distance);//必须放在前面 读取数据后 才能操作
// PrintCityDistance(Distance); //显示二维数组的数据 只显示5X5
// WriteDataTxt(Distance);//将distance 数据写入txt
TSP( Distance,SolutionSpace ,motionTable,&DesireLevel,queue);
//// //将得到的最优解 从新用TSP算法算
// memcpy( SolutionSpace->initSolution,SolutionSpace->optimalSolution,sizeof(ElementType)*CityNum ); //将临时解空间值复制到当前解空间
// printf("\n新初始解的渴望水平:%d \n",GetInitLevel(Distance,SolutionSpace->optimalSolution));
// TSP( Distance,SolutionSpace ,motionTable,&DesireLevel,queue);
//
finish = clock();
duration = (double)(finish - start) / CLOCKS_PER_SEC;
printf("\n TSP算法运行时间:%.4f秒 \n",duration);
MemFree(Distance, queue,motionTable,SolutionSpace);
;
}
/************************************************************************读取数据区***********************************************/
/*************************************************
**Function: MemBlockCity
**Description: 申请存储城市距离空间
**Calls: 无
**Called By: ReadDataTxt() 在txt文档中读取数据
**Input: 无
**Output: 无
**Return: 指向存储城市距离空间的指针
**Others: 无
*************************************************/
ElementType ** MemBlockCity()
{
ElementType ** Distance;
;
//动态申请一块内存存储城市之间的数据
Distance = (ElementType **)malloc(sizeof(ElementType *)*CityNum);
;i< CityNum ; i++){
Distance[i] = (ElementType *)malloc(sizeof (ElementType )* CityNum);
}
return Distance;
}
/*************************************************
**Function: PrintCityDistance
**Description: 显示Distance信息 这里仅仅显示了CityNum-25个元素 因为屏幕显示不开
**Calls: 无
**Called By: main()
**Input: Distance 全局变量的指针
**Output: 无
**Return: void
**Others: 无
*************************************************/
void PrintCityDistance( ElementType ** distance)
{
int i,j;
; i< CityNum-;i++){
;j<CityNum-;j++)
printf("%d ",distance[i][j]);
printf("\n");
}
}
/*************************************************
**Function: ReadDataTxt
**Description: 从txt文档中读取数据
**Calls: MemBlockCity()
**Called By: main()
**Input: 无
**Output: 无
**Return: void
**Others: 里面直接用的全局变量 指针Distance
*************************************************/
void ReadDataTxt()
{
// FILE *fpRead=fopen("F:\\GCJ\\Desktop\\智能优化方法作业\\data.txt","r");
FILE *fpRead=fopen("data.txt","r"); //从data.txt中读取数据
int i,j;
if(fpRead==NULL){
printf("open file data.txt failed!\n");
exit();
}
Distance = MemBlockCity(); //申请一块存储城市数量空间
;i<CityNum;i++){
Distance[i][i] = ;
;j < CityNum;j++ ){
fscanf(fpRead,"%d",&Distance[i][j]);//自动读取数据 只要自己能够控制好存储位置即可
Distance[j][i] = Distance[i][j];
}
}
fclose(fpRead);
}
/*************************************************
**Function: WriteDataTxt
**Description: 将Distance全局数组数据写到txt文档中去
**Calls: 无
**Called By: main()
**Input: 无
**Output: 无
**Return: void
**Others: 里面用到了宏值CityNum值
*************************************************/
void WriteDataTxt(ElementType **distance)
{
FILE *fpWrite;
int i,j;
fpWrite=fopen("F:\\GCJ\\Desktop\\智能优化方法作业\\data.txt","w"); //从data.txt中写数据
;i< CityNum;i++){
;j<CityNum;j++)
fprintf(fpWrite,"%d ",distance[i][j]);//这里%d后面必须要有空格 否则 直接输出连续的数字
fprintf(fpWrite,"\n");
}
fclose(fpWrite);
}
/**************************************************************禁忌表操作区*****************************************************/
/*************************************************
**Function: CreateQueue
**Description: malloc一个禁忌表队列并初始化
**Calls: 无
**Called By: main()
**Input: tabuLength 禁忌表数据长度
**Output: 无
**Return: Queue * 队列变量
**Others: 里面用到了宏值CityNum值
*************************************************/
Queue * CreateQueue(int tabuLength)
{
Queue * queue = (Queue *)malloc(sizeof(struct _Queue));//申请一块队列变量
//queue->tabuList =(ElementType *)malloc(sizeof(ElementType)*MaxSize);//申请一块数组空间
queue->tabuList =(Tabu *)malloc(sizeof(Tabu)*tabuLength);//21的长度
queue->front = ;
queue->rear = ;//头尾 都为0
queue->maxSize = tabuLength;
queue->count =;
queue->tabuList[].smallNum = ;
queue->tabuList[].bigNum = ;
return queue;
}
/*************************************************
**Function: IsFindTabu
**Description: 禁忌表中是否找到这个元素
**Calls: 无
**Called By: UpdateTabu() TSP()
**Input: Q 禁忌表队列 item 判断其是否在禁忌表中的Tabu结构的变量的指针
**Output: 无
**Return: 0 没有找到这个元素 1 找到这个元素了
**Others:
*************************************************/
static int IsFindTabu(Queue * Q,const Tabu *item)
{
Tabu tabu;
int i;
;
//将要禁忌的值按顺序放在中间变量中 方便加入到禁忌表中
if( (*item).bigNum >= (*item).smallNum ){
tabu.bigNum = (*item).bigNum;
tabu.smallNum = (*item).smallNum;
}
else{
tabu.bigNum = (*item).smallNum;
tabu.smallNum = (*item).bigNum;
}
//查找禁忌表中是否有这个禁忌元素 没有的话 插入元素在头部 否则把这个元素加上惩罚政策加入到禁忌表的头部 其他依次降序
for(i = Q->front; (i%TabuLength)!= Q->rear; ){//这个查找函数有问题了 因为循环队列的话 队列慢点话 rear = front 如何解决?
if( (tabu.smallNum == Q->tabuList[i].smallNum ) && ( tabu.bigNum == Q->tabuList[i].bigNum ) ){
//说明在禁忌表中找到这个元素了 那么就惩罚这个 放在最前面
//把第一个元素放入 这个值 剩下的依次 递减排列
// printf("在禁忌表中找到了%d %d\n",tabu.bigNum,tabu.smallNum);
//新加 记录位置
Q->tabuIndex = i;
IsFindFlag = ;
return IsFindFlag ; //表示不管了
}
if(++i >= TabuLength)//仅仅让i 在 0 - Tabulength范围内遍历
i = ;
}
if( Q->count >= TabuLength ){//说明禁忌表满 那么rear值就需要访问了 否则不需要访问
if( i%TabuLength == Q->rear )//因为循环队列寻找的时候 最后一个元素 无法通过for循环遍历到
if( (tabu.smallNum == Q->tabuList[i].smallNum ) && ( tabu.bigNum == Q->tabuList[i].bigNum ) ){
// printf("找到了最新的了%d %d\n",tabu.smallNum,tabu.bigNum);
//新加 记录位置
Q->tabuIndex = Q->rear;
IsFindFlag = ;
return IsFindFlag ; //表示不管了
}
}
return IsFindFlag;//之前这里就忘了加了 注意这点 !!
}
/*************************************************
**Function: UpdateTabu
**Description: 更新禁忌表
**Calls: IsFindTabu()
**Called By: TSP()
**Input: Q 禁忌表队列 item 加入禁忌表的Tabu结构的变量的指针
**Output: 无
**Return: void
**Others:
*************************************************/
void UpdateTabu(Queue *Q,Tabu *item)
{
Tabu tabu;
Tabu temptabu;
int i;
//将要禁忌的值按顺序放在中间变量中 方便加入到禁忌表中
if( (*item).bigNum >= (*item).smallNum ){
tabu.bigNum = (*item).bigNum;
tabu.smallNum = (*item).smallNum;
}
else{
tabu.bigNum = (*item).smallNum;
tabu.smallNum = (*item).bigNum;
}
if( !IsFindTabu(Q,item) ){
//如果没有找到 那么直接在队列插入这个元素
if( Q->count < TabuLength ){ //说明队列不满 那就直接插入元素
Q->count++ ;//最后满的时候为21个元素
Q->tabuList[Q->rear++] = tabu;//在后面插入 然后从前面取出元素
if( Q->rear >= TabuLength)//到了尾部的话 就直接从前面开始存储 尾部先存储后+1
--Q->rear ;//说明禁忌表满了的时候 让rear指向最后一个元素即可
}
else{//满了的话 就直接头部删除 尾部加入 //不是真正的删除 仅仅是释放掉这块存储空间
if( ++Q->front >= TabuLength )
Q->front =;
if( ++Q->rear >= TabuLength)//到了尾部的话 就直接从前面开始存储 尾部先存储后+1
Q->rear = ;
Q->tabuList[Q->rear] = tabu;
}
}
else{//在禁忌表中找到这个元素的时候 需要进行惩罚 将这个值放在头部,而该值前面的数依次向后排
int j,k;
j = Q->tabuIndex ; //禁忌表中找到的该值的索引
k = Q->front; //禁忌表头部索引
if( Q->tabuIndex >= Q->front ){
//说明禁忌表没有满 或者 禁忌表满了 但是移动仅仅在Q->front 到这个索引即可
for( --j ;j >= k ; --j){
Q->tabuList[j+] = Q->tabuList[j];
}/*for end*/
}
else{
//禁忌表满了且 Q->front 值大于 Q->tabuIndex
for( ;j == Q->front; --j ){
)
Q->tabuList[j] =Q->tabuList[j-];
else{ //j == 0
j = TabuLength ;
Q->tabuList[] = Q->tabuList[j-];
}
}/*for ...end */
}
//惩罚策略
Q->tabuList[Q->front] = tabu;
}/*if find .. else ..end*/
}
/******************************************************************************************2Opt邻域+TSp核心算法***********************************/
/*************************************************
**Function: CreateMotionStruct
**Description: 创建并初始化2-Opt 移动信息表格
**Calls: 无
**Called By: Init2Opt()
**Input: neighbor 邻居数量
**Output: 无
**Return: MotionTable *指针变量
**Others: 不用这块内存的时候要释放掉 !
*************************************************/
MotionTable* CreateMotionStruct(int neighbor)
{
int i;
MotionTable * motiontable = (MotionTable *)malloc(sizeof(MotionTable)*neighbor );
;i< neighbor;i++){
motiontable->tabu.smallNum =;
motiontable->tabu.bigNum = ;
motiontable->changedistance = ;
}
return motiontable;
}
/*************************************************
**Function: CreateSolutionSpace
**Description: 创建并初始化解空间
**Calls: 无
**Called By: Init2Opt()
**Input: cityNum 城市数量
**Output: 无
**Return: StrSolve *指针变量
**Others: 不用这块内存的时候要逐一释放掉 !
*************************************************/
StrSolve *CreateSolutionSpace(int cityNum)
{
int i;
StrSolve *strSolve = (StrSolve *)malloc( sizeof(StrSolve) ) ;
strSolve->initSolution = ( ElementType *)malloc(sizeof(ElementType)*cityNum );
strSolve->currentSolution = ( ElementType *)malloc(sizeof(ElementType)*cityNum );
strSolve->optimalSolution = ( ElementType *)malloc(sizeof(ElementType)*cityNum );
strSolve->tempSolution = ( ElementType *)malloc(sizeof(ElementType)*cityNum );
//初始化解空间
;i< cityNum;i++){
strSolve->initSolution[i] = (ElementType);
strSolve->currentSolution[i] = (ElementType);
strSolve->optimalSolution[i] = (ElementType);
strSolve->tempSolution[i] = (ElementType);
}
strSolve->lastdistance = ;//记录上次迭代获得最好的距离值
return strSolve;
}
/*************************************************
**Function: GetInitSolution
**Description: 获得初始解
**Calls: 无
**Called By: Init2Opt()
**Input: StrSolve * 指针变量
**Output: 无
**Return: StrSolve *指针变量
**Others: 这里在初始化解的时候可以用其他元启发式算法得出一个较好的解 !
@brief :思路 可以用一个记录初始解的类数组(申请的内存 大小为初始解的元素个数),之后循环 CityNum-1次,不断的产生1-CityNum-1的随机数
没产生一个就记录这个值 之后再次产生与上次不同的随机数 ,依次这样循环即可 不过速度上会很慢
*************************************************/
void GetInitSolution(StrSolve * strSolve)
{
int i;
//默认从0号城市顺序开始 这里的0是固定不动的
;i<CityNum;i++){
strSolve->initSolution[i] = i;
strSolve->currentSolution[i] = i;
strSolve->optimalSolution[i] = i;
strSolve->tempSolution[i] = i;
}
}
/*************************************************
**Function: Init2Opt
**Description: 初始化TSP需要用的值
**Calls: CreateMotionStruct() CreateSolutionSpace() GetInitSolution()
**Called By: main()
**Input: 无
**Output: 无
**Return: void
**Others: 这里在初始化解的时候可以用其他元启发式算法得出一个较好的解 ! 不知道为什么只能在Main函数中调用否则 会出现段错误
*************************************************/
void Init2Opt()
{
motionTable = CreateMotionStruct(Neighbor);//初始化变化表 记录变化邻居值
SolutionSpace = CreateSolutionSpace(CityNum);//创建解空间
GetInitSolution(SolutionSpace);//初始化解
}
/*************************************************
**Function: MemFree
**Description: 释放申请的动态内存
**Calls:
**Called By: main()
**Input: distance 存储城市距离的变量指针 queue 禁忌表队列 motiontable 移动表的指针 strSolve 解空间的指针
**Output: 无
**Return: void
**Others: 这里也可以一步一步的释放掉 各自的指针 因为就用一个.c所以释放内存的操作都在这里进行
*************************************************/
void MemFree(ElementType ** distance,Queue *queue,MotionTable *motiontable,StrSolve *strSolve)
{
;
;
//释放矩阵元素存储区
;i < CityNum; i++){
free( distance[i] );
}
free(distance);
//释放移动表
free(motiontable);
//释放掉队列区
free(queue->tabuList);
free(queue);
//释放解空间
free(strSolve->initSolution);
free(strSolve->currentSolution);
free(strSolve->optimalSolution);
free(strSolve->tempSolution);
free(strSolve);
}
/*************************************************
**Function: FindPosition
**Description: 在数组中找到指定元素值的位置
**Calls:
**Called By: Get2OptChangeDistance() TSP()
**Input: solution 一维数组指针 tabu Tabu结构指针
**Output: 无
**Return: void
**Others: 这里是从solution[1]开始查找到的!
*************************************************/
static void FindPosition(const ElementType * solution,Tabu *tabu)
{
int i;
Tabu tempTabu;
; i< CityNum;i++){
if( solution[i] == tabu->smallNum )
tempTabu.smallNum = i;
if( solution[i] == tabu->bigNum )
tempTabu.bigNum = i;
}
*tabu = tempTabu;//不能直接返回&tempTabu 因为这个是一个局部的变量 会有悬挂指针的后果
}
/*************************************************
**Function: FindPosition
**Description: 获得2邻域变化值
**Calls: FindPosition()
**Called By: Get2optSolution()
**Input: tabu Tabu结构指针 solution 一维数组指针
**Output: 无
**Return: ElementType 2邻域城市变化值
**Others: 返回的值越小越好 !
*************************************************/
static ElementType Get2OptChangeDistance(Tabu * tabu,const ElementType * solution)
{
ElementType change1,change2;
Tabu tempTabu1 = *tabu;
Tabu tempTabu;
change1 = change2 = ;
FindPosition(solution,&tempTabu1); //此时这里的tempTabu1存储的就是指定元素在 解空间中的位置
tempTabu.bigNum = ( tempTabu1.bigNum >tempTabu1.smallNum )? tempTabu1.bigNum: tempTabu1.smallNum;
tempTabu.smallNum = ( tempTabu1.bigNum >tempTabu1.smallNum )? tempTabu1.smallNum: tempTabu1.bigNum;
){//两个元素在解空间中的 位置相差1
){ //最大值位置 在最后一个位置
change1 = Distance[ solution[tempTabu.smallNum -] ][ solution[tempTabu.smallNum] ]+\
Distance[ solution[tempTabu.bigNum] ][ solution[ ] ];
change2 = Distance[ solution[tempTabu.smallNum -] ][ solution[tempTabu.bigNum] ] +\
Distance[ solution[tempTabu.smallNum] ][ solution[] ];
return (change2 - change1);//这个值越小越好
}
else{
change1 = Distance[ solution[tempTabu.smallNum -] ][ solution[tempTabu.smallNum] ] +\
Distance[ solution[tempTabu.bigNum] ][ solution[ tempTabu.bigNum +] ];
change2 = Distance[ solution[tempTabu.smallNum -] ][ solution[tempTabu.bigNum] ] +\
Distance[ solution[tempTabu.smallNum] ][ solution[tempTabu.bigNum +] ];
return (change2 - change1);
}
}
else{//两个元素位置 不挨着
){ //最大值位置 在最后一个位置
change1 = Distance[ solution[tempTabu.smallNum -] ][ solution[tempTabu.smallNum] ] +\
Distance[ solution[tempTabu.smallNum] ][ solution[tempTabu.smallNum +] ] +\
Distance[ solution[tempTabu.bigNum-] ][ solution[ tempTabu.bigNum ] ] +\
Distance[ solution[tempTabu.bigNum] ][ solution[ ] ];
change2 = Distance[ solution[tempTabu.smallNum -] ][ solution[tempTabu.bigNum] ] +\
Distance[ solution[tempTabu.bigNum] ][ solution[tempTabu.smallNum+] ] +\
Distance[ solution[tempTabu.bigNum-] ][ solution[ tempTabu.smallNum ] ]+\
Distance[ solution[tempTabu.smallNum] ][ solution[] ];
return (change2 - change1);//这个值越小越好
}
else{
change1 = Distance[ solution[tempTabu.smallNum -] ][ solution[tempTabu.smallNum] ] +\
Distance[ solution[tempTabu.smallNum] ][ solution[tempTabu.smallNum +] ] +\
Distance[ solution[tempTabu.bigNum-] ][ solution[ tempTabu.bigNum ] ] +\
Distance[ solution[tempTabu.bigNum] ][ solution[ tempTabu.bigNum +] ];
change2 = Distance[ solution[tempTabu.smallNum -] ][ solution[tempTabu.bigNum] ] +\
Distance[ solution[tempTabu.bigNum] ][ solution[tempTabu.smallNum+] ] +\
Distance[ solution[tempTabu.bigNum-] ][ solution[ tempTabu.smallNum ] ]+\
Distance[ solution[tempTabu.smallNum] ][ solution[tempTabu.bigNum +] ];
return (change2 - change1);
}
}
}
/*************************************************
**Function: Get2optSolution
**Description: 得到1个2邻域解 将移动元素,及其导致路径的变化值 存储到移动表中
**Calls: Get2OptChangeDistance()
**Called By: TSP()
**Input: strSolve 解空间指针 motiontable 移动表指针
**Output: 无
**Return: void
**Others: 随机数要注意!
*************************************************/
void Get2optSolution(const StrSolve * strSolve,MotionTable *motiontable )
{
//产生一个1-CityNum-1之间的随机数 因为默认0为初始位置 不能动
ElementType temp;
ElementType changeDistance;
int rand1,rand2;
// rand1 = (CityNum-1) *rand()/(RAND_MAX + 1.0);
rand1 = rand()%(CityNum-)+;
rand2 = rand()%(CityNum-)+;
while( rand2 == rand1 )//必须产生两个不同的随机数 切不能为0
rand2 = rand()%(CityNum-) +;
//记录交换的两个元素 (不是位置)
motiontable->tabu.smallNum = (rand2 >rand1)? rand1:rand2;
motiontable->tabu.bigNum = (rand2 >rand1)? rand2:rand1;
motiontable->changedistance = Get2OptChangeDistance( &motiontable->tabu ,strSolve->tempSolution );
}
/*************************************************
**Function: Insert_Sort
**Description: 按从小到大排序 插入排序 将制定的类数组变量 的内容进行排序
**Calls: 无
**Called By: FindBestMotionValue()
**Input: motiontable 移动表指针 n为类数组 元素个数
**Output: 无
**Return: void
**Others:
*************************************************/
void Insert_Sort (MotionTable * motiontable,int n)
{
//进行N-1轮插入过程
int i,k;
; i<n; i++){
//首先找到元素a[i]需要插入的位置
;
while( (motiontable[j].changedistance < motiontable[i].changedistance ) && (j <i ) )
j++;
//将元素插入到正确的位置
if(i != j){ //如果i==j,说明a[i]刚好在正确的位置
MotionTable temp = motiontable[i];
for(k = i; k > j; k--){
motiontable[k] = motiontable[k-];
}
motiontable[j] = temp;
}
}
}
/*************************************************
**Function: FindBestMotionValue
**Description: 找到移动表中最小的值 即为最优值
**Calls: Insert_Sort()
**Called By: TSP()
**Input: motiontable 移动表指针
**Output: 无
**Return: MotionTable *型的指针 存储移动表中最好值的表格指针
**Others:
*************************************************/
MotionTable * FindBestMotionValue( MotionTable * motiontable)
{
//下面是仅仅找到一个最好的值 不管在不在禁忌表中
// MotionTable *bestMotion= motiontable;
// MotionTable *start = motiontable;
// MotionTable *end = motiontable + Neighbor-1;
// while(start++ < end ){
// if( start->changedistance < bestMotion->changedistance){
// bestMotion = start;//保存最好的结构
// }
// }
// if( start->changedistance < bestMotion->changedistance )
// bestMotion = start;
// return bestMotion;//f返回最好结构的指针
Insert_Sort(motiontable,Neighbor);//选择排序算法 从小到大排
return motiontable;//返回最好元素的地址
}
/*************************************************
**Function: GetInitLevel
**Description: 获取初始解的渴望水平
**Calls:
**Called By: TSP()
**Input: distance 存储城市的矩阵指针 initSolution 初始解指针
**Output: 无
**Return: 初始解的渴望水平
**Others:
*************************************************/
int GetInitLevel( ElementType **distance,ElementType * initSolution)
{
int i;
;
; i < CityNum- ; i++){
SumLevel += distance[ initSolution[i] ][ initSolution[i+] ];
}
SumLevel+= distance[ initSolution[i] ][];//最后在加上 最后一个值和初始值的 距离 才是循环的总距离距离
return SumLevel;
}
/*************************************************
**Function: TSP
**Description: TSP核心算法
**Calls: GetInitLevel()
**Called By: TSP() Get2optSolution() FindBestMotionValue() UpdateTabu() FindPosition() memcpy()
**Input: distance 存储城市的矩阵指针 solutionSpace 解空间指针 motiontable 移动表 desireLevel 渴望水平 queue 禁忌表队列指针
**Output: 最优解信息
**Return: void
**Others:
*************************************************/
void TSP( ElementType **distance, StrSolve * solutionSpace ,MotionTable *motiontable,int *desireLevel,Queue *queue)
{
int i;
int temp;
;
MotionTable * BestMotionStruct;
ElementType BestChangeDistance;//最好的改变的值
// Init2Opt();//初始化相关
*desireLevel = GetInitLevel(distance,solutionSpace->initSolution);
solutionSpace->lastdistance = *desireLevel;//初始最优值为上次移动的最好的距离
solutionSpace->initdistance = solutionSpace->lastdistance;//将初始值给初始距离 之后再判断 减少的距离
printf("初始距离:%d ",*desireLevel);
// printf("初始最好的距离是%d,solutionSpace->lastdistance = %d\n",*desireLevel,solutionSpace->lastdistance);
printf("城市数量:%d 迭代次数:%d 邻居个数:%d\n",CityNum,MaxNG,Neighbor);
//迭代 次数作为停止条件
while( currentNG++ < MaxNG ){
//获得邻居最好解
; neighborNum < Neighbor; neighborNum++ ){//循环Neighbor那么多次
Get2optSolution(SolutionSpace,&motionTable[neighborNum] );//将邻域 移动放在移动表中
}
//找到移动表中最小的值 此时解若是 < 渴望水平 则更新最优解 否则找到不在禁忌表中的 最好的解 更新当前解
BestMotionStruct = FindBestMotionValue( motiontable);
BestChangeDistance = BestMotionStruct->changedistance;
if( solutionSpace->lastdistance + BestChangeDistance < *desireLevel){//当前迭代出的最好的解 小于渴望水平 更新最优解T表当前解
int temp;
//更新T表
UpdateTabu(queue,&BestMotionStruct->tabu);
//更新渴望水平
*desireLevel = solutionSpace->lastdistance +BestChangeDistance;
//更新上次迭代的最优值
solutionSpace->lastdistance = *desireLevel;
//更新当前解和最优解
FindPosition(solutionSpace->tempSolution,&BestMotionStruct->tabu);//找到当前解 对应的解空间的位置
temp = solutionSpace->tempSolution[ BestMotionStruct->tabu.smallNum ];
solutionSpace->tempSolution[ BestMotionStruct->tabu.smallNum] = solutionSpace->tempSolution[ BestMotionStruct->tabu.bigNum ];
solutionSpace->tempSolution[ BestMotionStruct->tabu.bigNum ] = temp;
memcpy( solutionSpace->currentSolution,solutionSpace->tempSolution,sizeof(ElementType)*CityNum ); //将临时解空间值复制到当前解空间
memcpy( solutionSpace->optimalSolution,solutionSpace->tempSolution,sizeof(ElementType)*CityNum );
}
else{//没有小于渴望水平 找到不在禁忌表中最好的移动
//在移动表中找到不在禁忌表中最好元素 因为拍好序了 所以从表的第二个值开始找即可
int i;
;i< Neighbor; i++){
if( !IsFindTabu(queue,&motiontable[i].tabu) ){
int temp;
//不在禁忌表中 则这个值就是目前来说最好的值
BestMotionStruct = &motiontable[i];
//更新T表
UpdateTabu(queue,&BestMotionStruct->tabu);
solutionSpace->lastdistance = solutionSpace->lastdistance + BestMotionStruct->changedistance;
//更新当前解
FindPosition(solutionSpace->tempSolution,&BestMotionStruct->tabu);//找到当前解 对应的解空间的位置
temp = solutionSpace->tempSolution[ BestMotionStruct->tabu.smallNum ];
solutionSpace->tempSolution[ BestMotionStruct->tabu.smallNum] = solutionSpace->tempSolution[ BestMotionStruct->tabu.bigNum ];
solutionSpace->tempSolution[ BestMotionStruct->tabu.bigNum ] = temp;
memcpy( solutionSpace->currentSolution,solutionSpace->tempSolution,sizeof(ElementType)*CityNum ); //将临时解空间值复制到当前解空间
break;//跳出循环
}
}
}
}
currentNG = ;//将全局迭代次数变量值清零
printf("\n初始值:%d 最优解值:%d 优化距离:%d\n最优解元素:\n\n",\
solutionSpace->initdistance,\
GetInitLevel(distance,solutionSpace->optimalSolution),solutionSpace->initdistance - *desireLevel);
;i< CityNum;i++){
printf("%d-> ",solutionSpace->optimalSolution[i]);
}
printf( ] );
}
原创:TSP问题解决方案-----禁忌搜索算法C实现的更多相关文章
- 禁忌搜索算法TSA 旅行商问题TSP python
import math import random import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot ...
- 【算法】禁忌搜索算法(Tabu Search,TS)超详细通俗解析附C++代码实例
01 什么是禁忌搜索算法? 1.1 先从爬山算法说起 爬山算法从当前的节点开始,和周围的邻居节点的值进行比较. 如果当前节点是最大的,那么返回当前节点,作为最大值 (既山峰最高点):反之就用最高的邻居 ...
- 【高级算法】禁忌搜索算法解决3SAT问题(C++实现)
转载请注明出处:http://blog.csdn.net/zhoubin1992/article/details/46440389 近期梳理,翻出了当年高级算法课程做的题目.禁忌搜索算法解决3SAT问 ...
- 原创:工作指派问题解决方案---模拟退火算法C实现
本文忽略了对于模拟退火的算法的理论讲解,读者可参考相关的博文或者其他相关资料,本文着重于算法的实现: /************************************************ ...
- 【原创】BI解决方案选型之ETL数据整合工具对比
一.背景 在企业BI平台建设过程中,数据整合始终是一切的基础,简单BI项目可以通过存储过程来实现,而复杂.全面.多方异构数据来源等就大大增加了复杂性,存储过程的可管理性.可维护性.容错性等就无法很好的 ...
- 【智能算法】变邻域搜索算法(Variable Neighborhood Search,VNS)超详细解析和TSP代码实例以及01背包代码实例
喜欢的话可以扫码关注我们的公众号哦,更多精彩尽在微信公众号[程序猿声] 00 目录 局部搜索再次科普 变邻域搜索 造轮子写代码 01 局部搜索科普三连 虽然之前做的很多篇启发式的算法都有跟大家提过局部 ...
- 智能优化算法对TSP问题的求解研究
要求: TSP 算法(Traveling Salesman Problem)是指给定 n 个城市和各个城市之间的距离,要 求确定一条经过各个城市当且仅当一次的最短路径,它是一种典型的优化组合问题,其最 ...
- 模拟退火算法SA原理及python、java、php、c++语言代码实现TSP旅行商问题,智能优化算法,随机寻优算法,全局最短路径
模拟退火算法SA原理及python.java.php.c++语言代码实现TSP旅行商问题,智能优化算法,随机寻优算法,全局最短路径 模拟退火算法(Simulated Annealing,SA)最早的思 ...
- 【算法】变邻域搜索算法(Variable Neighborhood Search,VNS)超详细一看就懂的解析
更多精彩尽在微信公众号[程序猿声] 变邻域搜索算法(Variable Neighborhood Search,VNS)一看就懂的解析 00 目录 局部搜索再次科普 变邻域搜索 造轮子写代码 01 局部 ...
随机推荐
- HDMI转MIPI DSI芯片方案TC358779XBG
型号:TC358779XBG功能:HDMI1.4转MIPI DSI通信方式:IIC分辨率:1920*1080电源:3.3/1.8/1.2封装形式:BGA80深圳长期现货 ,提供技术支持,样品申请及规格 ...
- Keil报错failed to execute 'd:\Keil\C51\BIN\C51.EXE'
关于老师发的keil软件报错如下: --- Error: failed to execute 'd:\Keil\C51\BIN\C51.EXE' 错误是因为老师直接拷贝的安装目录,里面的文件路径设置仍 ...
- keepalive集群工作原理及应用
author:JevonWei 版权声明:原创作品 集群工作原理 一.集群基础 1.系统的扩展方式 scale up向上扩展:提高单台服务器的性能 scale out向外扩展:多台服务器联合起来满足同 ...
- makefile初步制作,arm-linux- (gcc/ld/objcopy/objdump)详解
在linux中输入vi Makefile 来实现创建Makefile文件 注意:命令行前必须加TAB键 例如:将两个文件led.c和crt0.S汇编文件,制作一个Makefile文件 led.bin ...
- 使用HttpGet请求json数据
- 【★】IT界8大恐怖预言
IT界的8大恐怖预言 本文字数:3276 建议阅读时间:你开心就好 第三次科技革命已经进入白热化阶段---信息技术革命作为其中最主要的一环已经奠定了其基本格局和趋势.OK大势已定,根据目前的形势,小编 ...
- Spring mybatis源码篇章-NodeHandler实现类具体解析保存Dynamic sql节点信息
前言:通过阅读源码对实现机制进行了解有利于陶冶情操,承接前文Spring mybatis源码篇章-XMLLanguageDriver解析sql包装为SqlSource SqlNode接口类 publi ...
- 团队作业8——第二次项目冲刺(Beta阶段)Day7——5.26
展开圆桌式会议: 会议内容:1.汇总BETA阶段的成果.2.针对BETA阶段的大家的获得的收获进行了讨论.3.对整个团队项目的过程进行了总结.每个人的工作分配: 队员 今日任务 贡献比 林燕 做最后测 ...
- 控制结构(10) 指令序列(opcode)
// 上一篇:管道(pipeline) 发现问题 在一个正式项目的开发周期中,除了源代码版本控制外,还存在着项目的配置/编译/打包/发布等各种高频但非"核心"的脚本代码.职业程序员 ...
- 201521123104 《Java程序设计》第5周学习总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点 1.2 可选:使用常规方法总结其他上课内容. 1.接口不是类,不能使用new进行实例化; 2.接口可以扩展; 3.接口中可以包含 ...