zoukankan      html  css  js  c++  java
  • 算法:权重图的最最小生成树算法

    算法思路

    问题

    给定顶点集合为 V,边集合为 E,求最小生成树 T?

    解过程

    任意时刻的边都可以划分为到三个集合:

    • X:边的所有顶点都是最小生成树的一部分。
    • Y:边的末端节点不是最小生成树的一部分。
    • Z:其它。

    从 Y 中选择权重最小的边,将其加入到 T 中。

    优先级队列

    该算法需要用到一个工具:优先级队列(从某个集合中选择最小的元素)。

      1         class PriorityQueue<T>
      2             where T : IComparable<T>
      3         {
      4             private T[] _items;
      5             private int _length;
      6 
      7             public PriorityQueue(int size)
      8             {
      9                 _items = new T[size];
     10             }
     11 
     12             public void EnQueue(T item)
     13             {
     14                 if (this.IsFull())
     15                 {
     16                     throw new InvalidOperationException("容量已满,不能插入!");
     17                 }
     18 
     19                 _items[_length++] = item;
     20                 this.MoveUp(_length - 1);
     21             }
     22 
     23             private void MoveUp(int index)
     24             {
     25                 var bottom = _items[index];
     26                 var current = index;
     27 
     28                 while (current > 0)
     29                 {
     30                     var parent = (current - 1) / 2;
     31                     if (_items[parent].CompareTo(bottom) < 0)
     32                     {
     33                         break;
     34                     }
     35 
     36                     _items[current] = _items[parent];
     37                     current = parent;
     38                 }
     39 
     40                 _items[current] = bottom;
     41             }
     42 
     43             public T DeQueue()
     44             {
     45                 if (this.IsEmpty())
     46                 {
     47                     throw new InvalidOperationException("容量已空,不能删除!");
     48                 }
     49 
     50                 var result = _items[0];
     51                 _items[0] = _items[--_length];
     52 
     53                 this.MoveDown(0);
     54 
     55                 return result;
     56             }
     57 
     58             private void MoveDown(int index)
     59             {
     60                 var top = _items[index];
     61                 var current = index;
     62 
     63                 while (current < _length)
     64                 {
     65                     var small = 0;
     66                     var left = 2 * current + 1;
     67                     var right = left + 1;
     68 
     69                     if (left < _length && right < _length)
     70                     {
     71                         if (_items[left].CompareTo(_items[right]) <= 0)
     72                         {
     73                             small = left;
     74                         }
     75                         else
     76                         {
     77                             small = right;
     78                         }
     79                     }
     80                     else if (left < _length)
     81                     {
     82                         small = left;
     83                     }
     84                     else
     85                     {
     86                         break;
     87                     }
     88 
     89                     if (_items[small].CompareTo(top) >= 0)
     90                     {
     91                         break;
     92                     }
     93 
     94                     _items[current] = _items[small];
     95                     current = small;
     96                 }
     97 
     98                 _items[current] = top;
     99             }
    100 
    101             public bool IsFull()
    102             {
    103                 return _length == _items.Length;
    104             }
    105 
    106             public bool IsEmpty()
    107             {
    108                 return _length == 0;
    109             }
    110         }

    最小生成树代码

      1         class Edge : IComparable<Edge>
      2         {
      3             public int StartIndex { get; set; }
      4 
      5             public int EndIndex { get; set; }
      6 
      7             public int Weight { get; set; }
      8 
      9             public string Description { get; set; }
     10 
     11             public int CompareTo(Edge other)
     12             {
     13                 return this.Weight.CompareTo(other.Weight);
     14             }
     15         }
     16 
     17         private class Path : IComparable<Path>
     18         {
     19             public Path()
     20             {
     21                 this.Edges = new List<Edge>();
     22             }
     23 
     24             public int StartVertexIndex { get; set; }
     25 
     26             public int EndVertexIndex { get; set; }
     27 
     28             public List<Edge> Edges { get; private set; }
     29 
     30             public int Weight { get; private set; }
     31 
     32             public void AddEdges(IEnumerable<Edge> edges)
     33             {
     34                 foreach (var edge in edges)
     35                 {
     36                     this.AddEdge(edge);
     37                 }
     38             }
     39 
     40             public void AddEdge(Edge edge)
     41             {
     42                 this.Edges.Add(edge);
     43                 this.Weight += edge.Weight;
     44             }
     45 
     46             public int CompareTo(Path other)
     47             {
     48                 return this.Weight.CompareTo(other.Weight);
     49             }
     50         }
     51 
     52         class Vertex<T>
     53         {
     54             public T Value { get; set; }
     55         }
     56 
     57         class Graph<T>
     58         {
     59             #region 私有字段
     60 
     61             private int _maxSize;
     62             private Vertex<T>[] _vertexs;
     63             private Edge[][] _edges;
     64             private int _vertexCount = 0;
     65 
     66             #endregion
     67 
     68             #region 构造方法
     69 
     70             public Graph(int maxSize)
     71             {
     72                 _maxSize = maxSize;
     73                 _vertexs = new Vertex<T>[_maxSize];
     74                 _edges = new Edge[_maxSize][];
     75                 for (var i = 0; i < _maxSize; i++)
     76                 {
     77                     _edges[i] = new Edge[_maxSize];
     78                 }
     79             }
     80 
     81             #endregion
     82 
     83             #region 添加顶点
     84 
     85             public Graph<T> AddVertex(T value)
     86             {
     87                 _vertexs[_vertexCount++] = new Vertex<T> { Value = value };
     88 
     89                 return this;
     90             }
     91 
     92             #endregion
     93 
     94             #region 添加边
     95 
     96             public Graph<T> AddUnDirectedEdge(T startItem, T endItem, int weight)
     97             {
     98                 var startIndex = this.GetVertexIndex(startItem);
     99                 var endIndex = this.GetVertexIndex(endItem);
    100 
    101                 _edges[startIndex][endIndex] = new Edge { StartIndex = startIndex, EndIndex = endIndex, Weight = weight, Description = String.Format("{0}->{1}", startItem, endItem) };
    102                 _edges[endIndex][startIndex] = new Edge { StartIndex = endIndex, EndIndex = startIndex, Weight = weight, Description = String.Format("{0}->{1}", endItem, startItem) };
    103 
    104                 return this;
    105             }
    106 
    107             public Graph<T> AddDirectedEdge(T startItem, T endItem, int weight)
    108             {
    109                 var startIndex = this.GetVertexIndex(startItem);
    110                 var endIndex = this.GetVertexIndex(endItem);
    111 
    112                 _edges[startIndex][endIndex] = new Edge { StartIndex = startIndex, EndIndex = endIndex, Weight = weight, Description = String.Format("{0}->{1}", startItem, endItem) };
    113 
    114                 return this;
    115             }
    116 
    117             #endregion
    118 
    119             #region 最小生成树
    120 
    121             public IEnumerable<Edge> GetMinimumSpanningTree()
    122             {
    123                 var minimumSpanningTrees = new List<Edge>();
    124                 Dictionary<int, bool> vertexInTreesTracker = new Dictionary<int, bool>();
    125                 var queue = new PriorityQueue<Edge>(_maxSize);
    126 
    127                 var currentVertexIndex = 0;
    128                 while (minimumSpanningTrees.Count < _vertexCount - 1)
    129                 {
    130                     vertexInTreesTracker[currentVertexIndex] = true;
    131 
    132                     foreach (var item in _edges[currentVertexIndex])
    133                     {
    134                         if (item == null)
    135                         {
    136                             continue;
    137                         }
    138                         if (vertexInTreesTracker.ContainsKey(item.EndIndex))
    139                         {
    140                             continue;
    141                         }
    142 
    143                         queue.EnQueue(item);
    144                     }
    145 
    146                     var smallEdge = queue.DeQueue();
    147                     while (vertexInTreesTracker.ContainsKey(smallEdge.EndIndex))
    148                     {
    149                         smallEdge = queue.DeQueue();
    150                     }
    151                     minimumSpanningTrees.Add(smallEdge);
    152                     currentVertexIndex = smallEdge.EndIndex;
    153                 }
    154 
    155                 return minimumSpanningTrees;
    156             }
    157 
    158             #endregion
    159 
    160             #region 最短路径
    161 
    162             public IEnumerable<Edge> GetShortestPath(T startItem, T endItem)
    163             {
    164                 var startIndex = this.GetVertexIndex(startItem);
    165                 var endIndex = this.GetVertexIndex(endItem);
    166 
    167                 var shortestPaths = new Dictionary<int, Path>();
    168                 var queue = new PriorityQueue<Path>(_maxSize);
    169 
    170                 var currentVertexIndex = startIndex;
    171                 var currentPath = new Path
    172                 {
    173                     StartVertexIndex = startIndex,
    174                     EndVertexIndex = endIndex
    175                 };
    176 
    177                 while (!shortestPaths.ContainsKey(endIndex))
    178                 {
    179                     foreach (var item in _edges[currentVertexIndex])
    180                     {
    181                         if (item == null)
    182                         {
    183                             continue;
    184                         }
    185                         if (shortestPaths.ContainsKey(item.EndIndex))
    186                         {
    187                             continue;
    188                         }
    189 
    190                         var path = new Path
    191                         {
    192                             StartVertexIndex = startIndex,
    193                             EndVertexIndex = item.EndIndex
    194                         };
    195                         path.AddEdges(currentPath.Edges);
    196                         path.AddEdge(item);
    197                         queue.EnQueue(path);
    198                     }
    199 
    200                     var smallPath = queue.DeQueue();
    201                     while (shortestPaths.ContainsKey(smallPath.EndVertexIndex))
    202                     {
    203                         smallPath = queue.DeQueue();
    204                     }
    205                     shortestPaths[smallPath.EndVertexIndex] = smallPath;
    206                     currentVertexIndex = smallPath.EndVertexIndex;
    207                     currentPath = smallPath;
    208                 }
    209 
    210                 return shortestPaths[endIndex].Edges;
    211             }
    212 
    213             #endregion
    214 
    215             #region 帮助方法
    216 
    217             private int GetVertexIndex(T item)
    218             {
    219                 for (var i = 0; i < _vertexCount; i++)
    220                 {
    221                     if (_vertexs[i].Value.Equals(item))
    222                     {
    223                         return i;
    224                     }
    225                 }
    226                 return -1;
    227             }
    228 
    229             #endregion
    230         }

    备注

    最短路径的算法和最小生成树的算法非常相似,都是利用了:优先级队列。

  • 相关阅读:
    完全卸载Android Studio(卸载得干干净净)
    每日生活总结1
    求解协方差矩阵
    每天一个linux命令:ifconfig命令 临时修改重启后恢复原样
    每天一个linux命令(58):telnet命令
    每天一个linux命令:pwd命令
    每天一个linux命令(38):cal 命令
    每天一个linux命令:scp命令
    login shell与non-login shell的区别
    linux下重要的网络配置文件
  • 原文地址:https://www.cnblogs.com/happyframework/p/3497306.html
Copyright © 2011-2022 走看看