博客主要围绕图展开,介绍了图的BFS广度优先遍历和DFS深度优先遍历方法,还提及了Prim算法、Kruskal算法、Dijkstra算法以及Floyd算法等经典图算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Graph

BFS 广度优先遍历

//广度遍历(queue)
void BFS(Graph& G, int V){//初始化广度优先周游要用到的队列
   using std::queue;
   queue<int> Q; 
   G.Mark[V]= VISITED; //访问顶点V,并标记其标志位, V入队
   Visit(G, V);                        
   Q.push(V); 
   while(!Q.empty())    //如果队列仍然有元素
   {
      int V=Q.front();   //顶部元素 
      Q.pop();                //出队 
      for(Edge e=G.FirstEdge(V);G.IsEdge(e);e=G.NextEdge(e))//将与该点相邻的每一个未访问结点都入队
      {
        if(G.Mark[G.ToVertex(e)]== UNVISITED)
        {         
           G.Mark[G.ToVertex(e)]=VISITED;
           Visit(G, G.ToVertex(e));
         
           Q.push(G.ToVertex(e));        //入队   
        } 
      }
    }
} 

DFS 深度优先遍历

//深度递归遍历
void DFS(Graph& G, int v)  {        // 深度优先搜索的递归实现
     G.Mark[v] = VISITED;          // 将标记位设置为VISITED
     Visit(G,v);    // 访问顶点v
 for (Edge e = G.FirstEdge(v); G.IsEdge(e); e = G.NextEdge(e))
         if (G.Mark[G.ToVertex(e)] == UNVISITED)
          DFS(G, G.ToVertex(e));
}

Prim算法

//Prim最小生成树
Edge * Prim(AdjGraph& G,int s){//应用Prim算法从s顶点出发得到的最小生成树 
 int i,j;
 Edge *MST;                 //存储最小生成树的边
 int *nearest;                   //各个顶点到生成树中的各个顶点的最短的边,nearest[i]表示生成树中的点到i点的最小边权值
 int *neighbor;                       //neighbor[i]表示生成树中与i点最近的点编号,-1表示i点已经在生成树集合中
 int n = G.vertexNum;               //图的顶点个数
 nearest = new int[n];
 neighbor = new int[n];
 MST = new Edge[n-1];
 for(i = 0;i < n;i++){                    //初始化neighbor数组和nearest数组 
  neighbor[i] = s;
  nearest[i] = 9999;
 }
 for(Edge e = G.FirstEdge(s);G.IsEdge(e);e = G.NextEdge(e)){//与s相邻接的顶点的边权值作为这些点距离生成树集合的最短边长 
  nearest[e.end] = e.weight;
 }
 neighbor[s] = -1;                      //将已加入到生成树的点的最近邻设置为-1 
 for(i = 1;i < n;i++){                    //i标记已经加入到生成树中的点个数 
  int min = 9999;
  int v = -1;
  for(j = 0;j < n;j++){                //确定一个顶点在生成树集合一个顶点不在生成树集合且权值最小的边所关联的顶点 
   if(nearest[j]<min && neighbor[j]>-1){
    min = nearest[j];
    v = j;
   }
  }
  if(v > 0){                       //将v加入到生成树集合中,更新到生成树外的各个点最小权值的边信息 
   Edge tempEdge(neighbor[v],v,nearest[v]);
   MST[i-1] = tempEdge;  
   neighbor[v] = -1;          //将边加入到生成树集合中
   for(Edge e = G.FirstEdge(v);G.IsEdge(e);e = G.NextEdge(e)){
    int u = e.end;
    if(neighbor[u] != -1&&nearest[u] > e.weight){//用与v关联的边更新生成树之外顶点到生成树集合的最小边权值 
     neighbor[u] = v;
     nearest[u] = e.weight; 
    }
   } 
  }
 }
 delete []neighbor;                 //释放空间
 delete []nearest;
 return MST; 
}

Kruskal算法

//Kruskal求最小生成树
//等价类
class UFSets{
 private:
   int n;                            //等价类中元素个数
   int* root;                        //root[i]表示元素i所在的等价类的代表元素编号
   int* next;                        //next[i]表示在等价类中,i的后面元素编号
   int* length;                      //length[i]表示i所代表的等价类的元素个数
 public:
   UFSets(int size){                 //初始size个元素的等价类 
    n = size;
    root = new int[n];
    next = new int[n];
    length = new int[n];
    for(int i = 0;i < n;i++){
     root[i] = i;
     next[i] = i;        //各个元素独自成为一个等价类
     length[i] = 1; 
    }
   } 
   void swap(int & i,int & j)
       {
           int temp;
           temp = i;
           i = j;
           j = temp;
       }
   int Find(int v){
    return root[v];
   }
   void Union(int v,int u);          //合并v和u所在的等价类,将元素多的合并到元素少的等价类中 
};

void UFSets::Union(int v,int u){
 if(root[u] == root[v])             //如果v和u在一个等价类中则返回 
   return;
 else if(length[root[v]] < length[root[u]]){//将v所在等价类元素合并到u所在等价类,并将u所在等价类的代表元素作为合并后的等价类代表元 
  int rt = root[v];                  //获取v所在等价类的代表元素
  length[root[u]] += length[rt]; //修改u所在等价类的元素个数
  root[rt] = root[u];            //修改v所在等价类的各个元素的代表元素信息
  for(int j = next[rt];j != rt;j = next[j])
    root[j] = root[u];
  swap(next[rt],next[root[u]]);//将两个等价类的元素连接起来 
 }
 else{                            //length[root[v]]>=length[root[u]]
  int rt = root[u];
  length[root[v]] += length[rt];
  root[rt] = root[v];
  for(int j = next[rt];j != rt;j = next[j])
    root[j] = root[v];
  swap(next[rt],next[root[v]]);
 }                          
} 

