粒子群算法的调参技巧及改进方法
C++源码实现
1 基本粒子群算法简单介绍
1.1 粒子群算法( Particle Swarm Optimization, PSO)是一种典型的群体智能算法。最早是由美国心理学家Eberhart和电气工程师Kennedy于1995年提出,是一种模拟鸟类群体觅食行为的仿生智能计算方法。鸟群在整个搜寻的过程中,通过相互传递各自的信息,让其他的鸟知道自己的位置,同时也将最优解的信息传递给整个鸟群,最终,整个鸟群都能聚集在食物源周围,即我们所说的找到了最优解,即问题收敛。每只鸟会实时记录下自己的历史最优位置、鸟群的全局最优位置,作为下一次更新位置和速度的依据。
1.2 优点:简单容易实现、参数少、易于改进、对初始位置的依耐性弱、时间复杂度底
1.3 标准PSO算法的流程:(本博客,附源码实现)
步骤1: 随机初始化粒子群的位置和速度(种群规模N);
步骤2: 计算每个粒子的适应度;
步骤3: 对每个粒子,将其适应值与其经过的最好位置pbest作比较,如果当前值更好,更新pbest(历史最优);
步骤4: 对每个粒子,将其适应值与其经过的最好位置gbest作比较,如果当前值更好,更新gbest(全局最优);
步骤5: 调整粒子速度和位置;
步骤6: 满足结束条件,结束;否则,转到第2)步。
2 调参与改进综述
看了不少论文,目前学术界提高粒子群算法的性能主要有如下三种方法:
2.1 合理的设置基本参数: (本博客,附源码实现)
(1)种群规模amout的设置:根据模型复杂度定义
(2)惯性权重w,加速系数c1、c2的设置:w范围在0.7-0.9,c1=c2=(1-w)/2
(3)最大速度系数V_scale:范围在0.05-0.15之间
(4)退火思想(学习率渐渐减小):种群规模N、Vmax、w前期设置较大,后期渐渐变小,前期偏重全局搜索避免遗漏最优解,后期偏重局部搜索以提高收敛速度。
2.2 使用拓扑结构(本博客,附源码实现)
全局拓扑:全连接(标准粒子群算法)
局部拓扑:环形拓扑、冯诺依曼、四簇结构
优缺点:
全局拓扑结构速度快,但易早熟,陷入局部最优;
局部拓扑结构收敛速度慢一点,全局搜索的能力强;
通常情况下,冯诺依曼、四簇结构的综合性能比较好。
2.3 与其他智能优化算法联用(源码实现,见后续博客)
1 粒子群算法与禁忌搜索联用:可以过早避免陷入局部 (仿真速度和优化结构与四簇结构相似);
2 粒子群算法与PCA主成分分析联用:可以大大提高收敛速度(参数之间有较强相关性时使用有较好效果);
3 粒子群与梯度下降联用:可以提高收敛速度;
4 将基因算法的变异因子引入粒子群:在所有粒子陷入局部并停滞后,可以通过变异因子跳出局部继续仿真
等等
3. C++源码文件
3.1 Pso_single类:包含单个粒子的基本信息和方法函数,粒子的位置、适应值、各权重和系数、速度位置的更新方法、适应值计算方法等。所在文.3件:SinglePso.cpp、SinglePso.h;
3.2 Pso类:包含多个Pso_single对象,组成粒子群。包括系数退火方法、gbest计算方法、粒子群初始化、更新等。所在文件:Pso.cpp、Pso.h;
3.3 Pso_Top类:继承自Pso类。实现了3种局部top结构(环形拓扑、冯诺依曼、四簇结构)。所在文件:top.cpp、top.h;
3.4 工具函数:适应值函数、随机数组生成函数、粒子群优劣度比较函数等。所在文件:funs.cpp、funs.h;
3.5 主函数:main.cpp
4. 源码
4.1 SinglePso.h
#ifndef SINGLEPSO_H_INCLUDED
#define SINGLEPSO_H_INCLUDED
/*
Pso_single:封装了单个粒子的类;
该类的数据成员,包括粒子的:
坐标维度:in_dims,坐标,适应值,位置上下限,速度上下限,惯性系数,
全局速度因子,局部速度因子,速度上下限,速度范围因子,局部最优解,全局最优解,
方法: 随机初始化、计算适应值、更新全局最优、更新局部最优
*/
class Pso_single
{
private:
int in_dims; //坐标维度
float *in_max, *in_min; //位置上下限
float *v_max,*v_min; //速度上下限
float w,c1,c2; //惯性系数,局部速度因子、全局速度因子
public:
float *v_; //速度
float fitness_; //粒子的适应值
float *in_; //粒子的坐标
float fitness_pbest; //粒子的历史最优适应值
float *in_pbest; //粒子的历史最优坐标
float fitness_gbest; //粒子的全局最优适应值
float *in_gbest; //粒子的全局最优坐标
//Pso_single:构造函数
Pso_single(int in_dims_,float *inmax, float *inmin, float *vmax, float *vmin,float w_,float c1_,float c2_);
//init_:随机初始化粒子的速度和位置
void init_();
//get_fitness:计算当前坐标的适应值
void get_fitness();
//init_pbest:初始化历史最优
void init_pbest();
//updata_pbest:更新历史最优
void updata_pbest();
//get_gbest: 更新全局最优
void get_gbest(float *in_gbest_,float fitness_gbest_);
//updata_v::更新速度
void updata_v();
//updata_in:更新坐标
void updata_in();
};
#endif // SINGLEPSO_H_INCLUDED
4.2 SinglePso.cpp
#include <iostream>
#include<algorithm>
#include"SinglePso.h"
#include"funs.hpp"
using namespace std;
Pso_single::Pso_single(int in_dims_,float *inmax, float *inmin, float *vmax, float *vmin,float w_,float c1_,float c2_)
{
in_dims = in_dims_; //坐标维度
fitness_ = 0.0; //粒子的适应值
in_ = new float [in_dims]; //粒子的坐标
v_ = new float [in_dims]; //速度
fitness_pbest = 0.0 ; //粒子的历史最优适应值
in_pbest = new float [in_dims]; //粒子的历史最优坐标
fitness_gbest = 0.0; //粒子的全局最优适应值
in_gbest = new float [in_dims]; //粒子的全局最优坐标
in_max = inmax; //位置上限
in_min = inmin; //位置下限
v_max = vmax; //速度上限
v_min = vmin; //速度下限
w = w_; //惯性系数,
c1 = c1_; //历史速度因子
c2 = c2_; //全局速度因子
}
void Pso_single::init_()
{ // 随机初始化坐标
in_ = random_array(in_dims,in_max,in_min);
// 随机初始化速度
v_ = random_array(in_dims,v_max,v_min);
}
void Pso_single::get_fitness()
{
//计算适应值
fitness_ = fitness_fun(in_);
}
void Pso_single::init_pbest()
{
//将坐标值和适应值,直接拷贝
copy_(in_,in_pbest,in_dims);
fitness_pbest = fitness_;
}
void Pso_single::updata_pbest()
{ //如果当前粒子的适应值大于历史最优值pbest,重新拷贝
if (fitness_<=fitness_pbest)
copy_(in_,in_pbest,in_dims);
fitness_pbest = fitness_;
}
void Pso_single::get_gbest(float *in_gbest_,float fitness_gbest_)
{ //将传入的全局最优,赋值给当前粒子的全局最优
//全局最优需要比较所有粒子的适应值,
//所以先在外部对所有粒子进行比较。然后再传入。
copy_(in_gbest_,in_gbest,in_dims);
fitness_gbest = fitness_gbest_;
}
void Pso_single::updata_v(){
//根据如下公式更新速度
//v=v*w + (pbestin-in)*c1 + (gbestin-in)*c2
//速度不得超过上限、下限
for(int i = 0;i<in_dims;i++){
v_[i] = v_[i]*w + (in_pbest[i] - in_[i])*c1 + (in_gbest[i] - in_[i])*c2;
if (v_[i]>v_max[i])
{v_[i] = v_max[i];}
if (v_[i]<v_min[i])
{v_[i] = v_min[i];}
}
}
void Pso_single::updata_in(){
//更新位置。位置不得超过上限、下限
for(int i = 0;i<in_dims;i++){
in_[i] = in_[i] + v_[i];
if (in_[i]>in_max[i])
{in_[i] = in_max[i];}
if (in_[i]<in_min[i])
{in_[i] = in_min[i];}
}
}
4.3 Pso.h
#ifndef PSO_H_INCLUDED
#define PSO_H_INCLUDED
#include "SinglePso.h"
#include <vector>
using namespace std;
/*
Pso类:标准粒子群算法
成员:多个Single_pso,速度因子、惯性因子等
*/
class Pso
{
protected:
int swarm_amount; //粒子群数量
int in_dim; //粒子坐标的维度
float w,c1,c2; //
float* max_in; //
float* min_in; //
float* max_v; //
float* min_v; //
float* fitness_list; //
float v_scale = 0.1; //速度范围因子。建议0.05<v_scale<0.2
float w_col = 1.0; // 惯性衰减因子,建议0.96<w_col<1.0
float v_col = 1.0; //速度衰减因子,建议0.96<v_col<1.0
vector<Pso_single> vector_pso; //存储所有粒子的容器
public:
float* in_gbest_final; //存放最终的最优坐标
float fitness_gbest_final; //最优坐标对应的最优适应值
//Pso:构造函数
Pso(int swarm_amount_,int in_dim_,float w_,float* max_,float* min_,float v_scale_);
//set_w_col:设置惯性衰减因子
void set_w_col(float w_col);
//set_v_col:设置速度衰减因子
void set_v_col(float v_col);
//gbest:计算全局最优gbest
void gbest(int flag);
//initialize:初始化每个粒子的坐标值、速度、适应值、局部最优、全局最优、
void initialize();
//update:更新坐标值、速度、适应值、局部最优、全局最优、
void update();
//gone:循环迭代。circle_表示迭代次数
void gone(int circle_);
};
#endif // PSO_H_INCLUDED
4.4 Pso.cpp
#include <iostream>
#include <stdlib.h>
#include <vector>
#include <time.h>
#include<algorithm>
#include "Pso.h"
#include"funs.hpp"
using namespace std;
//构造函数:初始化参数
Pso::Pso(int swarm_amount_,int in_dim_,float w_,float* max_,float* min_,float v_scale_)
{
in_gbest_final = new float[in_dim];
swarm_amount = swarm_amount_;
fitness_list = new float[swarm_amount];
in_dim = in_dim_;
w = w_;
c1 = (1-w)/2;
c2 = (1-w)/2;
min_in = new float[in_dim];
max_in = new float[in_dim];
min_v = new float[in_dim];
max_v = new float[in_dim];
max_in = max_;
min_in = min_;
v_scale = v_scale_;
for(int i = 0; i<in_dim; i++)
{
max_v[i] = (max_[i]-min_[i])*v_scale;
min_v[i] = -(max_[i]-min_[i])*v_scale;
}
}
//设置惯性衰减系数
void Pso::set_w_col(float w_col_)
{
w_col = w_col_;
}
//设置速度范围的衰减系数
void Pso::set_v_col(float v_col_)
{
v_col = v_col_;
}
//更新粒子群的全局最优解gbest
void Pso::gbest(int init_flag)
{
float* in_gbest_temp = new float[in_dim]; //存放每轮的最优粒子坐标
float fitness_gbest_temp; //每一轮最优适应值
get_min(swarm_amount,vector_pso,in_gbest_temp,&fitness_gbest_temp,in_dim);
for(int i=0; i<swarm_amount; i++)
{
//如果是处于第一轮迭代,或者fitness_gbest_temp优于粒子的gbest
//将粒子的gbest替换为fitness_gbest_temp和in_gbest_temp
if (init_flag == 0 ||fitness_gbest_temp < vector_pso[i].fitness_gbest)
{
vector_pso[i].get_gbest(in_gbest_temp,fitness_gbest_temp);
}
}
}
//初始化粒子群的坐标、速度、历史最优、全局最优
void Pso::initialize()
{
for(int i=0; i<swarm_amount; i++)
{
Pso_single single(in_dim,max_in,min_in,max_v,min_v,w,c1,c2);
single.init_();
single.get_fitness();
single.init_pbest();
vector_pso.push_back(single);
}
gbest(0);
}
//更新粒子群的速度、坐标、历史最优、全局最优
void Pso::update()
{
if (w_col != 1.0)
{
w = w*w_col; //衰减w
c1 = (1-w)/2; //增加c1
c2 = (1-w)/2; //增加c2
}
if (v_col != 1.0)
{
v_scale = v_scale * v_col; //衰减v_scale
}
for(int i=0; i<swarm_amount; i++)
{
vector_pso[i].updata_v();
vector_pso[i].updata_in();
vector_pso[i].get_fitness();
vector_pso[i].updata_pbest();
}
gbest(1);
}
//初始化,并且反复进行circle_轮的迭代
void Pso::gone(int circle_)
{
this->initialize();
for (int i = 0; i<circle_; i++)
{
if (i%5 == 0)
{
cout<<"第"<<i<<"次迭代"<<endl;
}
this->update();
}
//get_final_gbest:计算最终的最优粒子
get_final_gbest(swarm_amount,vector_pso,in_gbest_final,&fitness_gbest_final,in_dim);
}
4.5 top.h
#ifndef TOP_H_INCLUDED
#define TOP_H_INCLUDED
#include <iostream>
#include <vector>
#include "Pso.h"
using namespace std;
/*
Pso_Top :
为Pso的子类,实现局部top结构的功能。
*/
class Pso_Top : public Pso
{
private:
int top_flag = 0; //拓扑值标签
public:
//Pso_Top: 构造函数
Pso_Top(int swarm_amount_,int in_dim_,float w_,float* max_,float* min_,float v_scale_):Pso(swarm_amount_,in_dim_,w_,max_,min_,v_scale_)
{
}
//set_topFlag: 设置top类型
void set_topFlag(int topFlag);
//gbest:生成全局最优
void gbest(int init_flag);
};
#endif // TOP_H_INCLUDED
4.6 top.cpp
#include <iostream>
//#include <stdlib.h>
#include <vector>
#include <cmath>
#include <time.h>
//#include<algorithm>
#include "top.h"
#include"funs.hpp"
using namespace std;
void Pso_Top::set_topFlag(int topFlag)
{
top_flag = topFlag;
}
/*top_index_0:环形top结构中,每个粒子共享其前后粒子的信息
top_index_1:冯诺依曼top结构中,每个粒子共享其前后粒子的信息
top_index_2:四簇结构,将所有粒子等分为4簇,簇内粒子共享信息;部分粒子与其他簇共享信息*/
//环形top结构的索引获取
void top_index_0(int i_ ,int size_v,int* index_v)
{
index_v[0] = (i_+size_v-1)%size_v;
index_v[1] = i_;
index_v[2] = (i_+1)%size_v;
}
//get_row_col:top_index_1的内置函数。
//功能:合理的分配行和列,行和列的值尽量接近些
int get_row_col(int num_)
{
int row = 0;
for(int i=1; i<=sqrt(num_); i++)
{
if (num_%i==0)
{
row = i;
}
}
return row;
}
//get_index:top_index_1的内置函数。
//功能:获取目标粒子前、后、左、右的索引。
//(i,j) = (-1,0) 前
//(i,j) = (1,0) 后
//(i,j) = (0,-1) 左
//(i,j) = (0,1) 右
int get_index(int row,int col,int row_curr,int col_curr,int i,int j)
{
return ((row_curr+i+row)%row)*col + ((col_curr+j+col)%col);
}
//冯诺依曼结构的索引获取
void top_index_1(int i_ ,int size_v,int* index_v)
{
int row,col,row_curr,col_curr;
row = get_row_col(size_v);
col = size_v/row;
row_curr = i_/col;
col_curr = i_%col;
index_v[0] = get_index(row,col,row_curr,col_curr,-1,0);//上
index_v[1] = get_index(row,col,row_curr,col_curr,1,0);//上
index_v[2] = i_;//中间
index_v[3] = get_index(row,col,row_curr,col_curr,0,-1);//左
index_v[4] = get_index(row,col,row_curr,col_curr,0,11);;//右
}
//四簇结构:将所有粒子等分为4簇,簇内粒子共享信息;部分粒子与其他簇共享信息
int top_index_2(int group_id ,int swarm_id)
{
/*
注:下文以group-i-k表示第i簇的第k号粒子;例如group-1-0,表示第1簇的第0号粒子;
group_index_0数组表示:group-0中的第0、1、2个粒子分别与group-1-0,group-2-1,
group-3-2相连接;group_index_1,group_index_2,group_index_3以此类推。
*/
int group_index_0[3][2] = {{1,0},{2,1},{3,2}};
int group_index_1[3][2] = {{0,0},{3,1},{2,0}};
int group_index_2[3][2] = {{1,2},{0,1},{3,0}};
int group_index_3[3][2] = {{2,2},{1,1},{0,2}};
switch(group_id)
{
case 0:
return group_index_0[swarm_id][0]*4 + group_index_0[swarm_id][1];
break;
case 1:
return group_index_1[swarm_id][0]*4 + group_index_0[swarm_id][1];
break;
case 2:
return group_index_2[swarm_id][0]*4 + group_index_0[swarm_id][1];
break;
case 3:
return group_index_3[swarm_id][0]*4 + group_index_0[swarm_id][1];
break;
};
}
void Pso_Top::gbest(int init_flag)
{
float* in_gbest_temp = new float[in_dim];
float fitness_gbest_temp;
int* index_;
if (top_flag < 2)
{
// top_flag = 0:环形结构
// top_flag = 1:冯诺依曼结构
for(int i=0; i<swarm_amount; i++)
{
//for循环:用于计算每个粒子的在当前top模型下的全局最优解gbest
switch(top_flag)
{
case 0:
index_ = new int[3]; //每个粒子以及与其共享信息的粒子的索引
top_index_0(i ,swarm_amount,index_); //索引值复杂
break;
case 1:
index_ = new int[5];//每个粒子以及与其共享信息的粒子的索引
top_index_1(i ,swarm_amount,index_);//索引值复杂
break;
}
vector<Pso_single> vector_local; //定义容器,用于存储与当前粒子共享信息的粒子
for(int j = 0; j<sizeof(index_); j++)
{
vector_local[j] = vector_pso[index_[j]];//逐个存储共享信息的粒子
}
//获取最优适应值的粒子
get_min(vector_local.size(),vector_local,in_gbest_temp,&fitness_gbest_temp,in_dim);
//更新粒子的gbest
// init_flag == 0,代表是第一轮迭代
if (init_flag == 0||fitness_gbest_temp<vector_pso[i].fitness_gbest)
{
vector_pso[i].get_gbest(in_gbest_temp,fitness_gbest_temp);
}
}
}
else
{
//top_flag = 2:四簇结构
//下面的for循环:循环4次,分别计算每一个簇中的粒子的gbest
for(int i=0; i<4; i++)
{
int sub_amout = int(swarm_amount/4);//sub_amout:每个子簇的粒子数量
vector<Pso_single> vector_local; //定义容器,用于存储每个簇粒子群
for(int j = 0; j<sub_amout; j++)
{
vector_local[j] = vector_pso[index_[i*sub_amout+j]];//存储当前簇内的所有粒子
}
//get_min:计算当前子簇内的gbest
get_min(vector_local.size(),vector_local,in_gbest_temp,&fitness_gbest_temp,in_dim);
for(int j=0; j<sub_amout; j++)
{
//给当前簇的所有粒子的gbest赋值
if (init_flag == 0||fitness_gbest_temp<vector_pso[i].fitness_gbest)
{
vector_pso[i*sub_amout+j].fitness_gbest = fitness_gbest_temp;
vector_pso[i*sub_amout+j].in_gbest = in_gbest_temp;
}
if(j<3)
{
//如果j<3:前三个粒子,还要再比较一下其和外簇相连粒子的gbest
int index_ = top_index_2(i ,j);
if (fitness_gbest_temp<vector_pso[i].fitness_gbest)
{
vector_pso[i*sub_amout+j].fitness_gbest = vector_pso[index_].fitness_;
vector_pso[i*sub_amout+j].in_gbest = vector_pso[index_].in_;
}
}
}
}
}
}
4.7 funs.h
#ifndef FUNS_HPP_INCLUDED
#define FUNS_HPP_INCLUDED
#include <vector>
#include "SinglePso.h"
using namespace std;
//random_single:生成0-1的浮点数
float random_single();
//random_array:随机生成dims维度的数组
float* random_array(int dims,float *max_, float *min_);
//fitness_fun:生成适应值的函数
float fitness_fun(float* in_);
//copy_:数组 深拷贝
void copy_(float src[],float dst[],int dims);
//get_max:通过计算,得到适应值最小的粒子
void get_min(int mount,vector<Pso_single> temp_pso,float* max_in,float* max_fit,int in_dims_);
//get_max:通过计算,得到适应值最小的粒子
void get_final_gbest(int mount,vector<Pso_single> temp_pso,float* final_in,float* final_fit,int in_dims_);
#endif // FUNS_HPP_INCLUDED
4.8 funs.cpp
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <vector>
#include <math.h>
#include "SinglePso.h"
#include "funs.hpp"
#define PI 3.1415926
using namespace std;
//生成0——1之间的随机数
float random_single()
{
return ((float)(rand()%1000))/1000.0;
}
//生成维度为dims的随机数组
float* random_array(int dims,float *max_,float *min_)
{
float *temp = new float[dims];
for(int i=0; i<dims; i++)
{
float random_ = random_single();
temp[i] = (max_[i] - min_[i])*random_ + min_[i];
}
return temp;
}
//fitness_fun:适应度函数使用 “Rastrigin's 函数”
float fitness_fun(float* inin)
{
float x1 = inin[0];
float x2 = inin[1];
float rastrigin_ = 20 + pow(x1,2) + pow(x2,2) - 10*(cos(2*PI*x1) + cos(2*PI*x2));
return rastrigin_;
}
//数组复制
void copy_(float src[],float dst[],int dims)
{
for(int i = 0; i<dims; i++)
{
dst[i] = src[i];
}
}
//通过计算,得到vector中的最小适应值和对应的坐标
void get_min(int mount,vector<Pso_single> temp_pso,float* min_in,float* min_fit,int in_dims_)
{
for(int i=0; i<mount; i++)
{
if(i == 0 || temp_pso[i].fitness_ < *min_fit)
{
*min_fit = temp_pso[i].fitness_;
copy_(temp_pso[i].in_,min_in,in_dims_);
}
}
}
//通过计算,得到最终的最优解
void get_final_gbest(int mount,vector<Pso_single> temp_pso,float* final_in,float* final_fit,int in_dims_)
{
for(int i=0; i<mount; i++)
{
if(i == 0 || temp_pso[i].fitness_ < *final_fit)
{
*final_fit = temp_pso[i].fitness_gbest;
copy_(temp_pso[i].in_,final_in,in_dims_);
}
}
}
4.9 main.cpp
#include <iostream>
#include <stdlib.h>
#include <vector>
#include <time.h>
#include <math.h>
#include "SinglePso.h"
#include "Pso.h"
#include "funs.hpp"
#include "top.h"
using namespace std;
int main()
{
srand(time(0)); //随机种子
int amout_ = 400; //粒子数
float w_ = 0.8; // 惯性权重
// 通常情况下,全局加速因子 c1、历史加速因子c2 ,等于 (1-w)/2
float v_scale_ = 0.1; //速度比例因子。最大速度、最小速度的范围
int circle_ = 80 ;//迭代次数
//本适应度函数是两维。网友可以根据自身需要更改适应度函数、
int in_dims_ = 2; //输入坐标的维度为2
float max_in[] = {5.0,5.0}; //输入参数的上限
float min_in[] = {-5.0,-5.0}; //输入参数的下限
Pso_Top pso_(amout_,2,0.8,max_in,min_in,v_scale_); //初始化粒子群对象,局部top结构的粒子群对象
//使用冯诺依曼top结构,粒子数应为偶数且大于12
//使用四簇拓扑结构,粒子数应为4的倍数且大于12
pso_.set_topFlag(2); //设置top类型{0:环形拓扑结构;1:冯诺依曼拓扑结构; 2:四簇拓扑结构}
/*
上述代码为 局部top结构的粒子群算法的初始方式。
标准粒子群算法的初始化代码如下:
Pso pso_(amout_,2,0.8,max_in,min_in,v_scale_);
*/
pso_.set_w_col(0.99); //设置惯性衰减系数。惯性系数每次迭代乘以0.99。c1和c2相应增加
pso_.set_v_col(0.99); //设置速度衰减因子。速度的上限和下限。随着迭代衰减
pso_.gone(circle_); //执行
cout<<"*********迭代完成********"<<endl;
cout<<"*****final_gbest fitness:"<<pso_.fitness_gbest_final<<endl;
cout<<"*****final_gbest in_:("<<pso_.in_gbest_final[0]<<","<<pso_.in_gbest_final[1]<<")"<<endl;
cout<<"*********迭代完成********"<<endl;
}