E81086713E446D36F62B2AA2A3502B5EB155

          Java雜家

          雜七雜八。。。一家之言

          BlogJava 首頁 新隨筆 聯(lián)系 聚合 管理
            40 Posts :: 1 Stories :: 174 Comments :: 0 Trackbacks
          四 拓?fù)渑判?br /> 考慮一個任務(wù)安排的例子,比如有很多任務(wù)T1,T2,....
          這些任務(wù)又是相互關(guān)聯(lián)的,比如Tj完成前必須要求Ti已完成,這樣T1,T2....序列關(guān)于這樣的先決條件構(gòu)成一個圖,其中如果Ti必須要先于Tj完成,那么<Ti,Tj>就是該圖中的一條路徑,路徑長度為1的就是一條邊。
          拓?fù)渑判蚓褪前堰@些任務(wù)按照完成的先后順序排列出來。顯然,這樣的順序可能不是唯一的,比如Tk,Tl如果沒有在一條路徑上,那么他們之間的順序是任意的。
          拓?fù)渑判蛑辽儆袃煞N解法

          1)首先找出入度(連接到改點(diǎn)的邊的數(shù)目)為零的頂點(diǎn)放入隊(duì)列,然后依次遍歷這些頂點(diǎn),每次訪問到其中的一個頂點(diǎn)時,把該定點(diǎn)關(guān)聯(lián)到的其它頂點(diǎn)的邊移去,也就是使得關(guān)聯(lián)頂點(diǎn)的入度減1.如果減1后該定點(diǎn)入度也變?yōu)?了,那么把該定點(diǎn)加入隊(duì)列下次從他開始處理,直到?jīng)]有入度為0的定點(diǎn)了。
          這里要注意,如果給定的圖有回路那么,可能不會處理完所有頂點(diǎn)就退出了。

          實(shí)現(xiàn)如下:

          private final void calculateInDegrees(int[] inDegrees)
              {
                  Arrays.fill(inDegrees, 
          0);
                  
          for(int v=0;v<numVertexes;v++)
                  {
                      
          for(Edge e=firstEdge(v);isEdge(e);e=nextEdge(e))
                      {
                          inDegrees[toVertex(e)]
          ++;
                      }
                  }
              }
              
          /**
               * 
               * 
          @param sortedVertexes
               
          */
              
          public void topologySort(int[] sortedVertexes)
              {
                  
          //first calculate the inDegrees
                  int[] inDegrees=new int[numVertexes];
                  calculateInDegrees(inDegrees);
                  
                  Arrays.fill(visitTags, 
          false);
                  
                  _IntQueue queue
          =new _IntQueue();
                  
                  
          for(int v=0;v<numVertexes-1;v++)
                  {
                      
          if(inDegrees[v]==0)queue.add(v);
                  }
                  
                  
                  
          int index=0;
                  
          while(!queue.isEmpty())
                  {
                      
                      
          int from=queue.remove();
                      System.out.println(
          "visit:"+from);
                      sortedVertexes[index
          ++]=from;
                      
          for(Edge e=firstEdge(from);isEdge(e);e=nextEdge(e))
                      {
                          
                          
          if(--inDegrees[toVertex(e)]==0)
                          {
                              queue.add(toVertex(e));
                          }
                      }
                  }
                  
          if(index<numVertexes)
                  {
                      
          throw new IllegalArgumentException("There is a loop");
                  }
                  
              }
          這里一開始計(jì)算了各個頂點(diǎn)的入度,計(jì)算的時候,每條邊需要訪問一次。
          如果是相鄰矩陣的存儲方式,計(jì)算入度只需要計(jì)算每列的非零個數(shù)。
          一般也可以靜態(tài)的給出。

          2)借助于圖的深度優(yōu)先周游,每次在回退到改頂點(diǎn)的時候把該頂點(diǎn)送入結(jié)果數(shù)組。
          這樣得到的數(shù)組恰好就是拓?fù)渑判虻哪嫘颍驗(yàn)樽畹讓拥墓?jié)點(diǎn)是最先回退到的。
          實(shí)現(xiàn):
          /**
               * 
               * 
          @param sortedVertexes
               
          */
              
          public void topologySort_byDFS(int[] sortedVertexes)
              {
                  Arrays.fill(visitTags, 
          false);
                  
          int num=0;
                  
          for(int i=0;i<numVertexes;i++)
                  {
                      
          if(!visitTags[i])num=do_topsort(i,sortedVertexes,num);
                  }
                  
              }



              
          private final int do_topsort(int v, int[] sortedVertexes, int num) {
                  visitTags[v]
          =true;
                  
                  
          for(Edge e=firstEdge(v);isEdge(e);e=nextEdge(e))
                  {
                      
          if(!visitTags[toVertex(e)])num=do_topsort(toVertex(e),sortedVertexes,num);
                  }
                  num
          ++;
                  sortedVertexes[numVertexes
          -num]=v;
              
                  
                  
          return num;
              }



              
          /**
               * Given graph :
               * 
               * C1 → C3 ← C2
               * ↓    ↓    ↓
               * C8    C4   C5
               * ↓    ↓    ↓
               * C9 → C7 ← C6
               
          */
              
          public static void testTopologySort()
              {
                  DefaultGraph g
          =new DefaultGraph(9);
                  g.setEdge(
          010);
                  g.setEdge(
          210);
                  g.setEdge(
          030);
                  g.setEdge(
          140);
                  g.setEdge(
          250);
                  g.setEdge(
          360);
                  g.setEdge(
          470);
                  g.setEdge(
          580);
                  g.setEdge(
          670);
                  g.setEdge(
          870);
                  
                  
                  g.assignLabels(
          new String[]{"C1","C3","C2","C8","C4","C5","C9","C7","C6"});
                  
                  
          int[] sorted=new int[g.vertexesNum()];
          //        g.topologySort(sorted);
                  g.topologySort_byDFS(sorted);
                  System.out.println(
          "Topology Sort Result==============:");
                  
          for(int i=0;i<sorted.length;i++)System.out.print(g.getVertexLabel(sorted[i])+",");
                  System.out.println();
              }

          五 最短路徑問題

          最短路徑問題分兩類,一類是單源最短路徑問題,就是從指定頂點(diǎn)出發(fā)到其他各點(diǎn)的最短距離,還有一類是
          每兩個頂點(diǎn)之間的最短距離,當(dāng)然第二類也可以通過對每個頂點(diǎn)做一次單源最短路徑求解,但是還有一種更優(yōu)雅的方法(Floyd算法),這種方法一般使用相鄰矩陣的實(shí)現(xiàn)方式,對每個頂點(diǎn)看它是不是能作為其它沒兩對頂點(diǎn)間的直接中間節(jié)點(diǎn),如果能,那么再看是不是通過它的兩兩頂點(diǎn)的距離是不是減小了,若果是就更新這兩對頂點(diǎn)間的距離,這樣通過每次“貪婪的”找出局部最優(yōu)解來得到全局最優(yōu)解,可以算是一個動態(tài)規(guī)劃的解法。
          首先我們需要一個輔助類來保存距離,以及回溯路徑的類:
          public static class Dist implements Comparable<Dist>
              {
                  
          public int preV;
                  
          public int curV;
                  
          public int distance;
                  
                  
          public Dist(int v)
                  {
                      
          this.curV=v;
                      
          this.preV=-1;
                      
          this.distance=Integer.MAX_VALUE;
                  }
                  
              
                  @Override
                  
          public int compareTo(Dist other) {
                      
          return distance-other.distance;
                  }
                  
              }
          下面給出第二類最短路徑的解法(Floyd算法)Java實(shí)現(xiàn):
          @Override
              
          public void floyd(Dist[][] dists) {
                  
          for(int i=0;i<numVertexes;i++)
                  {
                      dists[i]
          =new Dist[numVertexes];
                      
          for(int j=0;j<numVertexes;j++)
                      {
                          dists[i][j]
          =new Dist(-1);//
                          dists[i][j].preV=-1;
                          
          if(i==j)
                              dists[i][j].distance
          =0;
                          
                          
          else
                             dists[i][j].distance
          =Integer.MAX_VALUE;
                          
                      }
                  }
                  
                  
          for(int v=0;v<numVertexes;v++)
                  {
                      
          for(Edge e=firstEdge(v);isEdge(e);e=nextEdge(e))
                      {
                          
          int to=toVertex(e);
                          dists[v][to].distance
          =e.getWeight();
                          dists[v][to].preV
          =v;
                      }
                  }
                  
                  
          for(int v=0;v<numVertexes;v++)
                  {
                      
          for(int i=0;i<numVertexes;i++)
                          
          for(int j=0;j<numVertexes;j++)
                          {
                              
                              
          if((dists[i][v].distance!=Integer.MAX_VALUE)&&(dists[v][j].distance!=Integer.MAX_VALUE)&&(dists[i][v].distance+dists[v][j].distance<dists[i][j].distance))
                              {
                                  dists[i][j].distance
          =dists[i][v].distance+dists[v][j].distance;
                                  dists[i][j].preV
          =v;
                              }
                          }
                  }
                  
              }

          /**
               * A Graph example
               * we mark the vertexes  with 0,1,2,.14 from left to right , up to down
               * S-8-B-4-A-2-C-7-D
               * |    |     |     |     |
               * 3    3     1     2     5
               * |    |     |     |     |
               * E-2-F-6-G-7-H-2-I
               * |    |     |     |     |
               * 6    1     1     1     2
               * |    |     |     |     |
               * J-5-K-1-L-3-M-3-T
               * 
               
          */
              
          public static void testFloyd() {
                  DefaultGraph g
          =new DefaultGraph(15);
                  g.setEdge(
          018);
                  g.setEdge(
          108);//its a undirected graph
                  g.setEdge(124);
                  g.setEdge(
          214);
                  g.setEdge(
          232);
                  g.setEdge(
          322);
                  g.setEdge(
          347);
                  g.setEdge(
          437);
                  
                  g.setEdge(
          053);
                  g.setEdge(
          503);
                  g.setEdge(
          163);
                  g.setEdge(
          613);
                  g.setEdge(
          271);
                  g.setEdge(
          721);
                  g.setEdge(
          382);
                  g.setEdge(
          832);
                  g.setEdge(
          495);
                  g.setEdge(
          945);
                  
                  
                  g.setEdge(
          562);
                  g.setEdge(
          652);
                  g.setEdge(
          676);
                  g.setEdge(
          766);
                  g.setEdge(
          787);
                  g.setEdge(
          877);
                  g.setEdge(
          892);
                  g.setEdge(
          982);
                  
                  
                  g.setEdge(
          1056);
                  g.setEdge(
          5106);
                  g.setEdge(
          1161);
                  g.setEdge(
          6111);
                  g.setEdge(
          1271);
                  g.setEdge(
          7121);
                  g.setEdge(
          1381);
                  g.setEdge(
          8131);
                  g.setEdge(
          1492);
                  g.setEdge(
          9142);
                  
                  g.setEdge(
          10115);
                  g.setEdge(
          11105);
                  g.setEdge(
          11121);
                  g.setEdge(
          12111);
                  g.setEdge(
          12133);
                  g.setEdge(
          13123);
                  g.setEdge(
          13143);
                  g.setEdge(
          14133);
                  
                  g.assignLabels(
          new String[]{"S","B","A","C","D","E","F","G","H","I","J","K","L","M","T"});
                  
                  Dist[][] dists
          =new Dist[15][15];
                  g.floyd(dists);
                  
                  System.out.println(
          "Shortes path from S-T ("+dists[0][14].distance+")is:");
                  Stack
          <String> stack=new Stack<String>();
                  
          int i=0;
                  
          int j=14;
                  
          while(j!=i)
                  {
                      
                      stack.push(g.getVertexLabel(j));
                      j
          =dists[i][j].preV;
                      
                  }
                  stack.push(g.getVertexLabel(i));
                  
          while(!stack.isEmpty())
                  {
                      System.out.print(stack.pop());
                      
          if(!stack.isEmpty())System.out.print("->");
                  }
                  System.out.println();
                  

              }



          單源最短路徑問題的解法有Dijstra提出,所以也叫Dijstra算法。
          它把頂點(diǎn)分為兩個集合一個是已求出最短距離的頂點(diǎn)集合V1,另一類是暫未求出的頂點(diǎn)集合V2,而可以證明下一個將求出來(V2中到出發(fā)點(diǎn)最短距離值最?。┑捻旤c(diǎn)的最短路徑上的頂點(diǎn)除了該頂點(diǎn)不在V1中外其余頂點(diǎn)都在V1中。

          如此,先把出發(fā)點(diǎn)放入V1中(出發(fā)點(diǎn)的最短距離當(dāng)然也就是0),然后每次選擇V2中到出發(fā)點(diǎn)距離最短的點(diǎn)加入V1,并把標(biāo)記改點(diǎn)的最短距離.直到V2中沒有頂點(diǎn)為止,詳細(xì)的形式化證明見:
          Dijstra算法證明

          這里的實(shí)現(xiàn)我們使用最小值堆來每次從V2中挑出最短距離。

          先給出最小值堆的實(shí)現(xiàn):
          package algorithms;

          import java.lang.reflect.Array;

          public class MinHeap<extends Comparable<E>>
          {
                  
                  
          private E[] values;
                  
          int len;
                  
                  
          public MinHeap(Class<E> clazz,int num)
                  {
                      
                      
          this.values=(E[])Array.newInstance(clazz,num);
                      len
          =0;
                  }
                      
                  
                  
          public final E removeMin()
                  {
                      E ret
          =values[0];
                      values[
          0]=values[--len];
                      shift_down(
          0);
                      
          return ret;
                  }
              
                  
                  
          //insert to tail
                  public final void insert(E val)
                  {
                      values[len
          ++]=val;
                      shift_up(len
          -1);
                      
                  }
                  
                  
          public final void rebuild()
                  {
                      
          int pos=(len-1)/2;
                      
          for(int i=pos;i>=0;i--)
                      {
                          shift_down(i);
                      }
                  }
                  
                  
          public final boolean isEmpty()
                  {
                      
          return len==0;
                  }
                  
                  
          /**
                   * When insert element we  need shiftUp
                   * 
          @param array
                   * 
          @param pos
                   
          */
                  
          private final void shift_up(int pos)
                  {
              
                      E tmp
          =values[pos];
                      
          int index=(pos-1)/2;
                      
          while(index>=0)
                      {
                          
          if(tmp.compareTo(values[index])<0)
                          {
                              values[pos]
          =values[index];
                              pos
          =index;
                              
          if(pos==0)break;
                              index
          =(pos-1)/2;
                          }
                          
          else break;
                      }
                      values[pos]
          =tmp;
                  }
                  
          private final void shift_down(int pos)
                  {
                      
                      E tmp
          =values[pos];
                      
          int index=pos*2+1;//use left child
                      while(index<len)//until no child
                      {
                          
          if(index+1<len&&values[index+1].compareTo(values[index])<0)//right child is smaller
                          {
                              index
          +=1;//switch to right child
                          }
                          
          if(tmp.compareTo(values[index])>0)
                          {
                              values[pos]
          =values[index];
                              pos
          =index;
                              index
          =pos*2+1;
                              
                          }
                          
          else
                          {
                              
          break;
                          }
                          
                      }
                      values[pos]
          =tmp;
                      
                              
                  }
              }
          下面是基于最小值堆的最短路勁算法以及一個測試方法:


              
          public void dijstra(int fromV,Dist[] dists)
              {
                  MinHeap
          <Dist> heap=new MinHeap<Dist>(Dist.class,numVertexes*2);
                  
                  
          for(int v=0;v<numVertexes;v++)
                  {
                      dists[v]
          =new Dist(v);
                  }
                  
                  Arrays.fill(visitTags, 
          false);
                  dists[fromV].distance
          =0;
                  dists[fromV].preV
          =-1;
                  heap.insert(dists[fromV]);
                  
          int num=0;
                  
                  
          while(num<numVertexes)
                  {
                      Dist dist
          =heap.removeMin();
                      
          if(visitTags[dist.curV])
                      {
                          
          continue;
                      }
                      visitTags[dist.curV]
          =true;
                      num
          ++;
                     
          for(Edge e=firstEdge(dist.curV);isEdge(e);e=nextEdge(e))
                      {
                          
          if(!visitTags[toVertex(e)]&&e.getWeight()+dist.distance<dists[toVertex(e)].distance)
                          {
                              
                              dists[toVertex(e)].distance
          =e.getWeight()+dist.distance;
                              dists[toVertex(e)].preV
          =dist.curV;
                              heap.insert(dists[toVertex(e)]);
                              
                          }
                      }
                      
                  }
                  
                  
              }


              
              
          /**
               * A Graph example
               * we mark the vertexes  with 0,1,2,.14 from left to right , up to down
               * S-8-B-4-A-2-C-7-D
               * |   |   |   |   |
               * 3   3   1   2   5
               * |   |   |   |   |
               * E-2-F-6-G-7-H-2-I
               * |   |   |   |   |
               * 6   1   1   1   2
               * |   |   |   |   |
               * J-5-K-1-L-3-M-3-T
               * 
               
          */
              
          public static void testDijstra()
              {
                  DefaultGraph g
          =new DefaultGraph(15);
                  g.setEdge(
          018);
                  g.setEdge(
          108);//its a undirected graph
                  g.setEdge(124);
                  g.setEdge(
          214);
                  g.setEdge(
          232);
                  g.setEdge(
          322);
                  g.setEdge(
          347);
                  g.setEdge(
          437);
                  
                  g.setEdge(
          053);
                  g.setEdge(
          503);
                  g.setEdge(
          163);
                  g.setEdge(
          613);
                  g.setEdge(
          271);
                  g.setEdge(
          721);
                  g.setEdge(
          382);
                  g.setEdge(
          832);
                  g.setEdge(
          495);
                  g.setEdge(
          945);
                  
                  
                  g.setEdge(
          562);
                  g.setEdge(
          652);
                  g.setEdge(
          676);
                  g.setEdge(
          766);
                  g.setEdge(
          787);
                  g.setEdge(
          877);
                  g.setEdge(
          892);
                  g.setEdge(
          982);
                  
                  
                  g.setEdge(
          1056);
                  g.setEdge(
          5106);
                  g.setEdge(
          1161);
                  g.setEdge(
          6111);
                  g.setEdge(
          1271);
                  g.setEdge(
          7121);
                  g.setEdge(
          1381);
                  g.setEdge(
          8131);
                  g.setEdge(
          1492);
                  g.setEdge(
          9142);
                  
                  g.setEdge(
          10115);
                  g.setEdge(
          11105);
                  g.setEdge(
          11121);
                  g.setEdge(
          12111);
                  g.setEdge(
          12133);
                  g.setEdge(
          13123);
                  g.setEdge(
          13143);
                  g.setEdge(
          14133);
                  
                  g.assignLabels(
          new String[]{"S","B","A","C","D","E","F","G","H","I","J","K","L","M","T"});
                  
                  Dist[] dists
          =new Dist[15];
                  g.dijstra(
          0, dists);
                  
                  System.out.println(
          "Shortes path from S-T ("+dists[14].distance+")is:");
                  Stack
          <String> stack=new Stack<String>();
                  
          for(int v=dists[14].curV;v!=-1;v=dists[v].preV)
                  {
                      stack.push(g.getVertexLabel(v));
                  
                  }
                  
          while(!stack.isEmpty())
                  {
                      System.out.print(stack.pop());
                      
          if(!stack.isEmpty())System.out.print("->");
                  }
                  System.out.println();
                  
                  
              }





          posted on 2007-12-14 21:00 DoubleH 閱讀(6420) 評論(1)  編輯  收藏 所屬分類: Memorandum

          Feedback

          # re: 圖及其算法復(fù)習(xí)(Java實(shí)現(xiàn)) 二:拓?fù)渑判颍疃搪窂絾栴}[未登錄] 2008-05-09 19:08 小米
          沒有圖解,不生動形象,不容易被新手和小蝦理解,可以在加一些圖解!  回復(fù)  更多評論
            

          主站蜘蛛池模板: 阜康市| 凭祥市| 百色市| 蚌埠市| 荆州市| 泰来县| 永寿县| 灵山县| 宜兰市| 武清区| 新乡市| 郓城县| 咸宁市| 聂拉木县| 南开区| 苏尼特右旗| 东阿县| 翁源县| 凭祥市| 和平县| 夏津县| 延寿县| 嘉峪关市| 四川省| 万宁市| 太康县| 松桃| 临泽县| 闽清县| 墨竹工卡县| 新宾| 平安县| 上虞市| 连南| 通城县| 白银市| 星子县| 德格县| 竹北市| 葵青区| 芒康县|