<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 73,  comments - 55,  trackbacks - 0
    /*
    ?*?原題如下:用1、2、2、3、4、6這六個數(shù)字,用java寫一個main函數(shù),打印出所有不同的排列,
    ?*?如:612234、412346等,要求:"4"不能在第三位,"3"與"6"不能相連.?
    ?*?
    ?*?1?把問題歸結為圖結構的遍歷問題。實際上6個數(shù)字就是六個結點,把六個結點連接成無向連通圖,對于每一個結點求這個圖形的遍歷路徑,
    ?*?所有結點的遍歷路徑就是最后對這6個數(shù)字的排列組合結果集。?
    ?*?2?顯然這個結果集還未達到題目的要求。從以下幾個方面考慮:?
    ?*?1.?3,6不能相連:實際要求這個連通圖的結點3,5之間不能連通,?可在構造圖結構時就滿足改條件,然后再遍歷圖。?
    ?*?2.?不能有重復:?考慮到有兩個2,明顯會存在重復結果,可以把結果集放在TreeSet中過濾重復結果?
    ?*?3.?4不能在第三位:?仍舊在結果集中去除滿足此條件的結果。
    ?
    */


    import ?java.util.Iterator;
    import ?java.util.TreeSet;

    public ? class ?Test? {

    ?
    private ?String[]?b? = ? new ?String[]? {? " 1 " ,? " 2 " ,? " 2 " ,? " 3 " ,? " 4 " ,? " 6 " ?} ;

    ?
    private ? int ?n? = ?b.length;

    ?
    private ? boolean []?visited? = ? new ? boolean [n];

    ?
    private ? int [][]?a? = ? new ? int [n][n];

    ?
    private ?String?result? = ? "" ;

    ?
    private ?TreeSet?set? = ? new ?TreeSet();

    ?
    public ? static ? void ?main(String[]?args)? {
    ??
    new ?Test().start();
    ?}


    ?
    private ? void ?start()? {

    ??
    // ?Initial?the?map?a[][]
    ?? for ?( int ?i? = ? 0 ;?i? < ?n;?i ++ )? {
    ???
    for ?( int ?j? = ? 0 ;?j? < ?n;?j ++ )? {
    ????
    if ?(i? == ?j)? {
    ?????a[i][j]?
    = ? 0 ;
    ????}
    ? else ? {
    ?????a[i][j]?
    = ? 1 ;
    ????}

    ???}

    ??}


    ??
    // ?3?and?5?can?not?be?the?neighbor.
    ??a[ 3 ][ 5 ]? = ? 0 ;
    ??a[
    5 ][ 3 ]? = ? 0 ;

    ??
    // ?Begin?to?depth?search.
    ?? for ?( int ?i? = ? 0 ;?i? < ?n;?i ++ )? {
    ???
    this .depthFirstSearch(i);
    ??}


    ??
    // ?Print?result?treeset.
    ??Iterator?it? = ?set.iterator();
    ??
    while ?(it.hasNext())? {
    ???String?string?
    = ?(String)?it.next();
    ???System.out.println(string);
    ??}

    ?}


    ?
    private ? void ?depthFirstSearch( int ?startIndex)? {
    ??visited[startIndex]?
    = ? true ;
    ??result?
    = ?result? + ?b[startIndex];
    ??
    if ?(result.length()? == ?n)? {
    // ???"4"?can?not?be?the?third?position.
    ??? if ?(result.indexOf( " 4 " )? != ? 2 )? {
    // ????Filt?the?duplicate?value.
    ????set.add(result);
    ???}

    ??}

    ??
    for ?( int ?j? = ? 0 ;?j? < ?n;?j ++ )? {
    ???
    if ?(a[startIndex][j]? == ? 1 ? && ?visited[j]? == ? false )? {
    ????depthFirstSearch(j);
    ???}

    ??}


    ??
    // ?restore?the?result?value?and?visited?value?after?listing?a?node.
    ??result? = ?result.substring( 0 ,?result.length()? - ? 1 );
    ??visited[startIndex]?
    = ? false ;
    ?}

    }


    只要這樣定義圖,根本不用在代碼中寫IF ELSE語句。
    實際上基于圖的算法好處在于,只要你能定義好滿足題目要求的圖結構,遍歷的結果就是你要的結果,不用任何對遍歷結果做任何處理。包括本題中的:4不能在第三位置,3,5不能相連,唯一性要求,其實都可以在體現(xiàn)在構造的圖形結構里,然后直接遍歷圖取得自己要的結果。而不用再次處理結果集。只是說這里實際上對其它要求要體現(xiàn)在圖結構里有困難(理論上是可以的),但起碼3,5不能相接是很好構造的,就是上面的代碼段來解釋的。

    關于圖形數(shù)據(jù)結構建議先看看數(shù)據(jù)結構的書,主要是將如何利用二維數(shù)組描述圖結構,再看看圖的深度遍歷實現(xiàn)原理。最后再應用到這個問題上來,自然就不難明白了。

    posted @ 2007-03-02 17:37 保爾任 閱讀(2380) | 評論 (0)編輯 收藏

    (轉自:http://chinavery.100steps.net/chengxuyuan/4759.html
    動態(tài)規(guī)劃是本書介紹的五種算法設計方法中難度最大的一種,它建立在最優(yōu)原則的基礎上。采用動態(tài)規(guī)劃方法,可以優(yōu)雅而高效地解決許多用貪婪算法或分而治之算法無法解決的問題。在介紹動態(tài)規(guī)劃的原理之后,本章將分別考察動態(tài)規(guī)劃方法在解決背包問題、圖象壓縮、矩陣乘法鏈、最短路徑、無交叉子集和元件折疊等方面的應用。

    3.1 算法思想

    和貪婪算法一樣,在動態(tài)規(guī)劃中,可將一個問題的解決方案視為一系列決策的結果。不同的是,在貪婪算法中,每采用一次貪婪準則便做出一個不可撤回的決策,而在動態(tài)規(guī)劃中,還要考察每個最優(yōu)決策序列中是否包含一個最優(yōu)子序列。

    例3-1 [最短路經] 考察圖1 2 - 2中的有向圖。假設要尋找一條從源節(jié)點s= 1到目的節(jié)點d= 5的最短路徑,即選擇此路徑所經過的各個節(jié)點。第一步可選擇節(jié)點2,3或4。假設選擇了節(jié)點3,則此時所要求解的問題變成:選擇一條從3到5的最短路徑。如果3到5的路徑不是最短的,則從1開始經過3和5的路徑也不會是最短的。例如,若選擇的子路徑(非最短路徑)是3,2,5 (耗費為9 ),則1到5的路徑為1,3,2,5 (耗費為11 ),這比選擇最短子路徑3,4,5而得到的1到5的路徑1,3,4,5 (耗費為9) 耗費更大。

    所以在最短路徑問題中,假如在的第一次決策時到達了某個節(jié)點v,那么不管v 是怎樣確定的,此后選擇從v 到d 的路徑時,都必須采用最優(yōu)策略。

    例3-2 [0/1背包問題] 考察1 3 . 4節(jié)的0 / 1背包問題。如前所述,在該問題中需要決定x1 .. xn的值。假設按i = 1,2,.,n 的次序來確定xi 的值。如果置x1 = 0,則問題轉變?yōu)橄鄬τ谄溆辔锲罚次锲?,3,.,n),背包容量仍為c 的背包問題。若置x1 = 1,問題就變?yōu)殛P于最大背包容量為c-w1 的問題。現(xiàn)設r?{c,c-w1 } 為剩余的背包容量。

    在第一次決策之后,剩下的問題便是考慮背包容量為r 時的決策。不管x1 是0或是1,[x2 ,.,xn ] 必須是第一次決策之后的一個最優(yōu)方案,如果不是,則會有一個更好的方案[y2,.,yn ],因而[x1,y2,.,yn ]是一個更好的方案。

    假設n=3, w=[100,14,10], p=[20,18,15], c= 11 6。若設x1 = 1,則在本次決策之后,可用的背包容量為r= 116-100=16 。[x2,x3 ]=[0,1] 符合容量限制的條件,所得值為1 5,但因為[x2,x3 ]= [1,0] 同樣符合容量條件且所得值為1 8,因此[x2,x3 ] = [ 0,1] 并非最優(yōu)策略。即x= [ 1,0,1] 可改進為x= [ 1,1,0 ]。若設x1 = 0,則對于剩下的兩種物品而言,容量限制條件為11 6??傊?,如果子問題的結果[x2,x3 ]不是剩余情況下的一個最優(yōu)解,則[x1,x2,x3 ]也不會是總體的最優(yōu)解。

    例3-3 [航費] 某航線價格表為:從亞特蘭大到紐約或芝加哥,或從洛杉磯到亞特蘭大的費用為$ 1 0 0;從芝加哥到紐約票價$ 2 0;而對于路經亞特蘭大的旅客,從亞特蘭大到芝加哥的費用僅為$ 2 0。從洛杉磯到紐約的航線涉及到對中轉機場的選擇。如果問題狀態(tài)的形式為(起點,終點),那么在選擇從洛杉磯到亞特蘭大后,問題的狀態(tài)變?yōu)椋▉喬靥m大,紐約)。從亞特蘭大到紐約的最便宜航線是從亞特蘭大直飛紐約,票價$ 1 0 0。而使用直飛方式時,從洛杉磯到紐約的花費為$ 2 0 0。不過,從洛杉磯到紐約的最便宜航線為洛杉磯-亞特蘭大-芝加哥-紐約,其總花費為$ 1 4 0(在處理局部最優(yōu)路徑亞特蘭大到紐約過程中選擇了最低花費的路徑:亞特蘭大-芝加哥-紐約)。

    如果用三維數(shù)組(t a g,起點,終點)表示問題狀態(tài),其中t a g為0表示轉飛, t a g為1表示其他情形,那么在到達亞特蘭大后,狀態(tài)的三維數(shù)組將變?yōu)椋?0,亞特蘭大,紐約),它對應的最優(yōu)路徑是經由芝加哥的那條路徑。

    當最優(yōu)決策序列中包含最優(yōu)決策子序列時,可建立動態(tài)規(guī)劃遞歸方程( d y n a m i c -programming recurrence equation),它可以幫助我們高效地解決問題。

    例3-4 [0/1背包] 在例3 - 2的0 / 1背包問題中,最優(yōu)決策序列由最優(yōu)決策子序列組成。假設f (i,y) 表示例1 5 - 2中剩余容量為y,剩余物品為i,i + 1,.,n 時的最優(yōu)解的值,即:和利用最優(yōu)序列由最優(yōu)子序列構成的結論,可得到f 的遞歸式。f ( 1 ,c) 是初始時背包問題的最優(yōu)解。可使用( 1 5 - 2)式通過遞歸或迭代來求解f ( 1 ,c)。從f (n, * )開始迭式, f (n, * )由(1 5 - 1)式得出,然后由( 1 5 - 2)式遞歸計算f (i,*) ( i=n- 1,n- 2,., 2 ),最后由( 1 5 - 2)式得出f ( 1 ,c)。

    對于例1 5 - 2,若0≤y<1 0,則f ( 3 ,y) = 0;若y≥1 0,f ( 3 ,y) = 1 5。利用遞歸式(1 5 - 2),可得f (2, y) = 0 ( 0≤y<10 );f(2,y)= 1 5(1 0≤y<1 4);f(2,y)= 1 8(1 4≤y<2 4)和f(2,y)= 3 3(y≥2 4)。因此最優(yōu)解f ( 1 , 11 6 ) = m a x {f(2,11 6),f(2,11 6 - w1)+ p1} = m a x {f(2,11 6),f(2,1 6)+ 2 0 } = m a x { 3 3,3 8 } = 3 8。

    現(xiàn)在計算xi 值,步驟如下:若f ( 1 ,c) =f ( 2 ,c),則x1 = 0,否則x1 = 1。接下來需從剩余容量c-w1中尋求最優(yōu)解,用f (2, c-w1) 表示最優(yōu)解。依此類推,可得到所有的xi (i= 1.n) 值。

    在該例中,可得出f ( 2 , 11 6 ) = 3 3≠f ( 1 , 11 6 ),所以x1 = 1。接著利用返回值3 8 -p1=18 計算x2 及x3,此時r = 11 6 -w1 = 1 6,又由f ( 2 , 1 6 ) = 1 8,得f ( 3 , 1 6 ) = 1 4≠f ( 2 , 1 6 ),因此x2 = 1,此時r= 1 6 -w2 = 2,所以f (3,2) =0,即得x3 = 0。

    動態(tài)規(guī)劃方法采用最優(yōu)原則( principle of optimality)來建立用于計算最優(yōu)解的遞歸式。所謂最優(yōu)原則即不管前面的策略如何,此后的決策必須是基于當前狀態(tài)(由上一次決策產生)的最優(yōu)決策。由于對于有些問題的某些遞歸式來說并不一定能保證最優(yōu)原則,因此在求解問題時有必要對它進行驗證。若不能保持最優(yōu)原則,則不可應用動態(tài)規(guī)劃方法。在得到最優(yōu)解的遞歸式之后,需要執(zhí)行回溯(t r a c e b a c k)以構造最優(yōu)解。

    編寫一個簡單的遞歸程序來求解動態(tài)規(guī)劃遞歸方程是一件很誘人的事。然而,正如我們將在下文看到的,如果不努力地去避免重復計算,遞歸程序的復雜性將非常可觀。如果在遞歸程序設計中解決了重復計算問題時,復雜性將急劇下降。動態(tài)規(guī)劃遞歸方程也可用迭代方式來求解,這時很自然地避免了重復計算。盡管迭代程序與避免重復計算的遞歸程序有相同的復雜性,但迭代程序不需要附加的遞歸??臻g,因此將比避免重復計算的遞歸程序更快。


    3.2 應用

    3.2.1 0/1背包問題

    1. 遞歸策略

    在例3 - 4中已建立了背包問題的動態(tài)規(guī)劃遞歸方程,求解遞歸式( 1 5 - 2)的一個很自然的方法便是使用程序1 5 - 1中的遞歸算法。該模塊假設p、w 和n 為輸入,且p 為整型,F(xiàn)(1,c) 返回f ( 1 ,c) 值。

    程序15-1 背包問題的遞歸函數(shù)

    int F(int i, int y)

    {// 返回f ( i , y ) .

    if (i == n) return (y < w[n]) ? 0 : p[n];

    if (y < w[i]) return F(i+1,y);

    return max(F(i+1,y), F(i+1,y-w[i]) + p[i]);

    }

    程序1 5 - 1的時間復雜性t (n)滿足:t ( 1 ) =a;t(n)≤2t(n- 1)+b(n>1),其中a、b 為常數(shù)。通過求解可得t (n) =O( 2n)。

    例3-5 設n= 5,p= [ 6 , 3 , 5 , 4 , 6 ],w=[2,2,6,5,4] 且c= 1 0 ,求f ( 1 , 1 0 )。為了確定f ( 1 , 1 0 ),調用函數(shù)F ( 1 , 1 0 )。遞歸調用的關系如圖1 5 - 1的樹型結構所示。每個節(jié)點用y值來標記。對于第j層的節(jié)點有i=j,因此根節(jié)點表示F ( 1 , 1 0 ),而它有左孩子和右孩子,分別對應F ( 2 , 1 0 )和F ( 2 , 8 )??偣矆?zhí)行了2 8次遞歸調用。但我們注意到,其中可能含有重復前面工作的節(jié)點,如f ( 3 , 8 )計算過兩次,相同情況的還有f ( 4 , 8 )、f ( 4 , 6 )、f ( 4 , 2 )、f ( 5 , 8 )、f ( 5 , 6 )、f ( 5 , 3 )、f (5,2) 和f ( 5 , 1 )。如果保留以前的計算結果,則可將節(jié)點數(shù)減至1 9,因為可以丟棄圖中的陰影節(jié)點。

    正如在例3 - 5中所看到的,程序1 5 - 1做了一些不必要的工作。為了避免f (i,y)的重復計算,必須定義一個用于保留已被計算出的f (i,y)值的表格L,該表格的元素是三元組(i,y,f (i,y) )。在計算每一個f (i,y)之前,應檢查表L中是否已包含一個三元組(i,y, * ),其中*表示任意值。如果已包含,則從該表中取出f (i,y)的值,否則,對f (i,y)進行計算并將計算所得的三元組(i,y,f (i,y) )加入表L。L既可以用散列(見7 . 4節(jié))的形式存儲,也可用二叉搜索樹(見11章)的形式存儲。

    2. 權為整數(shù)的迭代方法

    當權為整數(shù)時,可設計一個相當簡單的算法(見程序1 5 - 2)來求解f ( 1 ,c)。該算法基于例3 - 4所給出的策略,因此每個f (i,y) 只計算一次。程序1 5 - 2用二維數(shù)組f [ ][ ]來保存各f 的值。而回溯函數(shù)Tr a c e b a c k用于確定由程序1 5 - 2所產生的xi 值。函數(shù)K n a p s a c k的復雜性為( n c),而Tr a c e b a c k的復雜性為( n )。

    程序15-2 f 和x 的迭代計算

    template<class T>

    void Knapsack(T p[], int w[], int c, int n, T** f)

    {// 對于所有i和y計算f [ i ] [ y ]

    // 初始化f [ n ] [ ]

    for (int y = 0; y <= yMax; y++)

    f[n][y] = 0;

    for (int y = w[n]; y <= c; y++)

    f[n][y] = p[n];

    // 計算剩下的f

    for (int i = n - 1; i > 1; i--) {

    for (int y = 0; y <= yMax; y++)

    f[i][y] = f[i+1][y];

    for (int y = w[i]; y <= c; y++)

    f[i][y] = max(f[i+1][y], f[i+1][y-w[i]] + p[i]);

    }

    f[1][c] = f[2][c];

    if (c >= w[1])

    f[1][c] = max(f[1][c], f[2][c-w[1]] + p[1]);

    }

    template<class T>

    void Traceback(T **f, int w[], int c, int n, int x[])

    {// 計算x

    for (int i = 1; i < n; i++)

    if (f[i][c] == f[i+1][c]) x[i] = 0;

    else {x[i] = 1;

    c -= w[i];}

    x[n] = (f[n][c]) ? 1 : 0;

    }

    3. 元組方法( 選讀)

    程序1 5 - 2有兩個缺點:1) 要求權為整數(shù);2) 當背包容量c 很大時,程序1 5 - 2的速度慢于程序1 5 - 1。一般情況下,若c>2n,程序1 5 - 2的復雜性為W (n2n )??衫迷M的方法來克服上述兩個缺點。在元組方法中,對于每個i,f (i, y) 都以數(shù)對(y, f (i, y)) 的形式按y的遞增次序存儲于表P(i)中。同時,由于f (i, y) 是y 的非遞減函數(shù),因此P(i) 中各數(shù)對(y, f (i, y)) 也是按f (i, y) 的遞增次序排列的。

    例3-6 條件同例3 - 5。對f 的計算如圖1 5 - 2所示。當i= 5時,f 由數(shù)對集合P( 5 ) = [ ( 0 , 0 ) , ( 4 , 6 ) ]表示。而P( 4 )、P( 3 )和P( 2 )分別為[ ( 0 , 0 ) , ( 4 , 6 ) , ( 9 , 1 0 ) ]、[ ( 0 , 0 ) ( 4 , 6 ) , ( 9 , 1 0 ) , ( 1 0 , 11)] 和[ ( 0 , 0 ) ( 2 , 3 ) ( 4 , 6 ) ( 6 , 9 ) ( 9 , 1 0 ) ( 1 0 , 11 ) ]。

    為求f ( 1 , 1 0 ),利用式(1 5 - 2)得f ( 1 , 1 0 ) = m a x{f ( 2 , 1 0 ),f ( 2 , 8 ) + p 1}。由P( 2 )得f ( 2 , 1 0 ) = 11、f (2,8)=9 (f ( 2 , 8 ) = 9來自數(shù)對( 6,9 ) ),因此f ( 1 , 1 0 ) = m a x{11 , 1 5}= 1 5?,F(xiàn)在來求xi 的值,因為f ( 1 , 1 0 ) =f ( 2 , 6 ) +p1,所以x1 = 1;由f ( 2 , 6 ) =f ( 3 , 6 - w 2 ) +p2 =f ( 3 , 4 ) +p2,得x2 = 1;由f ( 3 , 4 ) =f ( 4 , 4 ) =f ( 5 , 4 )得x3=x4 = 0;最后,因f ( 5 , 4 )≠0得x5= 1。

    檢查每個P(i) 中的數(shù)對,可以發(fā)現(xiàn)每對(y,f (i,y)) 對應于變量xi , ., xn 的0/1 賦值的不同組合。設(a,b)和(c,d)是對應于兩組不同xi , ., xn 的0 / 1賦值,若a≥c且b<d,則(a, b) 受(b, c) 支配。被支配者不必加入P(i)中。若在相同的數(shù)對中有兩個或更多的賦值,則只有一個放入P(i)。假設wn≤C,P(n)=[(0,0), (wn , pn ) ],P(n)中對應于xn 的兩個數(shù)對分別等于0和1。對于每個i,P(i)可由P(i+ 1 )得出。首先,要計算數(shù)對的有序集合Q,使得當且僅當wi≤s≤c且(s-wi , t-pi )為P(i+1) 中的一個數(shù)對時,(s,t)為Q中的一個數(shù)對。現(xiàn)在Q中包含xi = 1時的數(shù)對集,而P(i+ 1 )對應于xi = 0的數(shù)對集。接下來,合并Q和P(i+ 1 )并刪除受支配者和重復值即可得到P(i)。

    例3-7 各數(shù)據(jù)同例1 5 - 6。P(5)=[(0,0),(4,6)], 因此Q= [ ( 5 , 4 ) , ( 9 , 1 0 ) ]?,F(xiàn)在要將P( 5 )和Q合并得到P( 4 )。因( 5 , 4 )受( 4 , 6 )支配,可刪除( 5 , 4 ),所以P(4)=[(0,0), (4,6), (9,10)]。接著計算P( 3 ),首先由P( 4 )得Q=[(6,5), (10,11 ) ],然后又由合并方法得P(3)=[(0,0), (4,6), (9,10), (10,11 ) ]。最后計算P( 2 ):由P( 3 )得Q= [ ( 2 , 3 ),( 6 , 9 ) ],P( 3 )與Q合并得P(2)=[(0,0), (2,3), (4,6), (6,9), (9,10). (10,11 ) ]。因為每個P(i) 中的數(shù)對對應于xi , ., xn 的不同0 / 1賦值,因此P(i) 中的數(shù)對不會超過2n-i+ 1個。計算P(i) 時,計算Q需消耗( |P(i+ 1 ) |)的時間,合并P(i+1) 和Q同樣需要( |P(i+ 1 ) | )的時間。計算所有P(i) 時所需要的總時間為: (n ?i=2|P(i + 1)|= O ( 2n )。當權為整數(shù)時,|P(i) |≤c+1, 此時復雜性為O ( m i n {n c, 2n } )。

    如6 . 4 . 3節(jié)定義的,數(shù)字化圖像是m×m的像素陣列。假定每個像素有一個0 ~ 2 5 5的灰度值。因此存儲一個像素至多需8位。若每個像素存儲都用最大位8位,則總的存儲空間為8m2 位。為了減少存儲空間,我們將采用變長模式( variable bit scheme),即不同像素用不同位數(shù)來存儲。像素值為0和1時只需1位存儲空間;值2、3各需2位;值4,5,6和7各需3位;以此類推,使用變長模式的步驟如下:

    1) 圖像線性化根據(jù)圖15-3a 中的折線將m×m維圖像轉換為1×m2 維矩陣。

    2) 分段將像素組分成若干個段,分段原則是:每段中的像素位數(shù)相同。每個段是相鄰像素的集合且每段最多含2 5 6個像素,因此,若相同位數(shù)的像素超過2 5 6個的話,則用兩個以上的段表示。

    3) 創(chuàng)建文件創(chuàng)建三個文件:S e g m e n t L e n g t h, BitsPerPixel 和P i x e l s。第一個文件包含在2 )中所建的段的長度(減1 ),文件中各項均為8位長。文件BitsPerPixel 給出了各段中每個像素的存儲位數(shù)(減1),文件中各項均為3位。文件Pixels 則是以變長格式存儲的像素的二進制串。

    4) 壓縮文件壓縮在3) 中所建立的文件,以減少空間需求。

    上述壓縮方法的效率(用所得壓縮率表示)很大程度上取決于長段的出現(xiàn)頻率。

    例3-8 考察圖15-3b 的4×4圖像。按照蛇形的行主次序,灰度值依次為1 0,9,1 2,4 0,5 0,3 5,1 5,1 2,8,1 0,9,1 5,11,1 3 0,1 6 0和2 4 0。各像素所需的位數(shù)分別為4,4,4,6,6,6,4,4,4,4,4,4,4,8,8和8,按等長的條件將像素分段,可以得到4個段[ 1 0,9,1 2 ]、[ 4 0,5 0,3 5 ]、[15, 12, 8, 10, 9, 15, 11] 和[130, 160, 240]。因此,文件SegmentLength 為2,2,6,2;文件BitsPerSegment 的內容為3,5,3,7;文件P i x e l s包含了按蛇形行主次序排列的1 6個灰度值,其中頭三個各用4位存儲,接下來三個各用6位,再接下來的七個各用4位,最后三個各用8位存儲。因此存儲單元中前3 0位存儲了前六個像素:

    1010 1001 1100 111000 110010 100011

    這三個文件需要的存儲空間分別為:文件SegmentLength 需3 2位;BitsPerSegment 需1 2位;Pixels 需8 2位,共需1 2 6位。而如果每個像素都用8位存儲,則存儲空間需8×1 6 = 1 2 8位,因而在本例圖像中,節(jié)省了2位的空間。

    假設在2) 之后,產生了n 個段。段標題(segment header)用于存儲段的長度以及該段中每個像素所占用的位數(shù)。每個段標題需11位。現(xiàn)假設li 和bi 分別表示第i 段的段長和該段每個像素的長度,則存儲第i 段像素所需要的空間為li *bi 。在2) 中所得的三個文件的總存儲空間為11 n+n ?i = 1li bi。可通過將某些相鄰段合并的方式來減少空間消耗。如當段i 和i+ 1被合并時,合并后的段長應為li +li + 1。此時每個像素的存儲位數(shù)為m a x {bi,bi +1 } 位。盡管這種技術增加了文件P i x e l s的空間消耗,但同時也減少了一個段標題的空間。

    例3-9 如果將例1 5 - 8中的第1段和第2段合并,合并后,文件S e g m e n t L e n g t h變?yōu)?,6,2,BitsPerSegment 變?yōu)?,3,7。而文件Pixels 的前3 6位存儲的是合并后的第一段:001010 001001 001100 111000 110010 100011其余的像素(例1 5 - 8第3段)沒有改變。因為減少了1個段標題,文件S e g m e n t L e n g t h和BitsPerPixel 的空間消耗共減少了11位,而文件Pixels 的空間增加6位,因此總共節(jié)約的空間為5位,空間總消耗為1 2 1位。

    我們希望能設計一種算法,使得在產生n 個段之后,能對相鄰段進行合并,以便產生一個具有最小空間需求的新的段集合。在合并相鄰段之后,可利用諸如L Z W法(見7 . 5節(jié))和霍夫曼編碼(見9 . 5 . 3節(jié))等其他技術來進一步壓縮這三個文件。

    令sq 為前q 個段的最優(yōu)合并所需要的空間。定義s0 = 0。考慮第i 段(i>0 ),假如在最優(yōu)合并C中,第i 段與第i- 1,i- 2,.,i-r+1 段相合并,而不包括第i-r 段。合并C所需要的空間消耗等于:第1段到第i-r 段所需空間+ l s u m (i-r+ 1 ,i) * b m a x (i-r+ 1 ,i) + 11

    其中l(wèi) s u m(a, b)=b ?j =a

    lj,bmax (a, b)= m a x {ba , ..., bb }。假如在C中第1段到第i-r 段的合并不是最優(yōu)合并,那么需要對合并進行修改,以使其具有更小的空間需求。因此還必須對段1到段i-r 進行最優(yōu)合并,也即保證最優(yōu)原則得以維持。故C的空間消耗為:

    si = si-r +l s u m(i-r+1, i)*b m a x(i-r+1, i)+ 11

    r 的值介于1到i 之間,其中要求l s u m不超過2 5 6 (因為段長限制在2 5 6之內)。盡管我們不知道如何選擇r,但我們知道,由于C具有最小的空間需求,因此在所有選擇中, r 必須產生最小的空間需求。

    假定k a yi 表示取得最小值時k 的值,sn 為n 段的最優(yōu)合并所需要的空間,因而一個最優(yōu)合并可用kay 的值構造出來。

    例3-10 假定在2) 中得到五個段,它們的長度為[ 6,3,1 0,2,3 ],像素位數(shù)為[ 1,2,3,2,1 ],要用公式(1 5 - 3)計算sn,必須先求出sn-1,.,s0 的值。s0 為0,現(xiàn)計算s1:s1 =s0 +l1 *b1+ 11 = 1 7k a y1 = 1s2 由下式得出:

    s2 = m i n {s1 +l2 b2 , s0 + (l1 +l2 ) * m a x {b1 , b2} } + 11 = m i n { 1 7 + 6 , 0 + 9 * 2 } + 11 = 2 9

    k a y2 = 2

    以此類推,可得s1.s5 = [ 1 7,2 9,6 7,7 3,82] ,k a y1.k a y5 = [ 1,2,2,3,4 ]。因為s5 = 8 2,所以最優(yōu)空間合并需8 2位的空間。可由k a y5 導出本合并的方式,過程如下:因為k a y5 = 4,所以s5 是由公式(1 5 - 3)在k=4 時取得的,因而最優(yōu)合并包括:段1到段( 5 - 4 ) = 1的最優(yōu)合并以及段2,3,4和5的合并。最后僅剩下兩個段:段1以及段2到段5的合并段。

    1. 遞歸方法

    用遞歸式(1 5 - 3)可以遞歸地算出si 和k a yi。程序1 5 - 3為遞歸式的計算代碼。l,b,和k a y是一維的全局整型數(shù)組,L是段長限制( 2 5 6),h e a d e r為段標題所需的空間( 11 )。調用S ( n )返回sn 的值且同時得出k a y值。調用Tr a c e b a c k ( k a y, n )可得到最優(yōu)合并。

    現(xiàn)討論程序1 5 - 3的復雜性。t( 0 ) =c(c 為一個常數(shù)): (n>0),因此利用遞歸的方法可得t (n) = O ( 2n )。Tr a c e b a c k的復雜性為(n)。

    程序15-3 遞歸計算s , k a y及最優(yōu)合并

    int S(int i)

    { / /返回S ( i )并計算k a y [ i ]

    if (i == 0 ) return 0;

    //k = 1時, 根據(jù)公式( 1 5 - 3)計算最小值

    int lsum = l[i],bmax = b[i];

    int s = S(i-1) + lsum * bmax;

    kay[i] = 1;

    / /對其余的k計算最小值并求取最小值

    for (int k = 2; k <= i && lsum+l[i-k+1] <= L; k++) {

    lsum += l[i-k+1];

    if (bmax < b[i-k+1]) bmax = b[i-k+1];

    int t = S(i-k);

    if (s > t + lsum * bmax) {

    s = t + lsum * bmax;

    kay[i] = k;}

    }

    return s + header;

    }

    void Traceback(int kay[], int n)

    {// 合并段

    if (n == 0) return;

    Tr a c e b a c k ( k a y, n-kay[n]);

    cout << "New segment begins at " << (n - kay[n] + 1) << endl;

    }

    2. 無重復計算的遞歸方法

    通過避免重復計算si,可將函數(shù)S的復雜性減少到(n)。注意這里只有n個不同的si。

    例3 - 11 再考察例1 5 - 1 0中五個段的例子。當計算s5 時,先通過遞歸調用來計算s4,.,s0。計算s4 時,通過遞歸調用計算s3,.,s0,因此s4 只計算了一次,而s3 計算了兩次,每一次計算s3要計算一次s2,因此s2 共計算了四次,而s1 重復計算了1 6次!可利用一個數(shù)組s 來保存先前計算過的si 以避免重復計算。改進后的代碼見程序1 5 - 4,其中s為初值為0的全局整型數(shù)組。

    程序15-4 避免重復計算的遞歸算法

    int S(int i)

    { / /計算S ( i )和k a y [ i ]

    / /避免重復計算

    if (i == 0) return 0;

    if (s[i] > 0) return s[i]; //已計算完

    / /計算s [ i ]

    / /首先根據(jù)公式(1 5 - 3)計算k = 1時最小值

    int lsum = l[i], bmax = b[i];

    s[i] =S(i-1) + lsum * bmax;

    kay[i] = 1;

    / /對其余的k計算最小值并更新

    for (int k = 2; k <= i && lsum+l[i-k+1] <= L; k++) {

    lsum += l[i-k+1];

    if (bmax < b[i-k+1]) bmax = b[i-k+1];

    int t = S(i-k);

    if (s[i] > t + lsum * bmax) {

    s[i] = t + lsum * bmax;

    kay[i] = k;}

    }

    s[i] += header;

    return s[i];

    }

    為了確定程序1 5 - 4的時間復雜性,我們將使用分期計算模式( amortization scheme)。在該模式中,總時間被分解為若干個不同項,通過計算各項的時間然后求和來獲得總時間。當計算si 時,若sj 還未算出,則把調用S(j) 的消耗計入sj ;若sj 已算出,則把S(j) 的消耗計入si (這里sj依次把計算新sq 的消耗轉移至每個sq )。程序1 5 - 4的其他消耗也被計入si。因為L是2 5 6之內的常數(shù)且每個li 至少為1,所以程序1 5 - 4的其他消耗為( 1 ),即計入每個si 的量是一個常數(shù),且si 數(shù)目為n,因而總工作量為(n)。

    3. 迭代方法

    倘若用式(1 5 - 3)依序計算s1 , ., sn,便可得到一個復雜性為(n)的迭代方法。在該方法中,在si 計算之前, sj 必須已計算好。該方法的代碼見程序1 5 - 5,其中仍利用函數(shù)Tr a c e b a c k(見程序1 5 - 3)來獲得最優(yōu)合并。

    程序15-5 迭代計算s和k a y

    void Vbits (int l[], int b[], int n, int s[], int kay[])

    { / /計算s [ i ]和k a y [ i ]

    int L = 256, header = 11 ;

    s[0] = 0;

    / /根據(jù)式(1 5 - 3)計算s [ i ]

    for (int i = 1; i <= n; i++) {

    // k = 1時,計算最小值

    int lsum = l,

    bmax = b[i];

    s[i] = s[i-1] + lsum * bmax;

    kay[i] = 1;

    / /對其余的k計算最小值并更新

    for (int k=2; k<= i && lsum+l[i-k+1]<= L; k++) {

    lsum += l[i-k+1];

    if (bmax < b[i-k+1]) bmax = b[i-k+1];

    if (s[i] > s[i-k] + lsum * bmax){

    s[i] = s[i-k] + lsum * bmax;

    kay[i] = k; }

    }

    s[i] += header;

    }

    }


    3.2.3 矩陣乘法鏈

    m×n矩陣A與n×p矩陣B相乘需耗費(m n p)的時間(見第2章練習1 6)。我們把m n p作為兩個矩陣相乘所需時間的測量值?,F(xiàn)假定要計算三個矩陣A、B和C的乘積,有兩種方式計算此乘積。在第一種方式中,先用A乘以B得到矩陣D,然后D乘以C得到最終結果,這種乘法的順序可寫為(A*B) *C。第二種方式寫為A* (B*C) ,道理同上。盡管這兩種不同的計算順序所得的結果相同,但時間消耗會有很大的差距。

    例3-12 假定A為1 0 0×1矩陣,B為1×1 0 0矩陣,C為1 0 0×1矩陣,則A*B的時間耗費為10 0 0 0,得到的結果D為1 0 0×1 0 0矩陣,再與C相乘所需的時間耗費為1 000 000,因此計算(A*B) *C的總時間為1 010 000。B*C的時間耗費為10 000,得到的中間矩陣為1×1矩陣,再與A相乘的時間消耗為1 0 0,因而計算A*(B*C)的時間耗費竟只有10 100!而且,計算( A*B)*C時,還需10 000個單元來存儲A*B,而A*(B*C)計算過程中,只需用1個單元來存儲B*C。

    下面舉一個得益于選擇合適秩序計算A*B*C矩陣的實例:考慮兩個3維圖像的匹配。圖像匹配問題的要求是,確定一個圖像需旋轉、平移和縮放多少次才能逼近另一個圖像。實現(xiàn)匹配的方法之一便是執(zhí)行約1 0 0次迭代計算,每次迭代需計算1 2×1個向量T:

    T=?A(x, y, z) *B(x, y, z)*C(x, y, z )

    其中A,B和C分別為1 2×3,3×3和3×1矩陣。(x , y, z) 為矩陣中向量的坐標。設t 表示計算A(x , y, z) *B(x , y, z) *C(x , y, z)的計算量。假定此圖像含2 5 6×2 5 6×2 5 6個向量,在此條件中,這1 0 0個迭代所需的總計算量近似為1 0 0 * 2 5 63 * t≈1 . 7 * 1 09 t。若三個矩陣是按由左向右的順序相乘的,則t = 1 2 * 3 * 3 + 1 2 * 3 *1= 1 4 4;但如果從右向左相乘, t = 3 * 3 * 1 + 1 2 * 3 * 1 = 4 5。由左至右計算約需2 . 4 * 1 011個操作,而由右至左計算大概只需7 . 5 * 1 01 0個操作。假如使用一個每秒可執(zhí)行1億次操作的計算機,由左至右需4 0分鐘,而由右至左只需1 2 . 5分鐘。

    在計算矩陣運算A*B*C時,僅有兩種乘法順序(由左至右或由右至左),所以可以很容易算出每種順序所需要的操作數(shù),并選擇操作數(shù)比較少的那種乘法順序。但對于更多矩陣相乘來說,情況要復雜得多。如計算矩陣乘積M1×M2×.×Mq,其中Mi 是一個ri×ri + 1 矩陣( 1≤i≤q)。不妨考慮q=4 的情況,此時矩陣運算A*B*C*D可按以下方式(順序)計算:

    A* ( (B*C) *D) A* (B* (C*D)) (A*B) * (C*D) (A* (B*C) ) *D

    不難看出計算的方法數(shù)會隨q 以指數(shù)級增加。因此,對于很大的q 來說,考慮每一種計算順序并選擇最優(yōu)者已是不切實際的。

    現(xiàn)在要介紹一種采用動態(tài)規(guī)劃方法獲得矩陣乘法次序的最優(yōu)策略。這種方法可將算法的時間消耗降為(q3 )。用Mi j 表示鏈Mi×.×Mj (i≤j)的乘積。設c(i,j) 為用最優(yōu)法計算Mi j 的消耗,k a y(i, j) 為用最優(yōu)法計算Mi j 的最后一步Mi k×Mk+1, j 的消耗。因此Mij 的最優(yōu)算法包括如何用最優(yōu)算法計算Mik 和Mkj 以及計算Mik×Mkj 。根據(jù)最優(yōu)原理,可得到如下的動態(tài)規(guī)劃遞歸式:k a y(i,i+s)= 獲得上述最小值的k. 以上求c 的遞歸式可用遞歸或迭代的方法來求解。c( 1,q) 為用最優(yōu)法計算矩陣鏈的消耗,k a y( 1 ,q) 為最后一步的消耗。其余的乘積可由k a y值來確定。

    1. 遞歸方法

    與求解0 / 1背包及圖像壓縮問題一樣,本遞歸方法也須避免重復計算c (i, j) 和k a y(i, j),否則算法的復雜性將會非常高。

    例3-13 設q= 5和r =(1 0 , 5 , 1 , 1 0 , 2 , 1 0),式中待求的c 中有四個c的s= 0或1,因此用動態(tài)規(guī)劃方法可立即求得它們的值: c( 1 , 1 ) =c( 5 , 5 ) = 0 ;c(1,2)=50; c( 4 , 5 ) = 2 0 0。現(xiàn)計算C( 2,5 ):c( 2 , 5 ) = m i n {c( 2 , 2 ) +c(3,5)+50, c( 2 , 3 ) +c(4,5)+500, c( 2 , 4 ) +c( 5 , 5 ) + 1 0 0 } (1 5 - 5)其中c( 2 , 2 ) =c( 5 , 5 ) = 0;c( 2 , 3 ) = 5 0;c(4,5)=200 。再用遞歸式計算c( 3 , 5 )及c( 2 , 4 ) :c( 3 , 5 ) = m i n {c( 3 , 3 ) +c(4,5)+100, c( 3 , 4 ) +c( 5 , 5 ) + 2 0 } = m i n { 0 + 2 0 0 + 1 0 0 , 2 0 + 0 + 2 0 } = 4 0c( 2 , 4 ) = m i n {c( 2 , 2 ) +c( 3 , 4 ) + 1 0 ,c( 2 , 3 ) +c( 4 , 4 ) + 1 0 0 } = m i n { 0 + 2 0 + 1 0 , 5 0 + 1 0 + 2 0 } = 3 0由以上計算還可得k a y( 3 , 5 ) = 4,k ay( 2 , 4 ) = 2。現(xiàn)在,計算c(2,5) 所需的所有中間值都已求得,將它們代入式(1 5 - 5)得:

    c(2,5)=min{0+40+50, 50+200+500, 30+0+100}=90且k a y( 2 , 5 ) = 2

    再用式(1 5 - 4)計算c( 1 , 5 ),在此之前必須算出c( 3 , 5 )、c(1,3) 和c( 1 , 4 )。同上述過程,亦可計算出它們的值分別為4 0、1 5 0和9 0,相應的k a y 值分別為4、2和2。代入式(1 5 - 4)得:

    c(1,5)=min{0+90+500, 50+40+100, 150+200+1000, 90+0+200}=190且k a y( 1 , 5 ) = 2

    此最優(yōu)乘法算法的消耗為1 9 0,由k a y(1,5) 值可推出該算法的最后一步, k a y(1,5) 等于2,因此最后一步為M1 2×M3 5,而M12 和M35 都是用最優(yōu)法計算而來。由k a y( 1 , 2 ) = 1知M12 等于M11×M2 2,同理由k a y( 3 , 5) = 4得知M35 由M3 4×M55 算出。依此類推,M34 由M3 3×M44 得出。因而此最優(yōu)乘法算法的步驟為:

    M11×M2 2 = M1 2

    M3 3×M4 4 = M3 4

    M3 4×M5 5 = M3 5

    M1 2×M3 5 = M1 5

    計算c(i, j) 和k a y (i, j) 的遞歸代碼見程序1 5 - 6。在函數(shù)C中,r 為全局一維數(shù)組變量, k a y是全局二維數(shù)組變量,函數(shù)C返回c(i j) 之值且置k a y [a] [b] =k ay (a , b) (對于任何a , b),其中c(a , b)在計算c(i,j) 時皆已算出。函數(shù)Traceback 利用函數(shù)C中已算出的k a y值來推導出最優(yōu)乘法算法的步驟。

    設t(q)為函數(shù)C的復雜性,其中q=j-i+ 1(即Mij 是q個矩陣運算的結果)。當q為1或2時,t(q) =d,其中d 為一常數(shù);而q> 2時,t (q)=2q-1?k = 1t (k ) +e q,其中e 是一個常量。因此當q>2時,t(q)>2t (q- 1 ) +e,所以t (q)= W ( 2q)。函數(shù)Traceback 的復雜性為(q)。

    程序15-6 遞歸計算c (i, j) 和kay (i, j)

    int C(int i, int j)

    { / /返回c(i,j) 且計算k(i,j) = kay[i][j]

    if (i==j) return 0; //一個矩陣的情形

    if (i == j-1) { //兩個矩陣的情形

    kay[i][i+1] = i;

    return r[i]*r[i+1]*r[r+2];}

    / /多于兩個矩陣的情形

    / /設u為k = i 時的最小值

    int u = C(i,i) + C(i+1,j) + r[i]*r[i+1]*r[j+1];

    kay[i][j] = i;

    / /計算其余的最小值并更新u

    for (int k = i+1; k < j; k++) {

    int t = C(i,k) + C(k+1,j) + r[i]*r[k+1]*r[j+1];

    if (r < u) {//小于最小值的情形

    u = t;

    kay[i][j] = k;

    }

    return u;

    }

    void Traceback (int i, int j ,int **kay)

    { / /輸出計算Mi j 的最優(yōu)方法

    if ( i == j) return;

    Traceback(i, kay[i][j], kay);

    Traceback(kay[i][j]+1, j, kay);

    cout << "Multiply M" << i << ", "<< kay[i][j];

    cout << " and M " << (kay[i][j]+1) << ", " << j << end1;

    }

    2. 無重復計算的遞歸方法

    若避免再次計算前面已經計算過的c(及相應的k a y),可將復雜性降低到(q3)。而為了避免重復計算,需用一個全局數(shù)組c[ ][ ]存儲c(i, j) 值,該數(shù)組初始值為0。函數(shù)C的新代碼見程序1 5 - 7:

    程序15-7 無重復計算的c (i, j) 計算方法

    int C(int i,int j)

    { / /返回c(i,j) 并計算k a y ( i , j ) = k a y [ I ] [ j ]

    / /避免重復計算

    / /檢查是否已計算過

    if (c[i][j] >) return c[i][j];

    / /若未計算,則進行計算

    if(i==j) return 0; //一個矩陣的情形

    i f ( i = = j - 1 ) { / /兩個矩陣的情形

    kay[i][i+1]=i;

    c [ i ] [ j ] = r [ i ] * r [ i + 1 ] * r [ i + 2 ] ;

    return c[i][j];}

    / /多于兩個矩陣的情形

    / /設u為k = i 時的最小值

    int u=C(i,i)+C(i+1,j)+r[i]*r[i+1]*r[j+1];

    k a y [ i ] [ j ] = i ;

    / /計算其余的最小值并更新u

    for (int k==i+1; k<j;k++){

    int t=C(i,k)+C(k+1,j)+r[i]*r[k+1]*r[j+1];

    if (t<u) {// 比最小值還小

    u = t ;

    k a y [ i ] [ j ] = k ; }

    }

    c [ i ] [ j ] = u ;

    return u;

    }

    為分析改進后函數(shù)C 的復雜性,再次使用分期計算方法。注意到調用C(1, q) 時每個c (i, j)(1≤i≤j≤q)僅被計算一次。要計算尚未計算過的c(a,b),需附加的工作量s =j-i>1。將s 計入第一次計算c (a, b) 時的工作量中。在依次計算c(a, b) 時,這個s 會轉計到每個c (a, b) 的第一次計算時間c 中,因此每個c (i, i) 均被計入s。對于每個s,有q-s+ 1個c(i, j) 需要計算,因此總的工作消耗為q-1 ?s=1(q-s+ 1) = (q3 )。

    3. 迭代方法

    c 的動態(tài)規(guī)劃遞歸式可用迭代的方法來求解。若按s = 2,3,.,q-1 的順序計算c (i, i+s),每個c 和kay 僅需計算一次。

    例3-14 考察例3 - 1 3中五個矩陣的情況。先初始化c (i, i) (0≤i≤5) 為0,然后對于i=1, ., 4分別計算c (i, i+ 1 )。c (1, 2)= r1 r2 r3 = 5 0,c (2, 3)= 5 0,c ( 3,4)=20 和c (4, 5) = 2 0 0。相應的k ay 值分別為1,2,3和4。

    當s= 2時,可得:

    c( 1 , 3 ) = m i n {c( 1 , 1 ) +c(2,3)+ r1 r2 r4 , c( 1 , 2 ) +c( 3 ,3 )+r1r3r4 }=min

    =150

    且k a y( 1 , 3 ) = 2。用相同方法可求得c( 2 , 4 )和c( 3 , 5 )分別為3 0和4 0,相應k a y值分別為2和3。

    當s= 3時,需計算c(1,4) 和c( 2 , 5 )。計算c(2,5) 所需要的所有中間值均已知(見( 1 5 - 5 )式),代入計算公式后可得c( 2 , 5 ) = 9 0,k a y( 2 , 5 ) = 2。c( 1 , 4 )可用同樣的公式計算。最后,當s= 4時,可直接用(1 5 - 4)式來計算c( 1 , 5 ),因為該式右邊所有項都已知。

    計算c 和kay 的迭代程序見函數(shù)M a t r i x C h a i n(見程序1 5 - 8),該函數(shù)的復雜性為(q3 )。計算出kay 后同樣可用程序1 5 - 6中的Traceback 函數(shù)推算出相應的最優(yōu)乘法計算過程。

    程序15-8 c 和kay 的迭代計算

    void MatrixChain(int r[], int q, int **c, int **kay)

    {// 為所有的Mij 計算耗費和k a y

    // 初始化c[i][i], c[i][i+1]和k a y [ i ] [ i + 1 ]

    for (int i = 1; i < q; i++) {

    c[i][i] = 0;

    c[i][i+1] = r[i]*r[i+1]*r[i+2];

    kay[i][i+1] = i;

    }

    c[q][q] = 0;

    / /計算余下的c和k a y

    for (int s = 2; s < q; s++)

    for (int i = 1; i <= q - s; i++) {

    // k = i時的最小項

    c[i][i+s] = c[i][i] + c[i+1][i+s] + r[i]*r[i+1]*r[i+s+1];

    kay[i][i+s] = i;

    // 余下的最小項

    for (int k = i+1; k < i + s; k++) {

    int t = c[i][k] + c[k+1][i+s] + r[i]*r[k+1]*r[i+s+1];

    if (t < c[i][i+s]) {// 更小的最小項

    c[i][i+s] = t;

    kay[i][i+s] = k;}

    }

    }

    }

    3.2.4 最短路徑

    假設G為有向圖,其中每條邊都有一個長度(或耗費),圖中每條有向路徑的長度等于該路徑中各邊的長度之和。對于每對頂點(i, j),在頂點i 與j 之間可能有多條路徑,各路徑的長度可能各不相同。我們定義從i 到j 的所有路徑中,具有最小長度的路徑為從i 到j 的最短路徑。

    例3-15 如圖1 5 - 4所示。從頂點1到頂點3的路徑有

    1) 1,2,5,3

    2) 1,4,3

    3) 1,2,5,8,6,3

    4) 1,4,6,3

    由該圖可知,各路徑相應的長度為1 0、2 8、9、2 7,因而路徑3) 是該圖中頂點1到頂點3的最短路徑。

    在所有點對最短路徑問題( a l l - p a i r sshorest-paths problem)中,要尋找有向圖G中每對頂點之間的最短路徑。也就是說,對于每對頂點(i, j),需要尋找從i到j 的最短路徑及從j 到i 的最短路徑。因此對于一個n 個頂點的圖來說,需尋找p =n(n-1) 條最短路徑。假定圖G中不含有長度為負數(shù)的環(huán)路,只有在這種假設下才可保證G中每對頂點(i, j) 之間總有一條不含環(huán)路的最短路徑。當有向圖中存在長度小于0的環(huán)路時,可能得到長度為-∞的更短路徑,因為包含該環(huán)路的最短路徑往往可無限多次地加上此負長度的環(huán)路。

    設圖G中n 個頂點的編號為1到n。令c (i, j, k)表示從i 到j 的最短路徑的長度,其中k 表示該路徑中的最大頂點。因此,如果G中包含邊<i, j>,則c(i, j, 0) =邊<i, j> 的長度;若i= j ,則c(i,j, 0)=0;如果G中不包含邊<i, j>,則c (i, j, 0)= +∞。c(i, j, n) 則是從i 到j 的最短路徑的長度。

    例3-16 考察圖1 5 - 4。若k=0, 1, 2, 3,則c (1, 3, k)= ∞;c (1, 3, 4)= 2 8;若k = 5, 6, 7,則c (1, 3,k) = 1 0;若k=8, 9, 10,則c (1, 3, k) = 9。因此1到3的最短路徑長度為9。對于任意k>0,如何確定c (i, j, k) 呢?中間頂點不超過k 的i 到j 的最短路徑有兩種可能:該路徑含或不含中間頂點k。若不含,則該路徑長度應為c(i, j, k- 1 ),否則長度為c(i, k, k- 1) +c (k, j, k- 1 )。c(i, j, k) 可取兩者中的最小值。因此可得到如下遞歸式:

    c( i, j, k)= m i n {c(i, j, k-1), c (i, k, k- 1) +c (k, j, k- 1 ) },k>0

    以上的遞歸公式將一個k 級運算轉化為多個k-1 級運算,而多個k-1 級運算應比一個k 級運算簡單。如果用遞歸方法求解上式,則計算最終結果的復雜性將無法估量。令t (k) 為遞歸求解c (i, j, k) 的時間。根據(jù)遞歸式可以看出t(k) = 2t(k- 1 ) +c。利用替代方法可得t(n) = ( 2n )。因此得到所有c (i, j, n) 的時間為(n2 2n )。

    當注意到某些c (i, j, k-1) 值可能被使用多次時,可以更高效地求解c (i, j, n)。利用避免重復計算c(i, j, k) 的方法,可將計算c 值的時間減少到(n3 )。這可通過遞歸方式(見程序1 5 - 7矩陣鏈問題)或迭代方式來實現(xiàn)。出迭代算法的偽代碼如圖1 5 - 5所示。

    ?

    / /尋找最短路徑的長度

    / /初始化c(i,j,1)

    for (int i=1; i < = n ; i + +)

    for (int j=1; j<=n; j+ + )

    c ( i ,j, 0 ) = a ( i ,j); // a 是長度鄰接矩陣

    / /計算c ( i ,j, k ) ( 0 < k < = n )

    for(int k=1;k<=n;k++)

    for (int i=1;i<=n;i++)

    for (int j= 1 ;j< = n ;j+ + )

    if (c(i,k,k-1)+c(k,j, k - 1 ) < c ( i ,j, k - 1 ) )

    c ( i ,j, k ) = c ( i , k , k - 1 ) + c ( k ,j, k - 1 ) ;

    else c(i,j, k ) = c ( i ,j, k - 1 ) ;

    圖15-5 最短路徑算法的偽代碼

    ?

    注意到對于任意i,c(i,k,k) =c(i,k,k- 1 )且c(k,i,k) =c(k,i,k- 1 ),因而,若用c(i,j)代替圖1 5 - 5的c(i,j,k),最后所得的c(i,j) 之值將等于c(i,j,n) 值。此時圖1 5 - 5可改寫成程序1 5 - 9的C + +代碼。程序1 5 - 9中還利用了程序1 2 - 1中定義的AdjacencyWDigraph 類。函數(shù)AllPairs 在c 中返回最短路徑的長度。若i 到j 無通路,則c [i] [j]被賦值為N o E d g e。函數(shù)AllPairs 同時計算了k a y [ i ] [ j ],其中kay[i][j] 表示從i 到j 的最短路徑中最大的k 值。在后面將看到如何根據(jù)kay 值來推斷出從一個頂點到另一頂點的最短路徑(見程序1 5 - 1 0中的函數(shù)O u t p u t P a t h)。

    程序1 5 - 9的時間復雜性為(n3 ),其中輸出一條最短路徑的實際時間為O (n)。

    程序15-9 c 和kay 的計算

    template<class T>

    void AdjacencyWDigraph<T>::Allpairs(T **c, int **kay)

    { / /所有點對的最短路徑

    / /對于所有i和j,計算c [ i ] [ j ]和k a y [ i ] [ j ]

    / /初始化c [ i ] [ j ] = c(i,j,0)

    for (int i = 1; i <= n; i++)

    for (int j = 1; j <= n; j++) {

    c[i][j] = a[i][j];

    kay[i][j] = 0;

    }

    for (i = 1; i <= n; i++)

    c[i][i] = 0;

    // 計算c[i][j] = c(i,j,k)

    for (int k = 1; k <= n; k++)

    for (int i = 1; i <= n; i++)

    for (int j = 1; j <= n; j++) {

    T t1 = c[i][k];

    T t2 = c[k][j];

    T t3 = c[i][j];

    if (t1 != NoEdge && t2 != NoEdge && (t3 == NoEdge || t1 + t2 < t3)) {

    c[i][j] = t1 + t2;

    kay[i][j] = k;}

    }

    }

    程序15-10 輸出最短路徑

    void outputPath(int **kay, int i, int j)

    {// 輸出i 到j 的路徑的實際代碼

    if (i == j) return;

    if (kay[i][j] == 0) cout << j << ' ';

    else {outputPath(kay, i, kay[i][j]);

    o u t p u t P a t h ( k a y, kay[i][j], j);}

    }

    template<class T>

    void OutputPath(T **c, int **kay, T NoEdge, int i, int j)

    {// 輸出從i 到j的最短路徑

    if (c[i][j] == NoEdge) {

    cout << "There is no path from " << i << " to " << j << endl;

    r e t u r n ; }

    cout << "The path is" << endl;

    cout << i << ' ';

    o u t p u t P a t h ( k a y, i , j ) ;

    cout << endl;

    }

    例3-17 圖15-6a 給出某圖的長度矩陣a,15-6b 給出由程序1 5 - 9所計算出的c 矩陣,15-6c 為對應的k a y值。根據(jù)15-6c 中的kay 值,可知從1到5的最短路徑是從1到k a y [ 1 ] [ 5 ] = 4的最短路徑再加上從4到5的最短路徑,因為k a y [ 4 ] [ 5 ] = 0,所以從4到5的最短路徑無中間頂點。從1到4的最短路徑經過k a y [ 1 ] [ 4 ] = 3。重復以上過程,最后可得1到5的最短路徑為:1,2,3,4,5。

    3.2.5 網絡的無交叉子集

    在11 . 5 . 3節(jié)的交叉分布問題中,給定一個每邊帶n 個針腳的布線通道和一個排列C。頂部的針腳i 與底部的針腳Ci 相連,其中1≤i≤n,數(shù)對(i, Ci ) 稱為網組??偣灿衝 個網組需連接或連通。假設有兩個或更多的布線層,其中有一個為優(yōu)先層,在優(yōu)先層中可以使用更細的連線,其電阻也可能比其他層要小得多。布線時應盡可能在優(yōu)先層中布設更多的網組。而剩下的其他網組將布設在其他層。當且僅當兩個網組之間不交叉時,它們可布設在同一層。我們的任務是尋找一個最大無交叉子集(Maximum Noncrossing Su b s e t,M N S )。在該集中,任意兩個網組都不交叉。因(i, Ci ) 完全由i 決定,因此可用i 來指定(i, Ci )。

    例3-18 考察圖1 5 - 7(對應于圖1 0 - 1 7)。( 1 , 8 )和( 2 , 7 )(也即1號網組和2號網組)交叉,因而不能布設在同一層中。而( 1 , 8 ),(7,9) 和(9,10) 未交叉,因此可布設在同一層。但這3個網組并不能構成一個M N S,因為還有更大的不交叉子集。圖1 0 - 1 7中給出的例子中,集合{ ( 4 , 2 ) ,( 5 , 5 ) , ( 7 , 9 ) , ( 9 , 1 0 )}是一個含4個網組的M N S。

    設M N S(i, j) 代表一個M N S,其中所有的(u, Cu ) 滿足u≤i,Cu≤j。令s i z e(i,j) 表示M N S(i,j)的大小(即網組的數(shù)目)。顯然M N S(n,n)是對應于給定輸入的M N S,而s i z e(n,n)是它的大小。

    例3-19 對于圖1 0 - 1 7中的例子,M N S( 1 0 , 1 0 )是我們要找的最終結果。如例3 - 1 8中所指出的,s i z e( 1 0 , 1 0 ) = 4,因為( 1 , 8 ),( 2 , 7 ),( 7 , 9 ),( 8 , 3 ),( 9 , 1 0 )和( 1 0 , 6 )中要么頂部針腳編號比7大,要么底部針腳編號比6大,因此它們都不屬于M N S( 7 , 6 )。因此只需考察剩下的4個網組是否屬于M N S( 7 , 6 ),如圖1 5 - 8所示。子集{( 3 , 4 ) , ( 5 , 5 )}是大小為2的無交叉子集。沒有大小為3的無交叉子集,因此s i z e( 7 , 6) = 2。

    當i= 1時,( 1 ,C1) 是M N S( 1 ,j) 的唯一候選。僅當j≥C1 時,這個網組才會是M N S( 1 ,j) 的一個成員.

    下一步,考慮i>1時的情況。若j<Ci,則(i,Ci ) 不可能是M N S( i,j) 的成員,所有屬于M N S(i,j) 的(u, Cu ) 都需滿足u<i且Cu<j,因此:s i z e(i,j) =s i z e(i- 1 ,j), j<Ci (1 5 - 7)

    若j≥Ci,則(i,Ci ) 可能在也可能不在M N S(i,j) 內。若(i,Ci ) 在M N S(i,j) 內,則在M N S(i,j)中不會有這樣的(u,Cu ):u<i且Cu>Ci,因為這個網組必與(i, Ci ) 相交。因此M N S(i,j) 中的其他所有成員都必須滿足條件u<i且Cu<Ci。在M N S(i,j) 中這樣的網組共有Mi- 1 , Ci- 1 個。若(i,Ci ) 不在M N S(i,j)中,則M N S(i,j) 中的所有(u, Cu ) 必須滿足u<i;因此s i z e(i,j)=s i z e(i- 1 ,j)。雖然不能確定(i, Ci )是否在M N S(i,j) 中,但我們可以根據(jù)獲取更大M N S的原則來作出選擇。因此:s i z e(i,j) = m a x {s i z e(i-1 ,j), s i z e(i- 1 ,Ci-1)+1}, j≥Ci (1 5 - 8)

    雖然從(1 5 - 6)式到( 1 5 - 8)式可用遞歸法求解,但從前面的例子可以看出,即使避免了重復計算,動態(tài)規(guī)劃遞歸算法的效率也不夠高,因此只考慮迭代方法。在迭代過程中先用式(1 5 - 6)計算出s i ze ( 1 ,j),然后再用式(1 5 - 7)和(1 5 - 8)按i=2, 3, ., n 的順序計算s i ze (i,j),最后再用Traceback 來得到M N S(n, n) 中的所有網組。

    例3-20 圖1 5 - 9給出了圖1 5 - 7對應的s i z e(i,j) 值。因s i z e( 1 0 , 1 0) = 4,可知M N S含4個網組。為求得這4個網組,先從s i ze ( 1 0 , 1 0 )入手。可用(1 5 - 8)式算出s i z e( 1 0 , 1 0 )。根據(jù)式(1 5 - 8)時的產生原因可知s i ze ( 1 0 , 1 0)=s i z e( 9 , 1 0 ),因此現(xiàn)在要求M NS ( 9 , 1 0 )。由于M NS ( 1 0 , 1 0 )≠s i z e( 8 , 1 0 ),因此M NS (9,10) 中必包含9號網組。M N S(9,10) 中剩下的網組組成M NS ( 8 , C9- 1)=M N S( 8 , 9 )。由M N S( 8 , 9 ) =M NS (7,9) 知,8號網組可以被排除。接下來要求M N S( 7 , 9 ),因為s i z e( 7 , 9 )≠s i z e( 6 , 9 ),所以M N S中必含7號網組。M NS (7,9) 中余下的網組組成M NS ( 6 , C7- 1 ) =M N S( 6 , 8 )。根據(jù)s i z e( 6 , 8 ) =s i z e( 5 , 8 )可排除6號網組。按同樣的方法, 5號網組,3號網組加入M N S中,而4號網組等其他網組被排除。因此回溯過程所得到的大小為4的M N S為{ 3 , 5 , 7 , 9 }。

    注意到在回溯過程中未用到s i z e( 1 0 ,j) (j≠1 0 ),因此不必計算這些值。

    程序1 5 - 11給出了計算s i z e ( i , j ) 的迭代代碼和輸出M N S的代碼。函數(shù)M N S用來計算s i ze (i,j) 的值,計算結果用一個二維數(shù)組M N來存儲。size[i][j] 表示s i z e(i,j),其中i=j= n 或1≤i<n,0≤j≤n,計算過程的時間復雜性為(n2 )。函數(shù)Traceback 在N et[0 : m - 1]中輸出所得到的M N S,其時間復雜性為(n)。因此求解M M S問題的動態(tài)規(guī)劃算法的總的時間復雜性

    為(n2 )。

    程序1 5 - 11 尋找最大無交叉子集

    void MNS(int C[], int n, int **size)

    { / /對于所有的i 和j,計算s i z e [ i ] [ j ]

    / /初始化s i z e [ 1 ] [ * ]

    for (int j = 0; j < C[1]; j++)

    size[1][j] = 0;

    for (j = C[1]; j <= n; j++)

    size[1][j] = 1;

    // 計算size[i][*], 1 < i < n

    for (int i = 2; i < n; i++) {

    for (int j = 0; j < C[i]; j++)

    size[i][j] = size[i-1][j];

    for (j = C[i]; j <= n; j++)

    size[i][j] = max(size[i-1][j], size[i-1][C[i]-1]+1);

    }

    size[n][n] = max(size[n-1][n], size[n-1][C[n]-1]+1);

    }

    void Traceback(int C[], int **size, int n, int Net[], int& m)

    {// 在N e t [ 0 : m - 1 ]中返回M M S

    int j = n; // 所允許的底部最大針腳編號

    m = 0; // 網組的游標

    for (int i = n; i > 1; i--)

    // i 號n e t在M N S中?

    if (size[i][j] != size[i-1][j]){// 在M N S中

    Net[m++] = i;

    j = C[i] - 1;}

    // 1號網組在M N S中?

    if (j >= C[1])

    Net[m++] = 1; // 在M N S中

    }

    3.2.6 元件折疊

    在設計電路的過程中,工程師們會采取多種不同的設計風格。其中的兩種為位-片設計(bit-slice design)和標準單元設計(standard-cell design)。在前一種方法中,電路首先被設計為一個元件棧(如圖15-10a 所示)。每個元件Ci 寬為wi ,高為hi ,而元件寬度用片數(shù)來表示。圖15-10a 給出了一個四片的設計。線路是按片來連接各元件的,即連線可能連接元件Ci 的第j片到元件Ci+1 的第j 片。如果某些元件的寬度不足j 片,則這些元件之間不存在片j 的連線。當圖1 5 -10a 的位-片設計作為某一大系統(tǒng)的一部分時,則在V L SI ( Very Large Scale Integrated) 芯片上為它分配一定數(shù)量的空間單元。分配是按空間寬度或高度的限制來完成的?,F(xiàn)在的問題便是如何將元件棧折疊到分配空間中去,以便盡量減小未受限制的尺度(如,若高度限制為H時,必須折疊棧以盡量減小寬度W)。由于其他尺度不變,因此縮小一個尺度(如W)等價于縮小面積??捎谜劬€方式來折疊元件棧,在每一折疊點,元件旋轉1 8 0°。在圖15-10b 的例子中,一個1 2元件的棧折疊成四個垂直棧,折疊點為C6 , C9 和C1 0。折疊棧的寬度是寬度最大的元件所需的片數(shù)。在圖15-10b 中,棧寬各為4,3,2和4。折疊棧的高度等于各棧所有元件高度之和的最大值。在圖15-10b 中棧1的元件高度之和最大,該棧的高度決定了包圍所有棧的矩形高度。

    實際上,在元件折疊問題中,還需考慮連接兩個棧的線路所需的附加空間。如,在圖1 5 -10b 中C5 和C6 間的線路因C6 為折疊點而彎曲。這些線路要求在C5 和C6 之下留有垂直空間,以便能從棧1連到棧2。令ri 為Ci 是折疊點時所需的高度。棧1所需的高度為5 ?i =1hi +r6,棧2所需高度為8 ?i=6hi +r6+r9。

    在標準單元設計中,電路首先被設計成為具有相同高度的符合線性順序的元件排列。假設此線性順序中的元件為C1,.,Cn,下一步元件被折疊成如圖1 5 - 11所示的相同寬度的行。在此圖中, 1 2個標準單元折疊成四個等寬行。折疊點是C4,C6 和C11。在相鄰標準單元行之間,使用布線通道來連接不同的行。折疊點決定了所需布線通道的高度。設li 表示當Ci 為折疊點時所需的通道高度。在圖1 5 - 11的例子中,布線通道1的高度為l4,通道2的高度為l6,通道3的高度為l11。位-片棧折疊和標準單元折疊都會引出一系列的問題,這些問題可用動態(tài)規(guī)劃方法來解決。

    1. 等寬位-片元件折疊

    定義r1 = rn+1 =0。由元件Ci 至Cj 構成的棧的高度要求為j ?k= ilk+ ri+ rj + 1。設一個位-片設計中所有元件有相同寬度W。首先考察在折疊矩形的高度H給定的情況下,如何縮小其寬度。設Wi

    為將元件Ci 到Cn 折疊到高為H的矩形時的最小寬度。若折疊不能實現(xiàn)(如當ri +hi>H時),取Wi =∞。注意到W1 可能是所有n 個元件的最佳折疊寬度。

    當折疊Ci 到Cn 時,需要確定折疊點?,F(xiàn)假定折疊點是按棧左到棧右的順序來取定的。若第一點定為Ck+ 1,則Ci 到Ck 在第一個棧中。為了得到最小寬度,從Ck+1 到Cn 的折疊必須用最優(yōu)化方法,因此又將用到最優(yōu)原理,可用動態(tài)規(guī)劃方法來解決此問題。當?shù)谝粋€折疊點k+ 1已知時,可得到以下公式:

    Wi =w+ Wk + 1 (1 5 - 9)

    由于不知道第一個折疊點,因此需要嘗試所有可行的折疊點,并選擇滿足( 1 5 - 9)式的折疊點。令h s u m(i,k)=k ?j = ihj。因k+ 1是一個可行的折疊點,因此h s u m(i, k) +ri +rk+1 一定不會超過H。

    根據(jù)上述分析,可得到以下動態(tài)規(guī)劃遞歸式:

    這里Wn+1 =0,且在無最優(yōu)折疊點k+ 1時Wi 為∞。利用遞歸式(1 5 - 1 0),可通過遞歸計算Wn , Wn- 1., W2 , W1 來計算Wi。Wi 的計算需要至多檢查n-i+ 1個Wk+ 1,耗時為O (n-k)。因此計算所有Wi 的時間為O (n2 )。通過保留式(1 5 - 1 0)每次所得的k 值,可回溯地計算出各個最優(yōu)的折疊點,其時間耗費為O (n)。

    現(xiàn)在來考察另外一個有關等寬元件的折疊問題:折疊后矩形的寬度W已知,需要盡量減小其高度。因每個折疊矩形寬為w,因此折疊后棧的最大數(shù)量為s=W / w。令Hi, j 為Ci , ., Cn 折疊成一寬度為jw 的矩形后的最小高度, H1, s 則是所有元件折疊后的最小高度。當j= 1時,不允許任何折疊,因此:Hi,1 =h s u m(i,n) +ri , 1≤i≤n

    另外,當i=n 時,僅有一個元件,也不可能折疊,因此:Hn ,j=hn+rn , 1≤j≤s

    在其他情況下,都可以進行元件折疊。如果第一個折疊點為k+ 1,則第一個棧的高度為

    h s u m(i,k) +ri +rk+ 1。其他元件必須以至多(j- 1 ) *w 的寬度折疊。為保證該折疊的最優(yōu)性,其他元件也需以最小高度進行折疊.

    因為第一個折疊點未知,因此必須嘗試所有可能的折疊點,然后從中找出一個使式(1 5 - 11)的右側取最小值的點,該點成為第一個折疊點。

    可用迭代法來求解Hi, j ( 1≤i≤n, 1≤j≤s),求解的順序為:先計算j=2 時的H i, j,再算j= 3,.,以此類推。對應每個j 的Hi, j 的計算時間為O (n2 ),所以計算所有H i, j 的時間為O(s n2 )。通過保存由( 1 5 - 1 2)式計算出的每個k 值,可以采用復雜性為O (n) 的回溯過程來確定各個最優(yōu)的折疊點。

    2. 變寬位-片元件的折疊

    首先考察折疊矩形的高度H已定,欲求最小的折疊寬度的情況。令Wi 如式(1 5 - 1 0)所示,按照與(1 5 - 1 0)式相同的推導過程,可得:

    Wi = m i n {w m i n(i, k) +Wk+1 | h s u m(i,k)+ ri +rk+ 1≤H, i≤k≤n} (1 5 - 1 3)

    其中Wn+1=0且w m i n(i,k)= m ini≤j≤k{wj }。可用與(1 5 - 1 0)式一樣的方法求解(1 5 - 1 3)式,所需時間為O(n2 )。

    當折疊寬度W給定時,最小高度折疊可用折半搜索方法對超過O(n2 )個可能值進行搜索來實現(xiàn),可能的高度值為h(i,j)+ri +rj + 1。在檢測每個高度時,也可用( 1 5 - 1 3)式來確定該折疊的寬度是否小于等于W。這種情況下總的時間消耗為O (n2 l o gn)。

    3. 標準單元折疊

    用wi 定義單元Ci 的寬度。每個單元的高度為h。當標準單元行的寬度W 固定不變時,通過減少折疊高度,可以相應地減少折疊面積??疾霤i 到Cn 的最小高度折疊。設第一個折疊點是Cs+ 1。從元件Cs+1 到Cn 的折疊必須使用最小高度,否則,可使用更小的高度來折疊Cs+1 到Cn,從而得到更小的折疊高度。所以這里仍可使用最優(yōu)原理和動態(tài)規(guī)劃方法。

    令Hi , s 為Ci 到Cn 折疊成寬為W的矩形時的最小高度,其中第一個折疊點為Cs+ 1。令w s u m(i, s)=s ?j = iwj??杉俣]有寬度超過W的元件,否則不可能進行折疊。對于Hn,n 因為只有一個元件,不存在連線問題,因此Hn, n =h。對于H i, s(1≤i<s≤n)注意到如果w s u m(i, s )>W,不可能實現(xiàn)折疊。若w s u m(i,s)≤W,元件Ci 和C j + 1 在相同的標準單元行中,該行下方布線通道的高度為ls+ 1(定義ln+1 = 0)。因而:Hi, s = Hi+1, k (1 5 - 1 4)

    當i=s<n 時,第一個標準單元行只包含Ci 。該行的高度為h 且該行下方布線通道的高度為li+ 1。因Ci+ 1 到Cn 單元的折疊是最優(yōu)的.

    為了尋找最小高度折疊,首先使用式( 1 5 - 1 4)和(1 5 - 1 5)來確定Hi, s (1≤i≤s≤n)。最小高度折疊的高度為m in{H1 , s}。可以使用回溯過程來確定最小高度折疊中的折疊點。

    posted @ 2007-02-27 17:10 保爾任 閱讀(1512) | 評論 (0)編輯 收藏
    // 建立二叉樹并先根遍歷的代碼
    public ? class ?BinaryTreeTest? {
    ?
    public ? static ? void ?main(String?args[])? { // 主方法
    ??BinaryTreeTest?b? = ? new ?BinaryTreeTest();
    ??
    int ?data[]? = ? {? 12 ,? 11 ,? 34 ,? 45 ,? 67 ,? 89 ,? 56 ,? 43 ,? 22 ,? 98 ?} ;
    ??BinaryTree?root?
    = ? new ?BinaryTree(data[ 0 ]);

    ??System.out.print(
    " 二叉樹的中的數(shù)據(jù):   " );
    // 建立二叉樹
    ?? for ?( int ?i? = ? 1 ;?i? < ?data.length;?i ++ )? {
    ???root.insertTree(root,?data[i]);
    ???System.out.print(data[i?
    - ? 1 ]? + ? " ; " );
    ??}


    ??System.out.println(data[data.length?
    - ? 1 ]);

    ??
    int ?key? = ?Integer.parseInt(args[ 0 ]);

    ??
    if ?(b.searchkey(root,?key))? {
    ???System.out.println(
    " 找到了: " ? + ?key);
    ??}
    ? else ? {
    ???System.out.println(
    " 沒有找到: " ? + ?key);
    ??}

    ?}


    ?
    public ? boolean ?searchkey(BinaryTree?root,? int ?key)? { // 查詢
    ?? boolean ?bl? = ? false ;
    ??
    if ?(root? == ? null )? {
    ???bl?
    = ? false ;
    ???
    return ?bl;
    ??}
    ? else ? if ?(root.data? == ?key)? {
    ???bl?
    = ? true ;
    ???
    return ?bl;
    ??}
    ? else ? if ?(key? >= ?root.data)? {
    ???
    return ?searchkey(root.rightpoiter,?key);
    ??}

    ??
    return ?searchkey(root.leftpoiter,?key);
    ?}

    }


    class ?BinaryTree? { // 二叉樹類
    ? int ?data;

    ?BinaryTree?leftpoiter;

    ?BinaryTree?rightpoiter;

    ?BinaryTree(
    int ?data)? {
    ??
    this .data? = ?data;
    ??leftpoiter?
    = ? null ;
    ??rightpoiter?
    = ? null ;
    ?}


    ?
    public ? void ?insertTree(BinaryTree?root,? int ?data)? { // 插入節(jié)點
    ?? if ?(data? >= ?root.data)? {
    ???
    if ?(root.rightpoiter? == ? null )? {
    ????root.rightpoiter?
    = ? new ?BinaryTree(data);
    ???}
    ? else ? {
    ????insertTree(root.rightpoiter,?data);
    ???}

    ??}
    ? else ? {
    ???
    if ?(root.leftpoiter? == ? null )? {
    ????root.leftpoiter?
    = ? new ?BinaryTree(data);
    ???}
    ? else ? {
    ????insertTree(root.leftpoiter,?data);
    ???}

    ??}

    ?}

    }

    // ?end

    講解:一個尋找關鍵字--searchkey
    另一個是插入一個結點:insertTree
    另外這是一個完全的先序遍歷二叉樹的語法。先根結點,再左結點,如無再右結點,如些加歸至搜索完畢。??

    posted @ 2007-02-27 11:41 保爾任 閱讀(409) | 評論 (0)編輯 收藏

    10, 增加eclipse內存:
    更改ECLIPSE文件夾下的ECLIPSE.INI文件內容如下:
    -vmargs
    -Xms128m
    -Xmx512m
    -XX:PermSize=128m
    -XX:MaxPermSize=256m

    或者:

    在eclipse目錄下建個批處理文件eclipse.bat,用文本編輯器打開,寫入如下內容:
    eclipse.exe -vmargs -Xms128m -Xmx512m -XX:PermSize=128m -XX:PermSize=256m

    然后保存.以后運行eclipse的時候就執(zhí)行這個批處理就行了.
    解釋下參數(shù)的意思:
    -vmargs                                   說明后面的參數(shù)都是java虛擬機(vm)的參數(shù)
    -Xms128m                               虛擬機占用系統(tǒng)的最小內存
    -Xmx512m                               虛擬機占用系統(tǒng)的最大內存
    -XX:PermSize=64m              最小堆大小.一般報內存不足時,都是說這個太小,堆空間剩余小于5%                             就會警告,建議把這個稍微設大一點,不過要視自己機器內存大小來設置

    -XX:PermSize=128m             最大堆大小.這個也適當變大些

    在快捷方式中設置也可:
    eclipse.exe -vmargs -Xverify:none -XX:+UseParallelGC -XX:PermSize=20M -Xms64M -Xmx512M


    9,代碼風格設置
    可以通過Window->Perferences->Java->Code Style->Code Formatter來設定代碼的編寫格式,然后只要用快捷鍵Ctrl+Shift+F就可以將不標準的代碼自動轉化成所設定的標準格式。

    8,顯示行號,顯示限制列的線(默認80列)

    window -> Preferences -> General -> Editors -> Text Editors: Show line numbers; Show print margin

    7.打包成jar文件時,需要根據(jù)自定義的文件生成MANIFEST.MF,其中每行的冒號后面都有一個空格,否則出錯。例:Manifest-Version: 1.0(1.0前有空格,其他行也是如此)

    6.由數(shù)據(jù)庫中的表自動建立.java和.hbm.xml文件
    a.建立項目:打開帶HibernateTools插件的eclipse,建立一個名為“test”的java project,內部新建一個名字為src的source folder。
    b.建立hibernate配置文件:新建“hibernate configuration file”,輸出路徑選擇“test項目的src目錄”,然后的對話框填寫配置文件(包括database dialect,driver class,connection url,username,password,creat a console configuration),下一個對話框先填寫name(即console configuration name),再點“add external jars”,選擇數(shù)據(jù)庫驅動的jar文件,看到src中有“hibernate.cfg.xml”就是配置文件建立成功。
    c.建立目標文件:點工具欄hibernate圖標,選擇“hibernate code generation...”,在彈出的對話框中點擊左側“新建”,把名字改為“test”,console configuration選剛才建立的console configuration name,package填想生成的包結構,點reveng.xml的“setup”,接下來對話框選擇test的src目錄,然后導入需要的數(shù)據(jù)庫表(有關聯(lián)的就要導入,即外鍵的表也要導入),然后點“finish”;選擇main右邊的exporters,選中generate domain code,generate mappings三項,run,刷新項目,看到包中生成的.java和.hbm.xml文件,成功,把它們拷入myeclipse的相應項目里。
    d.刪除Console Configuration:打開Hibernate Console的透視圖(perspective),在左側Hibernate Configuration的視圖(view)中右鍵單擊,就可以刪除。
    刪除Hivernate Code Generation:點擊工具欄Hibernate圖標,左側即可刪除。

    5.*.service.spring包中的*ServiceImpl.java文件中有dao對象屬性,必須包括這個對象的get/set方法,否則出錯。

    4.從一個.jsp文件轉到另一個包含有form表單.jsp文件時,出錯信息為form表單的action找不到mapping,在兩個頁面之間加一個action即可找到。

    3.eclipse與tomcat代碼不同步的問題
    搜索tomcat中有此項目名的所有文件,全部刪除。在實驗應該會成功。

    2.字符集框手動輸入
    我把“eclipse 的window-->prefrences -->general -->content type”設為了UTF8,是為了不讓每個項目再選一遍UTF8,結果單個項目選擇時就沒有GBK選項了。解決辦法就是在單個項目讓你選字符集的地方手動輸入GBK,就ok了?。?!

    1.debug工具條灰色
    debug模式下,eclipse用debug透視圖打開斷點頁面,但debug工具條卻顯示灰色,應該轉到其他透視圖在轉會來就可以了。比如debug -> java -> debug


     

    posted @ 2007-02-13 11:21 保爾任 閱讀(458) | 評論 (0)編輯 收藏
    作者一記錄:
    ?
    編輯
    作用域??功能??快捷鍵
    全局??查找并替換?Ctrl+F
    文本編輯器?查找上一個?Ctrl+Shift+K
    文本編輯器?查找下一個?Ctrl+K
    全局??撤銷??Ctrl+Z
    全局??重做??Ctrl+Y
    全局??復制??Ctrl+C
    全局??剪切??Ctrl+X
    全局??粘貼??Ctrl+V
    全局??全部選中?Ctrl+A
    全局??刪除??Delete
    全局??快速修正?Ctrl+1
    全局??內容輔助?Alt+/
    全局??上下文信息?Alt+??Alt+Shift+??Ctrl+Shift+Space
    Java編輯器 顯示工具提示描述 F2
    全局 恢復上一個選擇 Alt+Shift+↓
    Java編輯器 選擇封裝元素 Alt+Shift+↑
    Java編輯器 選擇上一個元素 Alt+Shift+←
    Java編輯器 選擇下一個元素 Alt+Shift+→
    文本編輯器 增量查找 Ctrl+J
    文本編輯器 增量逆向查找 Ctrl+Shift+J
    文本編輯器 改寫切換 Insert
    文本編輯器 上滾行 Ctrl+↑
    文本編輯器 下滾行 Ctrl+↓

    ?
    查看
    作用域 功能 快捷鍵
    全局 放大 Ctrl+=
    全局 縮小 Ctrl+-
    ?
    窗口
    作用域 功能 快捷鍵
    全局 激活編輯器 F12
    全局 切換編輯器 Ctrl+Shift+W
    全局 上一個編輯器 Ctrl+Shift+F6
    全局 上一個視圖 Ctrl+Shift+F7
    全局 上一個透視圖 Ctrl+Shift+F8
    全局 下一個編輯器 Ctrl+F6
    全局 下一個視圖 Ctrl+F7
    全局 下一個透視圖 Ctrl+F8
    文本編輯器 顯示標尺上下文菜單 Ctrl+W
    全局 顯示視圖菜單 Ctrl+F10
    全局 顯示系統(tǒng)菜單 Alt+-
    ?
    導航
    作用域 功能 快捷鍵
    Java編輯器 打開結構 Ctrl+F3
    全局 打開類型 Ctrl+Shift+T
    全局 打開類型層次結構 F4
    全局 打開聲明 F3
    全局 打開外部javadoc Shift+F2
    全局 打開資源 Ctrl+Shift+R
    全局 后退歷史記錄 Alt+←
    全局 前進歷史記錄 Alt+→
    全局 上一個 Ctrl+,
    全局 下一個 Ctrl+.
    Java編輯器 顯示大綱 Ctrl+O
    全局 在層次結構中打開類型 Ctrl+Shift+H
    全局 轉至匹配的括號 Ctrl+Shift+P
    全局 轉至上一個編輯位置 Ctrl+Q
    Java編輯器 轉至上一個成員 Ctrl+Shift+↑
    Java編輯器 轉至下一個成員 Ctrl+Shift+↓
    文本編輯器 轉至行 Ctrl+L

    搜索
    作用域 功能 快捷鍵
    全局 出現(xiàn)在文件中 Ctrl+Shift+U
    全局 打開搜索對話框 Ctrl+H
    全局 工作區(qū)中的聲明 Ctrl+G
    全局 工作區(qū)中的引用 Ctrl+Shift+G

    ?
    文件
    作用域 功能 快捷鍵
    全局 保存 Ctrl+S
    全局 打印 Ctrl+P
    全局 關閉 Ctrl+F4
    全局 全部保存 Ctrl+Shift+S
    全局 全部關閉 Ctrl+Shift+F4
    全局 屬性 Alt+Enter
    全局 新建 Ctrl+N

    項目
    作用域 功能 快捷鍵
    全局 全部構建 Ctrl+B

    源代碼
    作用域 功能 快捷鍵
    Java編輯器 格式化 Ctrl+Shift+F
    Java編輯器 取消注釋 Ctrl+\
    Java編輯器 注釋 Ctrl+/
    Java編輯器 添加導入 Ctrl+Shift+M
    Java編輯器 組織導入 Ctrl+Shift+O
    Java編輯器 使用try/catch塊來包圍未設置,太常用了,所以在這里列出,建議自己設置。
    也可以使用Ctrl+1自動修正。
    ?
    運行
    作用域 功能 快捷鍵
    全局 單步返回 F7
    全局 單步跳過 F6
    全局 單步跳入 F5
    全局 單步跳入選擇 Ctrl+F5
    全局 調試上次啟動 F11
    全局 繼續(xù) F8
    全局 使用過濾器單步執(zhí)行 Shift+F5
    全局 添加/去除斷點 Ctrl+Shift+B
    全局 顯示 Ctrl+D
    全局 運行上次啟動 Ctrl+F11
    全局 運行至行 Ctrl+R
    全局 執(zhí)行 Ctrl+U

    重構
    作用域 功能 快捷鍵
    全局 撤銷重構 Alt+Shift+Z
    全局 抽取方法 Alt+Shift+M
    全局 抽取局部變量 Alt+Shift+L
    全局 內聯(lián) Alt+Shift+I
    全局 移動 Alt+Shift+V
    全局 重命名 Alt+Shift+R
    全局 重做 Alt+Shift+Y

    作者二記錄:
    讓我們按照使用頻率來看看我最愛用的一些熱鍵組合。(注:以下內容在Eclipse3.02及一上版本通過測試)
    1. Control-Shift-T: 打開類型(Open type)。如果你不是有意磨洋工,還是忘記通過源碼樹(source tree)打開的方式吧。
    2. Control-Shift-R: 打開資源(不只是用來尋找Java文件)。小提示:利用Navigator視圖的黃色雙向箭頭按鈕讓你的編輯窗口和導航器相關聯(lián)。這會讓你打開的文件對應顯示在導航器的層級結構中,這樣便于組織信息。如果這影響了速度,就關掉它。
    3. F3: 打開申明(Open declaration)。或者,利用Declaration Tab(在Java視圖模式下,選擇Windows --> Show View -- > Declaration)。當你選中代碼中的一個方法,然后按這個按鍵,它會把整個方法在申明方框里顯示出來。
    4. Alt-left arrow: 在導航歷史記錄(Navigation History)中后退。就像Web瀏覽器的后退按鈕一樣,在利用F3跳轉之后,特別有用。(用來返回原先編譯的地方)
    5. Alt-right arrow: 導航歷史記錄中向前。
    6. Control-Q: 回到最后依次編輯的地方。這個快捷鍵也是當你在代碼中跳轉后用的。特別是當你鉆的過深,忘記你最初在做什么的時候。
    7. Control-Shift-G: 在workspace中搜索引用(reference)。這是重構的前提。對于方法,這個熱鍵的作用和F3恰好相反。它使你在方法的棧中,向上找出一個方法的所有調用者。一個與此相關的功能是開啟“標記”功能(occurrence marking) 。選擇Windows->Preferences->Java-> Editor-> Mark Occurrences,勾選選項。這時,當你單擊一個元素的時候,代碼中所有該元素存在的地方都會被高亮顯示。我個人只使用“標記本地變量”(Mark Local Variables)。注意:太多的高亮顯示會拖慢Eclipse。
    8. Control-Shift-F: 根據(jù)代碼風格設定重新格式化代碼。我們的團隊有統(tǒng)一的代碼格式,我們把它放在我們的wiki上。要這么做,我們打開Eclipse,選擇Window?Preferences?Java?Code Style,然后設置Code Formatter,Code Style和Organize Imports。利用導出(Export)功能來生成配置文件。我們把這些配置文件放在wiki上,然后團隊里的每個人都導入到自己的Eclipse中。
    9. Control-O: 快速概要(quick outline)。通過這個快捷鍵,你可以迅速的跳到一個方法或者屬性,只需要輸入名字的頭幾個字母。
    10. Control-/: 對一行注釋或取消注釋。對于多行也同樣適用。
    11. Control-Alt-down arrow: 復制高亮顯示的一行或多行。
    12. Alt-down arrow: 將一行或多行向下移動。Alt-up arrow會向上移動。
    其他的熱鍵在菜單里有。你可以通過按下Control-Shift-L(從3.1版本開始),看到所有快捷鍵的列表。按下Control-Shift-L兩次,會顯示熱鍵對話框(Keys Preferences dialog),你可以在這里自己設置熱鍵。我歡迎你在Talkback部分發(fā)表你的Eclipse提示。
    其他的Eclipse竅門
    我總結了幾個相關的小竅門:
    鎖定命令行窗口:在命令行視圖中(Window ? Show View ? Other ? Basic ? Console),試試看用滾動鎖定按鈕來鎖定控制臺輸出不要滾屏。
    使用Ant視圖:在我的Java或Debug模式下,我喜歡顯示出Ant視圖,這樣我就可以迅速的運行Ant任務。通過Window ? Show View ? Other ? Ant可以找到該視圖。把Ant視圖放在屏幕的一角,通過“添加編譯文件(Add Buildfiles)”按鈕來添加build.xml文件。在3.1版本中,甚至支持Ant調試腳本語言。
    自動遍歷一個集合:for + Control-Space: 如果你還不知道,那么你應該記住Control-Space是自動完成功能。在Eclipse中,你還可以自動完成結構。在一個數(shù)組或集合范圍內,試試看輸入“for”然后按下Control-Space鍵。Eclipse會問你你想要遍歷哪一個集合然后自動完成循環(huán)代碼。
    使用分級布局:在包瀏覽視圖(Package Explorer view)中默認的布局(扁平式)方式讓我困惑,它把包的全名顯示在導航樹(navigation tree)中。我更喜歡我源碼的包和文件系統(tǒng)視圖,在Eclipse中叫做分級布局(Hierarchical Layout)。要切換到這種模式,點擊包瀏覽視圖中向下的按鈕,選擇布局(Layout),然后選擇分級(Hierarchial)。
    一次顯示多個文件:你可以一次瀏覽多個文件。把不在激活狀態(tài)的編輯窗口拖到激活窗口的底部或側邊的滾動條上,就可以打開該編輯窗口。這是我能描述該竅門的最好方式了。
    同時打開兩個Eclipse:要將改動從一個CVS分支上合并到另外一個上,我喜歡通過同時打開兩個工作目錄(Workspace)不同Eclipse來實現(xiàn)。這樣我可以通過比較CVS上的最新版本看到所有的變化(右鍵單擊工程,然后選擇Compare with ? Lastest from HEAD)然后把每一個變化都合并到另外一個CVS分支上。啟動多個Eclipse的最簡單的方法是利用Eclipse Launcher。
    Implementors插件:安裝一個能夠跳到一個接口的實現(xiàn)的插件。如果你是個dependency injection 粉絲,或者正在基于編寫優(yōu)良的接口工作,那么你需要一個這樣的插件來加速代碼導航。你可以在SourceForge找到這個插件。
    posted @ 2007-02-13 11:20 保爾任 閱讀(723) | 評論 (0)編輯 收藏
    ?  可以【方法一】簡單地把plugin放到eclipse SDK本身的features和plugins目錄下來進行plugin的安裝,但是這種方法并不利于plugin的管理:
    • 雖然可以通過【方法二】eclipse SDK的update功能來升級自身,然而因為速度的原因我們一般還是會選擇完全下載新版本,這樣就需要把后來安裝到eclipse SDK目錄下的plugin都挑選出來并拷貝到新版本的eclipse SDK目錄下,如果這樣的plugin比較多的話將會有些麻煩。
    • 有時候會共存多個版本的eclipse SDK,顯然我們并不想把這些plugin拷貝到每個版本的eclipse SDK里
      【方法三】eclipse platform是支持把plugin安裝到其他目錄的,不過它對這些目錄是有要求的:該目錄必須有一個名為eclipse的子目錄,eclipse子目錄下必須有一個.eclipseextension文件,plugin本身放在eclipse子目錄下的features和plugins目錄下。這樣的一個位置就是一個eclipse extension,.eclipseextension文件描述了這個eclipse extension,包括三項name、id和version;可以有多個eclipse extension,具體創(chuàng)建幾個eclipse extension,每個eclipse extension包含哪些plugin,完全視情況而定,比如可以把關系比較密切的幾個plugin放在一個eclipse extension中。

      顯然我們必須告訴eclipse platform這些eclipse extension的位置才行,這有兩種方法:
    • 當eclipse啟動后用,打開Help->Software Updates/Manager Configuration,用Add an Extension Location來添加eclipse extesnion,指定的位置將會被存放到當前的configuration里
    • 在eclipse platform所在的eclipse目錄下建一個links目錄,多個插件可以定義一個***.link,一個path=location一行;或者定義多個***.link文件,每個包含一個path=location。路徑分隔符為正斜杠,如果用反斜杠必須用兩個以轉義
      第一種方法是把eclipse extension的位置保存在當前configuration中,因此用這種方法指定的eclipse extension是特定于configuration的,不同的configuration可以具有不同的eclipse extension配置,可以在啟動時用-configuration選項來選擇一個configuration,但是似乎當添加完eclipse extension后是不能刪除的,只能disable,而且多個configuration也帶來了管理的負擔;第二種方法比較明了,但它是 configuration insensitive的,不管以哪個configuration運行這些eclipse extension都是可見的,這里不用擔心內存的占用問題,因為eclipse的plugin都是lazy loading的,用不到的plugin是并不會占用內存空間的,不過可能會有plugin沖突問題,比如兩個插件在同一個extension point處擴展,而對extension point的處理又是不可配置的,比如選擇extension的策略是找到的第一個extension,而此時如果我們希望運行的extension恰好排在第二位,那么就有問題了,這時可能就需要兩種方法都用到了。

      配置好eclipse extension后,這些eclipse extension中的plugin就和eclipse platform/sdk中的plugin,按照extension和extension point的關系,共同形成了一個插件網絡,這時各個plugin的位置已經沒有區(qū)別了,你甚至可以指定運行位于eclipse extension中的product。

      一般的plugin包都會把eclipse目錄打進去,這樣只要把該包直接解壓到選定的 eclipse extension目錄中即可,不過如前所述,要成為真正的eclipse extension目錄,還需要一個.eclipseextension文件,除了手工建立外,當從update site安裝plugin時還可以讓eclipse來建立它,只要在安裝對話框彈出時選擇change location指定一個目錄即可。
    posted @ 2007-02-13 11:18 保爾任 閱讀(306) | 評論 (0)編輯 收藏
    -1 subversion開發(fā)
    subclipse: http://subclipse.tigris.org/update_1.2.x
    按照提示安裝完畢后,我們就可以打開Subversion的資源庫了。選擇Eclipse菜單Window->Show View->Other…,選擇SVN->SVN Repository,然后添加一個新的資源庫,例如http://livebookstore.googlecode.com/svn/trunk

    0  python開發(fā)
    pydev:http://www.fabioz.com/pydev/updates

    1  Eclipse下載
    EMF,GEF - Graphical Editor Framework,UML2,VE - Visual Editor都在這里下載
    http://www.eclipse.org/downloads/index.php

    2  lomboz J2EE插件,開發(fā)JSP,EJB
    http://forge.objectweb.org/projects/lomboz

    3  MyEclipse J2EE開發(fā)插件,支持SERVLET/JSP/EJB/數(shù)據(jù)庫操縱等
    http://www.myeclipseide.com/

    4  Properties Editor  編輯java的屬性文件,并可以自動存盤為Unicode格式
    http://propedit.sourceforge.jp/index_en.html

    5  Colorer Take  為上百種類型的文件按語法著色
    http://colorer.sourceforge.net/

    6  XMLBuddy 編輯xml文件
    http://www.xmlbuddy.com/

    7  Code Folding  加入多種代碼折疊功能(比eclipse自帶的更多)
    http://www.coffee-bytes.com/servlet/PlatformSupport

    8  Easy Explorer  從eclipse中訪問選定文件、目錄所在的文件夾
    http://easystruts.sourceforge.net/

    9  Fat Jar 打包插件,可以方便的完成各種打包任務,可以包含外部的包等
    http://fjep.sourceforge.net/

    10  RegEx Test 測試正則表達式
    http://brosinski.com/stephan/archives/000028.php

    11  JasperAssistant 報表插件(要錢的哦~)
    http://www.jasperassistant.com/

    12  Jigloo GUI Builder JAVA的GUI編輯插件
    http://cloudgarden.com/jigloo/

    13  Profiler 性能跟蹤、測量工具,能跟蹤、測量B/S程序
    http://sourceforge.net/projects/eclipsecolorer/

    14  AdvanQas 提供對if/else等條件語句的提示和快捷幫助(自動更改結構等)
    http://eclipsecolorer.sourceforge.net/advanqas/index.html

    15  Log4E Log4j插件,提供各種和Log4j相關的任務,如為方法、類添加一個logger等
    http://log4e.jayefem.de/index.php/Main_Page

    16  VSSPlugin VSS插件
    http://sourceforge.net/projects/vssplugin

    17  Implementors 提供跳轉到一個方法的實現(xiàn)類,而不是接口的功能(實用!)
    http://eclipse-tools.sourceforge.net/implementors/

    18  Call Hierarchy 顯示一個方法的調用層次(被哪些方法調,調了哪些方法)
    http://eclipse-tools.sourceforge.net/call-hierarchy/index.html

    19  EclipseTidy 檢查和格式化HTML/XML文件
    http://eclipsetidy.sourceforge.net/

    20  Checkclipse 檢查代碼的風格、寫法是否符合規(guī)范
    http://www.mvmsoft.de/content/plugins/checkclipse/checkclipse.htm

    21  Hibernate Synchronizer Hibernate插件,自動映射等
    http://www.binamics.com/hibernatesync/

    22  VeloEclipse  Velocity插件
    http://propsorter.sourceforge.net/ 
     
    23  EditorList 方便的列出所有打開的Editor
    http://editorlist.sourceforge.net/ 
     
    24  MemoryManager 內存占用率的監(jiān)視
    http://cloudgarden.com/memorymanager/ 
     
    25  swt-designer java的GUI插件
    http://www.swt-designer.com/
     
    26  TomcatPlugin 支持Tomcat插件
    http://www.sysdeo.com/eclipse/tomcatPlugin.html
     
    27  XML Viewer
    http://tabaquismo.freehosting.net/ignacio/eclipse/xmlview/index.html
     
    28  quantum 數(shù)據(jù)庫插件
    http://quantum.sourceforge.net/
     
    29  Dbedit 數(shù)據(jù)庫插件
    http://sourceforge.net/projects/dbedit
     
    30  clay.core 可視化的數(shù)據(jù)庫插件
    http://www.azzurri.jp/en/software/index.jsp
    http://www.azzurri.jp/eclipse/plugins
     
    31  hiberclipse hibernate插件
    http://hiberclipse.sourceforge.net/
    http://www.binamics.com/hibernatesync
     
    32  struts-console Struts插件
    http://www.jamesholmes.com/struts/console/
     
    33  easystruts Struts插件
    http://easystruts.sourceforge.net/ 
     
    34  veloedit Velocity插件
    http://veloedit.sourceforge.net/
     
    35  jalopy 代碼整理插件
    http://jalopy.sourceforge.net/
     
    36  JDepend 包關系分析
    http://andrei.gmxhome.de/jdepend4eclipse/links.html
     
    37  Spring IDE Spring插件
    http://springide-eclip.sourceforge.net/updatesite/
     
    38  doclipse 可以產生xdoclet 的代碼提示
    http://beust.com/doclipse/

    39  SQLExplorer,在Eclipse 中連接各種數(shù)據(jù)庫進行操作使用
    http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=124&threadID=31124

    ===========================================================\

    以下為7月13日轉貼更新

    JSEclipse

    插件主頁:http://www.interaktonline.com/Products/Eclipse/JSEclipse/Overview/
    插件介紹:JSEclipse是個Eclipse下的免費Javascript腳本編輯器

    subversion
    版本控制,相當于CVS
    安裝:http://subclipse.tigris.org/install.html
    Name: Subclipse
    URL:  http://subclipse.tigris.org/update_1.0.x


    CSS Editor for Eclipse
    http://csseditor.sourceforge.net/

    FacesIDE
    FacesIDE是一個用于開發(fā)JSF的Eclispe插件.它可以可視化編輯faces-config.xml文件并且提供代碼編輯與校驗,預覽JSF的JSP文件.FacesIDE包含MyFaces來作為JSF的實現(xiàn)
    http://amateras.sourceforge.jp/cgi-bin/fswiki_en/wiki.cgi?page=FacesIDE

    Eclipse SQLExplorer plugin
    一個數(shù)據(jù)庫管理插件
    http://sourceforge.net/projects/eclipsesql

    Poperties Editor
    一個在編輯完成后可以將資源文件中的中文編碼格式轉換為unicode編碼的插件,在開發(fā)國際化應用程序的時候非常有用
    http://propedit.sourceforge.jp/eclipse/updates/

    eclipseME
     
    http://eclipseme.org/updates/

    Eclipse加速插件KeepResident
    http://suif.stanford.edu/pub/keepresident/

     
    MyEclipse  J2EE開發(fā)插件,支持SERVLET/JSP/EJB/數(shù)據(jù)庫操縱等
    www.myeclipseide.com
     
    Properties Editor  編輯java的屬性文件,并可以自動存盤為Unicode格式
    http://propedit.sourceforge.jp/index_en.html
    http://propedit.sourceforge.jp/eclipse/updates/
     
    Colorer Take  為上百種類型的文件按語法著色
    http://colorer.sourceforge.net/
     
    XMLBuddy 編輯xml文件
    www.xmlbuddy.com
     
    Code Folding  加入多種代碼折疊功能(比eclipse自帶的更多)
    http://www.coffee-bytes.com/servlet/PlatformSupport
     
    Easy Explorer  從eclipse中訪問選定文件、目錄所在的文件夾
    http://easystruts.sourceforge.net/
     
    Fat Jar 打包插件,可以方便的完成各種打包任務,可以包含外部的包等
    http://fjep.sourceforge.net/
     
    RegEx Test 測試正則表達式
    http://brosinski.com/stephan/archives/000028.php
     
    JasperAssistant 報表插件(強,要錢的)
    http://www.jasperassistant.com/
     
    Jigloo GUI Builder JAVA的GUI編輯插件
    http://cloudgarden.com/jigloo/
     
    Profiler 性能跟蹤、測量工具,能跟蹤、測量BS程序
    http://sourceforge.net/projects/eclipsecolorer/
     
    AdvanQas 提供對if/else等條件語句的提示和快捷幫助(自動更改結構等)
    http://eclipsecolorer.sourceforge.net/advanqas/index.html
     
    Log4E     Log4j插件,提供各種和Log4j相關的任務,如為方法、類添加一個logger等
    http://log4e.jayefem.de/index.php/Main_Page
     
    VSSPlugin VSS插件
    http://sourceforge.net/projects/vssplugin
     
    Implementors   提供跳轉到一個方法的實現(xiàn)類,而不是接中的功能(實用!)
    http://eclipse-tools.sourceforge.net/implementors/
     
    Call Hierarchy 顯示一個方法的調用層次(被哪些方法調,調了哪些方法)
    http://eclipse-tools.sourceforge.net/call-hierarchy/index.html
     
    EclipseTidy 檢查和格式化HTML/XML文件
    http://eclipsetidy.sourceforge.net/
     
    Checkclipse 檢查代碼的風格、寫法是否符合規(guī)范
    http://www.mvmsoft.de/content/plugins/checkclipse/checkclipse.htm
     
    Hibernate Synchronizer Hibernate插件,自動映射等
    http://www.binamics.com/hibernatesync/
     
    spring updatesite 插件
    http://springide.org/updatesite/

    VeloEclipse  Velocity插件
    http://propsorter.sourceforge.net/
     
    EditorList   方便的列出所有打開的Editor
    http://editorlist.sourceforge.net/
     
    MemoryManager 內存占用率的監(jiān)視
    http://cloudgarden.com/memorymanager/

    Eclipse的游戲插件
    http://eclipse-games.sourceforge.net/

    JBoss-IDE
    http://jboss.sourceforge.net/jbosside/updates/

    自動反編譯class,安裝后要設定class文件缺省關聯(lián)到jode
    http://www.technoetic.com/eclipse/update


    jigloo swing/sw設計工具,里面自帶的form/anchor布局很好用!
    http://cloudgarden.soft-gems.net/update-site/

    jinto的資源文件編輯工具,同時編輯多種語言,而且自動轉換成iso8859-1編碼。很好用!
    http://www.guh-software.de/eclipse/

    posted @ 2007-02-13 11:17 保爾任 閱讀(673) | 評論 (0)編輯 收藏
    ?一、exe4j

    說明:exe4j可以將Jar文件制作成exe文件,但需jre支持,也可將Jar文件放在外面。

    軟件性質:共享軟件

    下載地址:http://www.ej-technologies.com/products/exe4j/overview.html

    二、JBuilder

    說明:新版本的JBuilder可以直接把工程制作成各系統(tǒng)的可執(zhí)行文件,包括Windows系統(tǒng)。

    軟件性質:商業(yè)軟件

    下載地址:略。我是從eMule下載的。

    三、NativeJ

    說明:與exe4j功能類似。

    軟件性質:共享軟件

    下載地址:http://www.dobysoft.com/products/nativej/download.html

    四、Excelsior JET

    說明:可以直接將Java類文件制作成exe文件,除AWT和Swing及第三方圖形接口外可不需jre支持(Java5.0不行)。

    軟件性質:共享軟件

    下載地址:http://excelsior-usa.com/home.html

    五、jshrink

    說明:可將Jar文件打包進exe文件。同時具有混淆功能(這才是它的主要功能)。

    軟件性質:共享軟件

    下載地址:http://www.e-t.com/jshrink.html

    六、InstallAnywhere

    說明:打包工具,對Java打包最好用??纱虬筛鞑僮飨到y(tǒng)運行包。包括Windows系統(tǒng)。

    軟件性質:商業(yè)軟件。

    下載地址:http://www.zerog.com/

    七、InstallShieldX

    說明:與InstallAnywhere類似,但比InstallAnywhere功能強大。相對的,比較復雜,不易上手,我現(xiàn)在還沒學會。
    posted @ 2007-02-13 11:16 保爾任 閱讀(290) | 評論 (0)編輯 收藏

    一、代碼轉換工具:
    native2ascii -encoding gb2312 application_temp.properties application_zh_CN.properties
    注釋:-encoding gb2312 表示讀application_temp.properties 的編碼方式,application_temp.properties 存的是中文資源文件,application_zh_CN.properties
    存的是轉成ascii碼后的資源文件。

    二、反編譯工具jad.exe:
    ?以下假設jad.exe在c:\java目錄下
    1、基本用法
    Usage:??? jad [option(s)] <filename(s)>
    直接輸入類文件名,且支持通配符,如下所示。
    c:\java\>jad example1.class
    c:\java\>jad *.class
    結果是將example1.class反編譯為example1.jad。將example1.jad改為example1.java即得源文件。
    2、Option -o
    不提示,覆蓋源文件
    3、Option -s
    c:\java\>jad -sjava example1.class
    反編譯結果以.java為擴展名。
    4、Option -p
    將反編譯結果輸出到屏幕
    c:\java\>jad -p example1.class
    將反編譯結果重定向到文件
    c:\java\>jad -p example1.class>example1.java
    5、Option -d
    指定反編譯的輸出文件目錄
    c:\java\>jad -o -dtest -sjava *.class

    三、文檔生成工具javadoc.exe
    ? 大家都知道,J2SE5中的Javadoc.exe的命令行可選參數(shù)多達五十余個,其復雜性可想而知,是不是看著頭都大了呢?但通常情況下,我們不想那么麻煩!
    假設源代碼在 C:\src 目錄下,其中 com.liigo 是主包,其下可能有數(shù)十個子包,數(shù)百(千)個Java文件。目錄結構大約是這樣的:
    - C:\
    ????? | src\
    ????????? | com\
    ????????????? | liigo\
    ????????????????? | ***
    怎么才能以最簡捷的方式生成所有的API文檔呢?
    c:\>
    c:\>cd src
    c:\src>javadoc -d doc -subpackages com.liigo
    這樣就搞定了,最終生成的API文檔位于 c:\src\doc 目錄(該目錄是由javadoc.exe自動生成的)。
    上面的用法利用了“當前目錄”和“相對路徑”,當然也可以用絕對路徑:
    ...>javadoc -d c:\doc -sourcepath c:\src -subpackages com.liigo
    最終生成的API文檔位于 c:\doc 目錄(該目錄同樣是由javadoc.exe自動生成的)。

    總結一下:
    我們只用到了javadoc的三個參數(shù): -d,-subpackages,-sourcepath,其中:
    ?參數(shù)? 說明?
    ?-d? 指定API文檔的輸出目錄,默認是當前目錄。建議總是指定該參數(shù)。
    ?-sourcepath 指定源代碼路徑,默認是當前目錄。 此參數(shù)通常是必須的。
    ?-subpackages? 以遞歸的方式處理各子包。關鍵參數(shù)!如果不使用本參數(shù),每次只能處理一個子包(或需手工列出所有子包)。

    四、運行jvm時改變內存或堆的大小
    -Xms<size>???????????????? set?? initial?? Java?? heap?? size??
    -Xmx<size>???????????????? set?? maximum?? Java?? heap?? size??
    -Xss<size>???????????????? set?? java?? thread?? stack?? size??
    ???
    比如:java?? -Xmx512M? HelloWorld.class,讓jvm使用512Mheap內存.

    posted @ 2007-02-13 11:16 保爾任 閱讀(300) | 評論 (0)編輯 收藏

    ???作者:江南白衣,原文出處: http://blog.csdn.net/calvinxiu/archive/2007/01/27/1495778.aspx,轉載請保留出處。

    ??? Unix系統(tǒng)永遠只會越來越多,開發(fā)人員就沒必要特意學習它們的安裝、配置和管理了,就全部交給集成人員吧。
    ??? 但開發(fā)人員行走于Unix之間,依然有四樣東西要熟練。

    ??? 一、VI

    ??? 雖然Unix上的文本編輯器已經越來越好用,但不在Console前面,網速也不夠連XWindows的時候,還是要依賴VI。
    ??? 回想VI的時代背景,發(fā)現(xiàn)VI對開發(fā)人員已經周到得離譜了,熱鍵多到你雙手不離鍵盤就能完成大半編輯工作。
    ??? 建議自己制作一張自己認為有用,但又經常忘記的命令的sheet,拿出考試的力氣把它背熟。

    ??? 二、文本處理

    ?? ??? 開發(fā)人員在Unix下干得最多的除了Make和除Bug外,大概就是處理日志文件、業(yè)務文件進行查錯和統(tǒng)計了。
    ???? 只會more和grep是不夠的,開發(fā)老手會把awk,sed,grep,sort,uniq,wc,head,tail這些文本處理命令,通過管道玩具式的拆卸拼裝,最后完成一件原本以為非編寫大段代碼不可的工作。周到的參數(shù)設定,讓人再一次感嘆那個簡單的年代,這樣復雜到極致的設計.......怪不得《Unix 編程藝術》的作者有那么驕傲的自覺。

    ???? 比如車東的每月訪問TOP10 統(tǒng)計腳本:

    awk?-F?' t'?'{ print ? $ 4 }'?2004_2 . txt|?grep?chedong . com / tech / | uniq?-c| sort ?-rn|head?- 10 ?
    • awk -F '\t' 將2004_2.txt訪問紀錄文件,用TAB分割,打印第4列
    • grep chedong.com/tech 只列出chedong.com/tech筆記目錄下的文檔
    • uniq -c 匯總計數(shù)
    • sort -rn 按數(shù)值排序
    • head -10 TOP 10

    ??? 三、Bash Shell 編程

    ??? 編程是開發(fā)人員的天賦本能,不論什么語言,看看參考手冊應該就能上手。

    ??? 見Bash新手指南中文版,一份寫給新手看的包含很多老手知識的指南。

    ??? 四、Make與AutoMake

    ??? 用過Java的Ant后,想起Make就覺得很煩,很厭倦??倸w還是會的,見GNU Make 3.8.0 中文手冊????

    ???? 不過即使make已經精通到變態(tài),每個人寫出來的MakeFile還是千奇百怪,再看看開源項目們個個都是automake+autoconf了,我們自己也長進一點吧。手工編寫MakeFile.am,讓auotomake變成MakeFile.in,再讓用戶./configure 生成最終的MakeFile。
    ????
    ??? 生成的MakeFile既能跨越平臺,又是標準的寫法,最重要的是,編寫MakeFile.am的工作量比MakeFile少多了,只要簡單的定義目標文件,先要處理的子目錄,需要的源文件,頭文件與庫文件就可以了。如果看完下面兩篇還是不懂,直接看ACE里的Makefile.am就懂了。

    ????入門文章:使用AutoMake輕松生成Makefile?
    ??? 進階文章:IBM DW:解 autoconf 和 automake 生成 Makefile 文件
    ??? 完整的免費電子書:?GNU Autoconf, Automake and Libtool

    ?? ?另外,ACE里還貢獻了一個更厲害的MPC(Makefile, Project, and Workspace Creator ),??自動的生成了MakeFile.am或者VC的項目文件。

    ??? 附錄A:我的VI易忘命令手冊

    ??? 上下左右:
    ??? ctrl+u/d 上下半屏,ctrl+f/b,上下一屏
    ??? H/G屏幕頭/文章末 ,0/$ 行首行末
    ???
    ??? 增刪改:
    ??? yy/dd 復制/刪除 一行,p/P:將yy/dd的內容paste出來
    ??? I/A 在行首/末添加, o/O 開新行,d0/d$ 刪除到行首,行末
    ??? u:undo

    ??? 查:
    ??? ? 向前查找, n/N 重復上一次查找

    附錄B: 文本處理命令小結

    ?? awk:處理結構化的文本(每行以固定符號分成若干列),提取打印某些字段,如:
    ??? ls -l|awk '{print $1}'? --將ls-l結果的第一列打印出來
    ??? awk -F":" '{print $1"? "$6}' /etc/passwd ,將以:分割的/etc/passwd文件的第1,6列打印出來,中間以空格分開
    ??? 詳見IBM DW中國的AWK實例(共3篇) 或 Bash新手指南中文版第6章。

    ??? grep:過濾,大家用得最多的命令,支持正則表達式。參數(shù)有:
    ??? -i忽略大小寫,-n顯示line number,-c 統(tǒng)計在每個文件的出現(xiàn)次數(shù),-l只顯示符合的文件的名字。

    ??? sed:流編輯器,主要用于替換,如:
    ??? sed -e '1,10s/foo/bar/g' myfile2.txt 將1到10行的文本中的foo 替換成bar,s代表替換,g代表全局替換
    ??? 支持正則的替換字符串,可以只替換某個范圍內的內容。
    ??? 用法不算簡單,詳見IBM DW中國的Sed實例(共3篇)或 Bash新手指南中文版第5章
    ????
    ??? sort:排序,參數(shù)有:
    ??? -r逆序, -n 數(shù)字比較 , -M 日歷比較 Feb,Dec, -f 忽略大小寫
    ??? 同樣支持結構化文件,如
    ??? sort -t : -k 1,1 /etc/passwd,以: 分割,只按第1列排序
    ??? sort -t : -k 1,1 -k2.2,3.4 /etc/passwd ,以:分割,先按第1列排序,再按第2列的第二個字符到第3列的第4個字符排序。

    ??? uniq:去除重復行。
    ??? 除了正常用法外,還有-c統(tǒng)計重復次數(shù),和-u (唯一)和 -d (重復)兩個參數(shù),只顯示唯一的和重復的行。

    ??? wc: 統(tǒng)計。
    ??? -l 行,-m 字符,-w 單詞

    posted @ 2007-01-29 17:31 保爾任 閱讀(313) | 評論 (0)編輯 收藏
    僅列出標題
    共8頁: 上一頁 1 2 3 4 5 6 7 8 下一頁 

    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    常用鏈接

    留言簿(4)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲免费在线观看视频| 久久er国产精品免费观看8| 亚洲成a人片在线观看国产| 16女性下面无遮挡免费| 九九综合VA免费看| 亚洲av一本岛在线播放| 国产亚洲福利精品一区| 免费永久国产在线视频| 黄页网站在线观看免费高清| 久久精品免费观看| 成人免费夜片在线观看| 亚洲乱码国产乱码精华| 亚洲人成网站在线观看播放青青| 亚洲小说区图片区| 亚洲五月六月丁香激情| 最新精品亚洲成a人在线观看| 免费观看a级毛片| 噼里啪啦电影在线观看免费高清 | 久久亚洲色WWW成人欧美| 亚洲成人福利在线| 亚洲综合久久一本伊伊区| 久久狠狠高潮亚洲精品| 精品久久久久久亚洲| 国产精品深夜福利免费观看| 91嫩草国产在线观看免费| 免费能直接在线观看黄的视频| 免费日本一区二区| 亚洲一级免费视频| 永久黄网站色视频免费| 国产精品xxxx国产喷水亚洲国产精品无码久久一区 | 亚洲视频在线免费播放| 亚洲不卡中文字幕无码| 亚洲综合网美国十次| 亚洲黄色网站视频| 亚洲综合国产成人丁香五月激情| 亚洲小说图片视频| 国产大陆亚洲精品国产| 阿v免费在线观看| 日韩一级片免费观看| 国产成人精品免费久久久久| 国产精品白浆在线观看免费|