代码改变世界

数据结构-图(带权图)(js)

2010-08-15 23:03  Clingingboy  阅读(2720)  评论(0编辑  收藏  举报

 

一.最小生成树

永远遵循取最小权值的原则
如一个顶点到多个顶点,取最小权值
1.添加边结构

var Edge = function (sv, dv, d) {
    //起始点
    this.srcVert = sv;
    //重点
    this.destVert = dv;
    //权值
    this.distance = d;
}

2.添加优先级队列

var PriorityQ = function () {
    this.queArray = [];
    this.Max_Size = 10;
    this.length = 0;
};

PriorityQ.prototype.Insert = function (item) {
    var i;
    //compute distance index
    for (i = 0; i < this.length; i++) {
        if (item.distance >= this.queArray[i].distance)
            break;
    }
    //move
    for (var j = this.length - 1; j >= i; j--) {
        this.queArray[j + 1] = this.queArray[j];
    }
    this.queArray[i] = item;
    this.length++;
};

PriorityQ.prototype.remove = function () {
    if (arguments.length == 0)
        return this.queArray[--this.length];
    if (arguments.length == 1) {
        for (var j = arguments[0]; j < this.length - 1; j++) {
            this.queArray[j] = this.queArray[j + 1];
        }
        this.length--;
    }
};

PriorityQ.prototype.peek = function () {
    if (arguments.length == 0)
        return this.queArray[this.length - 1];
    if (arguments.length == 1) {
        return this.queArray[arguments[0]];
    }
};

PriorityQ.prototype.IsEmpty = function () {
    return this.length == 0;
}

PriorityQ.prototype.find = function (dex) {
    for (var j = 0; j < this.length; j++) {
        if (this.queArray[j].destVert == dex)
            return j;
    }
    return -1;
}
3.1 标记当前项
this.getCurrentVertex().isInTree = true;
nTree++;

3.2将符合条件的权值放入队列中
for (var j = 0; j < this.length; j++) {
    //skip 
    //if it's us 
    //in the tree
    //no edge
    if (j == this.currentVertIndex)
        continue;
    if (this.vertexList[j].isInTree)
        continue;
    var distance = this.adjMat[this.currentVertIndex][j];
    if (distance == 0)
        continue;
    //put in pq
    //ensure index and distance
    this.putInPQ(j, distance);
}
如遇到起点相同的,则比较distance,放弃distance长的那个.
Graph.prototype.putInPQ=function(newVert, newDist)
{
    var queueIndex = this.thePQ.find(newVert);
    if (queueIndex != -1) {
        var tempEdge = this.thePQ.peek(queueIndex);
        var oldDist = tempEdge.distance;
        //compare distance
        if (oldDist > newDist) {
            this.thePQ.remove(queueIndex);
            var theEdge = new Edge(this.currentVertIndex, newVert, newDist);
            this.thePQ.Insert(theEdge);
        }
    }
    else {
        //insert directly                    
        var theEdge = new Edge(this.currentVertIndex, newVert, newDist);
        this.thePQ.Insert(theEdge);
    }
}

3.4.取最小权值
if (this.thePQ.length == 0) return;
//remove minium distance from dq
var theEdge = this.thePQ.remove();
var srcVert = theEdge.srcVert;
this.currentVertIndex = theEdge.destVert;
//display

this.vertexList[srcVert].Display();
this.vertexList[this.currentVertIndex].Display();
完整示例
Graph.prototype.getCurrentVertex=function()
            {
               return this.vertexList[this.currentVertIndex];
            }

            Graph.prototype.mstw = function () {
                var nTree = 0;
                while (nTree < this.length - 1) {
                    //put CurrentVertex in tree
                    this.getCurrentVertex().isInTree = true;
                    nTree++;

                    for (var j = 0; j < this.length; j++) {
                        //skip 
                        //if it's us 
                        //in the tree
                        //no edge
                        if (j == this.currentVertIndex)
                            continue;
                        if (this.vertexList[j].isInTree)
                            continue;
                        var distance = this.adjMat[this.currentVertIndex][j];
                        if (distance == 0)
                            continue;
                        //put in pq
                        //ensure index and distance
                        this.putInPQ(j, distance);
                    }
                    if (this.thePQ.length == 0) return;
                    //remove minium distance from dq
                    var theEdge = this.thePQ.remove();
                    var srcVert = theEdge.srcVert;
                    this.currentVertIndex = theEdge.destVert;
                    //display

                    this.vertexList[srcVert].Display();
                    this.vertexList[this.currentVertIndex].Display();
                }
            }
          Graph.prototype.putInPQ=function(newVert, newDist)
          {
              var queueIndex = this.thePQ.find(newVert);
              if (queueIndex != -1) {
                  var tempEdge = this.thePQ.peek(queueIndex);
                  var oldDist = tempEdge.distance;
                  //compare distance
                  if (oldDist > newDist) {
                      this.thePQ.remove(queueIndex);
                      var theEdge = new Edge(this.currentVertIndex, newVert, newDist);
                      this.thePQ.Insert(theEdge);
                  }
              }
              else {
                  //insert directly                    
                  var theEdge = new Edge(this.currentVertIndex, newVert, newDist);
                  this.thePQ.Insert(theEdge);
              }
          }


二.求最短路径

迪杰斯特拉(Dijkstra)算法求顶点0到其他各顶点的最短路径


1.用于保存之前顶点到当前顶点的距离

    class DistPar             // distance and parent
    {                      // items stored in sPath array
        public int distance;   // distance from start to this vertex
        public int parentVert; // current parent of this vertex
        // -------------------------------------------------------------
        public DistPar(int pv, int d)  // constructor
        {
            distance = d;
            parentVert = pv;
        }
        // -------------------------------------------------------------
    }  // end class DistPar

2.将第一个顶点标记为在树中

      int startTree = 0;             // start at vertex 0
      vertexList[startTree].isInTree = true;
      nTree = 1;                     // put it in tree

3.初始化读取顶点到各个顶点的距离,如果没有边则距离为无穷大

// transfer row of distances from adjMat to sPath
for(int j=0; j<nVerts; j++)
   {
   int tempDist = adjMat[startTree][j];
   sPath[j] = new DistPar(startTree, tempDist);
   }

4.进入回圈

4.1在各点中取距离最小的点

int indexMin = getMin();    // get minimum from sPath
int minDist = sPath[indexMin].distance;


4.2记录距离最小的点的索引值和距离,并把该顶点标记入树

if(minDist == INFINITY)     // if all infinite
          {                        // or in tree,
          System.out.println("There are unreachable vertices");
          break;                   // sPath is complete
          }
       else
          {                        // reset currentVert
          currentVert = indexMin;  // to closest vert
          startToCurrent = sPath[indexMin].distance;
          // minimum distance from startTree is
          // to currentVert, and is startToCurrent
          }
       // put current vertex in tree
       vertexList[currentVert].isInTree = true;
4.3 当把当前索引顶点记录之后,然后获取该顶点到各顶点的距离
            int column = 1;                // skip starting vertex
while(column < nVerts)         // go across columns
   {

   int currentToFringe = adjMat[currentVert][column];
}
4.4记录上个距离和当前距离的和
int startToFringe = startToCurrent + currentToFringe;
4.5与第一个顶点到该节点的距离和startToFringe 进行比较,然后取短路径.并更新sPath的顶点和距离.
比如A到B是60,B到C是50,A到C是150,那么A经过B再到C的路径小于A直接到C的距离,则产生了最小路径
         int sPathDist = sPath[column].distance;

// compare distance from start with sPath entry
if(startToFringe < sPathDist)   // if shorter,
   {                            // update sPath
   sPath[column].parentVert = currentVert;
   sPath[column].distance = startToFringe;
   }
完整(核心
public void adjust_sPath()
      {
      // adjust values in shortest-path array sPath
      int column = 1;                // skip starting vertex
      while(column < nVerts)         // go across columns
         {
         // if this column's vertex already in tree, skip it
         if( vertexList[column].isInTree )
            {
            column++;
            continue;
            }
         // calculate distance for one sPath entry
                       // get edge from currentVert to column
         int currentToFringe = adjMat[currentVert][column];
                       // add distance from start
         int startToFringe = startToCurrent + currentToFringe;
                       // get distance of current sPath entry
         int sPathDist = sPath[column].distance;

         // compare distance from start with sPath entry
         if(startToFringe < sPathDist)   // if shorter,
            {                            // update sPath
            sPath[column].parentVert = currentVert;
            sPath[column].distance = startToFringe;
            }
         column++;
         }  // end while(column < nVerts)
    }
等sPath更新完毕后就是最小路径了

输出

Shortest paths
CurrentVert  1  distance  50
before begin sPath----------------
ParentVert/SelfVert  0  0   InTree  true   distance  1000000
ParentVert/SelfVert  0  1   InTree  true   distance  50
ParentVert/SelfVert  0  2   InTree  false   distance  1000000
ParentVert/SelfVert  0  3   InTree  false   distance  80
ParentVert/SelfVert  0  4   InTree  false   distance  1000000
before end sPath----------------
Start/Vert/column  0  1  2  distance  60  total undirect  110  sPathDist direct  1000000
2  changed
Start/Vert/column  0  1  3  distance  90  total undirect  140  sPathDist direct  80
Start/Vert/column  0  1  4  distance  1000000  total undirect  1000050  sPathDist direct  1000000
adjusted begin sPath----------------
ParentVert/SelfVert  0  0   InTree  true   distance  1000000
ParentVert/SelfVert  0  1   InTree  true   distance  50
ParentVert/SelfVert  1  2   InTree  false   distance  110
ParentVert/SelfVert  0  3   InTree  false   distance  80
ParentVert/SelfVert  0  4   InTree  false   distance  1000000
adjusted end sPath----------------
CurrentVert  3  distance  80
before begin sPath----------------
ParentVert/SelfVert  0  0   InTree  true   distance  1000000
ParentVert/SelfVert  0  1   InTree  true   distance  50
ParentVert/SelfVert  1  2   InTree  false   distance  110
ParentVert/SelfVert  0  3   InTree  true   distance  80
ParentVert/SelfVert  0  4   InTree  false   distance  1000000
before end sPath----------------
Start/Vert/column  0  3  2  distance  20  total undirect  100  sPathDist direct  110
2  changed
Start/Vert/column  0  3  4  distance  70  total undirect  150  sPathDist direct  1000000
4  changed
adjusted begin sPath----------------
ParentVert/SelfVert  0  0   InTree  true   distance  1000000
ParentVert/SelfVert  0  1   InTree  true   distance  50
ParentVert/SelfVert  3  2   InTree  false   distance  100
ParentVert/SelfVert  0  3   InTree  true   distance  80
ParentVert/SelfVert  3  4   InTree  false   distance  150
adjusted end sPath----------------
CurrentVert  2  distance  100
before begin sPath----------------
ParentVert/SelfVert  0  0   InTree  true   distance  1000000
ParentVert/SelfVert  0  1   InTree  true   distance  50
ParentVert/SelfVert  3  2   InTree  true   distance  100
ParentVert/SelfVert  0  3   InTree  true   distance  80
ParentVert/SelfVert  3  4   InTree  false   distance  150
before end sPath----------------
Start/Vert/column  0  2  4  distance  40  total undirect  140  sPathDist direct  150
4  changed
adjusted begin sPath----------------
ParentVert/SelfVert  0  0   InTree  true   distance  1000000
ParentVert/SelfVert  0  1   InTree  true   distance  50
ParentVert/SelfVert  3  2   InTree  true   distance  100
ParentVert/SelfVert  0  3   InTree  true   distance  80
ParentVert/SelfVert  2  4   InTree  false   distance  140
adjusted end sPath----------------
CurrentVert  4  distance  140
before begin sPath----------------
ParentVert/SelfVert  0  0   InTree  true   distance  1000000
ParentVert/SelfVert  0  1   InTree  true   distance  50
ParentVert/SelfVert  3  2   InTree  true   distance  100
ParentVert/SelfVert  0  3   InTree  true   distance  80
ParentVert/SelfVert  2  4   InTree  true   distance  140
before end sPath----------------
adjusted begin sPath----------------
ParentVert/SelfVert  0  0   InTree  true   distance  1000000
ParentVert/SelfVert  0  1   InTree  true   distance  50
ParentVert/SelfVert  3  2   InTree  true   distance  100
ParentVert/SelfVert  0  3   InTree  true   distance  80
ParentVert/SelfVert  2  4   InTree  true   distance  140
adjusted end sPath----------------
A=inf(A) B=50(A) C=100(D) D=80(A) E=140(C)

步骤总结:
1.选定一个顶点为根记做A
2.选择该顶点的最小边记做B,并记录这条边与A相交的顶点C,并标记入树C
3.计算C点到各顶点(不在树中的)的边的长度并与(A到各顶点的边)相比较,选择路径小者对A进行更新,并记录该顶点(以便排序顶点输出)
4.重复2-3步骤,等所有顶点都在树中时,则A到各顶点的最小路径更新完毕

这属于一个贪婪算法,总是先选最小的权值
终于搞懂了微笑 理解后,其实也不难.多看看中间步骤,一步到位很难理解

三.弗洛伊德(Floyed)算法求每一对顶点之间的最短路径的