//Kruskal算法
Edge * Kruskal(Graph& G){ //求含有n个顶点、e条边的连通图G的最小生成树 
 int n = G.vertexNum;
 UFSets set(n);                   //定义n个结点的等价类
 Edge *MST = new Edge[n-1];         //记录最小生成树的边
 Heap<Edge> H(G.edgeNum);
 Edge edge; 
 for(int i = 0;i < G.vertexNum;i++){  //将图的所有边记录在堆中 
  for(edge = G.FirstEdge(i);G.IsEdge(edge);edge = G.NextEdge(edge)){
   if(G.StartVertex(edge) < G.EndVertex(edge)){//避免无向图中的边被重复考察 
    H.Insert(edge);
   }
  } 
 }
 int edgeNum = 0;                  //生成树的边个数
 while(edgeNum < n-1){            //n个结点的连通图的生成树有n-1条边 
  if(!H.isEmpty()){
   H.Delete(edge);     //找到权重最小的未处理的边
   int v = edge.start;
   int u = edge.end;
   if(set.Find(v) != set.Find(u)){//判断该边关联的顶点是否在一个连通分量 
    set.Union(v,u);     //合并两个顶点所在的等价类
    MST[edgeNum++] = edge;//将符合条件的边添加到生成树的边集合中 
   } 
  }
 } 
 return MST;
}

Dijkstra算法

//Dijkstra单源最短路径
void Dijkstra(Graph &G,int s,int D[],int Path[]){
 int n = G.vertexNum;
 int i,j;
 for(i = 0;i < n;i++){
  G.Mark[i] = 0;
  D[i] = 9999;
  Path[i] = -1;                 //标记此时不存在s到i的路径 
 }
 G.Mark[s] = 1;
 D[s] = 0;
 Path[s] = s;
 for(i = 0;i < n;i++){               //找到一条最短特殊路径,即min{D[j]|G.Mark[j]==0,0<=j<n} 
  int min = 9999;
  int k = 0;
  for(j = 0;j < n;j++){
   if(G.Mark[j]==0 && min>D[j]){
    min = D[j];
    k = j;
    }
   }
  G.Mark[k] = 1;               //已确定s到k的最短路径
  for(Edge e = G.FirstEdge(k);G.IsEdge(e);e = G.NextEdge(e)){//利用k更新到其余未访问顶点的最短特殊路径 
   int endVertex = e.end;
   if(G.Mark[endVertex]==0 && D[endVertex]>(D[k]+e.weight)){//更新到endVertex的最短特殊路径 
    D[endVertex] = D[k] + e.weight;
    Path[endVertex] = k; 
   } 
  } 
 }
}

Floyd算法

//顶点之间最短路径
void Floyd(int **Adj,int **Path){
 int i,j,v;                    //i,j是计数器,v记录相应顶点 
 int n = vertexNum;
 for(i = 0;i < n;i++){
  for(j = 0;j < n;j++){
   if(i == j){
    Adj[i][j] = 0;
    Path[i][j] = i;
   }
   else{
    Adj[i][j] = 9999;
    Path[i][j] = -1;
   }
  }
 }
 for(v = 0;v < n;v++){            //检查各条边,将边(v,u)的值作为Adj[v,u],v作为Path[u]的值 
  for(Edge e = FirstEdge(v);IsEdge(e);e = NextEdge(e)){
   Adj[v][e.end] = Weight(e);
   Path[v][e.end] = v;
  }
 }
 for(v = 0;v < n;v++)             //如果两个顶点i,j间的最短路径经过顶点v,且有Adj[i][j]>(Adj[i][v]+Adj[v][j]),则更新Adj[i][j],Path[i][j] 
  for(i = 0;i < n;i++)
   for(j = 0;j < n;j++)
    if(Adj[i][j] > (Adj[i][v]+Adj[v][j])){
     Adj[i][j] = Adj[i][v]+Adj[v][j];//更新i,j之间经过的点编号不超过v的最短路径长度 
     Path[i][j] = v;        //更新i,j之间经过的点编号不超过v的最短路径上j的前驱 
    }
}
内容概要:本文针对国内加密货币市场预测研究较少的现状,采用BP神经网络构建了CCi30指数预测模型。研究选取2018年3月1日至2019年3月26日共391天的数据作为样本,通过“试凑法”确定最优隐结点数目,建立三层BP神经网络模型对CCi30指数收盘价进行预测。论文详细介绍了数据预处理、模型构建、训练及评估过程,包括数据归一化、特征工程、模型架构设计(如输入层、隐藏层、输出层)、模型编译与训练、模型评估(如RMSE、MAE计算)以及结果可视化。研究表明,该模型在短期内能较准确地预测指数变化趋势。此外,文章还讨论了隐层节点数的优化方法及其对预测性能的影响,并提出了若干改进建议,如引入更多技术指标、优化模型架构、尝试其他时序模型等。 适合人群:对加密货币市场预测感兴趣的研究人员、投资者及具备一定编程基础的数据分析师。 使用场景及目标:①为加密货币市场投资者提供一种新的预测工具和方法;②帮助研究人员理解BP神经网络在时间序列预测中的应用;③为后续研究提供改进方向,如数据增强、模型优化、特征工程等。 其他说明:尽管该模型在短期内表现出良好的预测性能,但仍存在一定局限性,如样本量较小、未考虑外部因素影响等。因此,在实际应用中需谨慎对待模型预测结果,并结合其他分析工具共同决策。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值