計算幾何與圖形學有關的幾種常用演算法
我的專業是計算機輔助設計(CAD),算是一半機械一半軟體,《計算機圖形學》是必修課,也是我最喜歡的課程。熱衷於用程式碼擺平一切的我幾乎將這本教科書上的每種演算法都實現了一遍,這種重複勞動雖然意義不大,但是收穫很多,特別是丟棄了多年的數學又重新回到了腦袋中,算是最大的收穫吧。儘管已經畢業多年了,但是每次回顧這些演算法的程式碼,都覺得內心十分澎湃,如果換成現在的我,恐怕再也不會有動力去做這些事情了。
在學習《計算機圖形學》之前,總覺得很多東西高深莫測,但實際掌握了之後,卻發現其中了無神祕可言,就如同被原始人像神一樣崇拜的火卻被現代人叼在嘴上玩弄一樣的感覺。圖形學的基礎之一就是計算幾何,但是沒有理論數學那麼高深莫測,它很有實踐性,有時候甚至可以簡單到匪夷所思。計算幾何是隨著計算機和CAD的應用而誕生的一門新興學科,在國外被稱為“計算機輔助幾何設計(Computer Aided Geometric Design,CAGD)”。“算法系列”接下來的幾篇文章就會介紹一些圖形學中常見的計算幾何演算法(順便晒晒我的舊程式碼),都是一些圖形學中的基礎演算法,需要一些圖形學的知識和數學知識,但是都不難。不信?那就來看看到底有多難。
本文是第一篇,主要是一些圖形學常用的計算幾何方法,涉及到向量、點線關係以及點與多邊形關係求解等數學知識,還有一些平面幾何的基本原理。事先宣告一下,文中涉及的演算法實現都是著眼於解釋原理以及揭示演算法實質的目的,在演算法效率和可讀性二者的考量上,更注重可讀性,有時候為了提高可讀性會刻意採取“效率不高”的程式碼形式,實際工程中使用的程式碼肯定更緊湊更高效,但是演算法原理都是一樣的,請讀者們對此有正確的認識。
一、 判斷點是否在矩形內
計算機圖形學和數學到底有什麼關係?我們先來看幾個例子,增加一些感性認識。首先是判斷一個點是否在矩形內的演算法,這是一個很簡單的演算法,但是卻非常重要。比如你在一個按鈕上點選滑鼠,系統如何知道你要觸發這個按鈕對應的事件而不是另一個按鈕?對了,就是一個點是否在矩形內的判斷處理。Windows 的API提供了PtInRect()函式,實現方法其實就是判斷點的x座標和y座標是否同時落在矩形的x座標範圍和y座標範圍內,演算法實現也很簡單:
150 bool IsPointInRect(const Rect& rc, const Point& p) 151 { 152 double xr = (p.x - rc.p1.x) * (p.x - rc.p2.x); 153 double yr = (p.y - rc.p1.y) * (p.y - rc.p2.y); 154 155 return ( (xr <= 0.0) && (yr <= 0.0) ); 156 } |
看看IsPointInRect()函式的實現是否和你想象的不一樣?有時候硬體實現乘法有困難或受限制於CPU乘法指令的效率,可以考慮用下面的函式替換,程式碼繁瑣了一點,但是避免了乘法運算:
120 bool IsPointInRect(const Rect& rc, const Point& p) 121 { 122 double xl,xr,yt,yb; 123 124 if(rc.p1.x < rc.p2.x) 125 { 126 xl = rc.p1.x; 127 xr = rc.p2.x; 128 } 129 else 130 { 131 xl = rc.p2.x; 132 xr = rc.p1.x; 133 } 134 135 if(rc.p1.y < rc.p2.y) 136 { 137 yt = rc.p2.y; 138 yb = rc.p1.y; 139 } 140 else 141 { 142 yt = rc.p1.y; 143 yb = rc.p2.y; 144 } 145 146 return ( (p.x >= xl && p.x <= xr) && (p.y >= yb && p.y <= yt) ); 147 } |
由於IsPointInRect()函式並不假設矩形的兩個定點是按照座標軸升序排列的,所以演算法實現時就考慮了所有可能的座標範圍。IsPointInRect()函式使用的是平面直角座標系,如果不特別說明,本文所有的演算法都是基於平面直角座標系設計的。另外,IsPointInRect()函式沒有指定特別的浮點數精度範圍,預設是系統浮點數的最大精度,只在某些必須要與0比較的情況下,採用10-8次方精度,如無特別說明,本文的所有演算法都這樣處理。
一、 判斷點是否在圓內
現在考慮複雜一點,如果圖形介面的按鈕不是矩形而是圓形的怎麼辦呢?當然就是判斷點是否在圓內部。判斷演算法的原理就是計算點到圓心的距離d,然後與圓半徑r進行比較,若d < r則說明點在圓內,若d = r則說明點在圓上,若d > r則說明點在圓外。這就要提到計算平面上兩點距離的演算法。以下圖為例,計算平面上任意兩點之間的距離主要依據著名的勾股定理:
圖1 平面兩點距離計算示意圖
113 //計算歐氏幾何空間內平面兩點的距離 114 double PointDistance(const Point& p1, const Point& p2) 115 { 116 return std::sqrt( (p1.x-p2.x)*(p1.x-p2.x) 117 + (p1.y-p2.y)*(p1.y-p2.y) ); 118 } |
一、 判斷點是否在多邊形內
現在再考慮複雜一點的,如果按鈕是個不規則的多邊形區域怎麼辦?別以為這個考慮沒有意義,很多多媒體軟體和遊戲,通常都是用各種形狀的不規則圖案作為熱點(Hot Spot),Windows也提供了PtInRegion() API,用於判斷點是否在一個不規則區域中。我們對問題做一個簡化,就判斷一個點是否在多邊形內?判斷點P是否在多邊形內是計算幾何中一個非常基本的演算法,最常用的方法是射線法。以P點為端點,向左方做射線L,然後沿著L從無窮遠處開始向P點移動,當遇到多邊形的某一條邊時,記為與多邊形的第一個交點,表示進入多邊形內部,繼續移動,當遇到另一個交點時,表示離開多邊形內部。由此可知,當L與多邊形的交點個數是偶數時,表示P點在多邊形外,當L與多邊形交點個數是奇數時,表示P點在多邊形內部。
由此可見,要實現判斷點是否在多邊形內的演算法,需要知道直線段求交演算法,而求交演算法又涉及到向量的一些基本概念,因此在實現這個演算法之前,先講一下向量的基本概念以及線段求交演算法。
3.1 向量的基礎知識
什麼是向量?簡單地講,就是既有大小又有方向的量,數學中又常被稱為向量。向量有幾何表示、代數表示和座標表示等多種表現形式,本文討論的是幾何表示。如果一條線段的端點是有次序之分的,我們把這種線段成為有向線段(Directed Segment),比如線段P1P2,如果起始端點P1就是座標原點(0, 0),P2的座標是(x, y),則線段P1P2的二維向量座標表示就是P= (x, y)。
3.2 向量的加法和減法
現在來看幾個與向量有關的重要概念,首先是向量的加減法。假設有二維向量P = ( x1, y1 ),Q = ( x2 , y2 ),則向量加法定義為:
P + Q = ( x1 + x2 , y1 + y2 )
同樣的,向量減法定義為:
P - Q = ( x1 - x2 , y1 - y2 )
根據向量加減法的定義,向量的加減法滿足以下性質:
P + Q = Q + P
P - Q = - ( Q - P )
圖2 演示了向量加法和減法的幾何意義,由於幾何中直線段的兩個點不可能剛好在原點,因此線段P1P2的向量其實就是OP2 - OP1的結果,如圖2 (b)所示:
3.3 向量的叉積(外積)
另一個比較重要的概念是向量的叉積(外積)。計算向量的叉積是判斷直線和線段、線段和線段以及線段和點的位置關係的核心演算法。假設有二維向量P = ( x1, y1 ),Q = ( x2 , y2 ),則向量的叉積定義為:
P × Q = x1*y2 - x2*y1
向量叉積的幾何意義可以描述為由座標原點(0,0)、P、Q和P + Q所組成的平行四邊形的面積,而且是個帶符號的面積,由此可知,向量的叉積具有以下性質:
P × Q = - ( Q × P )
叉積的結果P × Q是P和Q所在平面的法向量,它的方向是垂直與P和Q所在的平面,並且按照P、Q和P × Q的次序構成右手系,所以叉積的另一個非常重要性質是可以通過它的符號可以判斷兩向量相互之間位置關係是順時針還是逆時針關係,具體說明如下:
1) 如果 P × Q > 0 , 則Q在P的逆時針方向;
2) 如果 P × Q < 0 , 則Q在P的順時針方向;
3) 如果 P × Q = 0 , 則Q與P共線(但可能方向是反的);
3.4 向量的點積(內積)
最後要介紹的概念是向量的點積(內積)。假設有二維向量P = ( x1, y1 ),Q = ( x2 , y2 ),則向量的點積定義為:
P·Q = x1*x2 + y1*y2
向量點積的結果是一個標量,它的代數表示是:
P·Q = |P| |Q| cos(P, Q)
(P, Q) 表示向量P和Q的夾角,如果P和Q不共線,則根據上式可以得到向量點積的一個非常重要的性質,具體說明如下:
1) 如果 P · Q > 0 , 則P和Q的夾角是鈍角(大於90度);
2) 如果 P · Q < 0 , 則P和Q的夾角是銳角(小於90度);
3) 如果 P · Q = 0 , 則P和Q的夾角是90度;
瞭解了向量的概念以及向量的各種運算的幾何意義和代數意義後,就可以開始解決各種計算幾何的簡單問題了,回想本文開始提到的點與多邊形的關係問題,首先要解決的就是判斷點和直線段的位置關係問題。
3.5 用向量的叉積判斷點和直線的關係
根據向量叉積的幾何意義,如果線段所表示的向量和點的向量的叉積是0,就說明點線上段所在的直線上,相對於座標原點O來說,線段的向量其實就是線段終點P2=[x2, y2]的向量OP2減線段起點P1=[x1, y1]的向量OP1的結果,因此線段P1P2的向量可以表示為P1P2=(x2 – x1, y2 – y1)。如果要判斷點P是否線上段P1P2上,就要判斷向量P1P2和向量OP的叉積是否是0。需要注意的是,叉積為0只能說明點P與線段P1P2所在的直線共線,並不能說明點P一定會落在P1P2區間上,因此只是一個必要條件。要正確判斷P線上段P1P2上,還需要做一個排斥試驗,就是檢查點P是否在以直線段為對角線的矩形空間內,如果以上兩個條件都為真,即可判定點線上段上。有了上述原理,演算法實現就比較簡單了,以下就是判斷點是否線上段上的演算法:
174 bool IsPointOnLineSegment(const LineSeg& ls, const Point& pt) 175 { 176 Rect rc; 177 178 GetLineSegmentRect(ls, rc); 179 double cp = CrossProduct(ls.pe.x - ls.ps.x, ls.pe.y - ls.ps.y, 180 pt.x - ls.ps.x, pt.y - ls.ps.y); //計算叉積 181 182 return ( (IsPointInRect(rc, pt)) //排除實驗 183 && IsZeroFloatValue(cp) ); //1E-8 精度 184 } 185 |
3.6 用向量的叉積判斷直線段是否有交
向量叉積計算的另一個常用用途是直線段求交。求交演算法是計算機圖形學的核心演算法,也是體現速度和穩定性的重要標誌,高效並且穩定的求交演算法是任何一個CAD軟體都必需要重點關注的。求交包含兩層概念,一個是判斷是否相交,另一個是求出交點。直線(段)的求交演算法相對來說是比較簡單的,首先來看看如何判斷兩直線段是否相交。
常規的代數計算通常分三步,首先根據線段還原出兩條線段所在直線的方程,然後聯立方程組求出交點,最後再判斷交點是否線上段區間上。常規的代數方法非常繁瑣,每次都要解方程組求交點,特別是交點不線上段區間的情況,計算交點就是做無用功。計算幾何方法判斷直線段是否有交點通常分兩個步驟完成,這兩個步驟分別是快速排斥試驗和跨立試驗。假設要判斷線段P1P2和線段Q1Q2是否有交點,則:
(1) 快速排斥試驗
設以線段 P1P2 為對角線的矩形為R1, 設以線段 Q1Q2 為對角線的矩形為R2,如果R1和R2不相交,則兩線段不會有交點;
(2) 跨立試驗。
如果兩線段相交,則兩線段必然相互跨立對方,所謂跨立,指的是一條線段的兩端點分別位於另一線段所在直線的兩邊。判斷是否跨立,還是要用到向量叉積的幾何意義。以圖3為例,若P1P2跨立Q1Q2 ,則向量 ( P1 - Q1 ) 和( P2 - Q1 )位於向量( Q2 - Q1 ) 的兩側,即:
( P1 - Q1 ) × ( Q2 - Q1 ) * ( P2 - Q1 ) × ( Q2 - Q1 ) < 0
上式可改寫成:
( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) > 0
當 ( P1 - Q1 ) × ( Q2 - Q1 ) = 0 時,說明線段P1P2和Q1Q2共線(但是不一定有交點)。同理判斷Q1Q2跨立P1P2的依據是:
( Q1 - P1 ) × ( P2 - P1 ) * ( Q2 - P1 ) × ( P2 - P1 ) < 0
具體情況如下圖所示:
圖3 直線段跨立試驗示意圖
根據向量叉積的幾何意義,跨立試驗只能證明線段的兩端點位於另一個線段所在直線的兩邊,但是不能保證是在另一直線段的兩端,因此,跨立試驗只是證明兩條線段有交點的必要條件,必需和快速排斥試驗一起才能組成直線段相交的充分必要條件。根據以上分析,兩條線段有交點的完整判斷依據就是:1)以兩條線段為對角線的兩個矩形有交集;2)兩條線段相互跨立。
判斷直線段跨立用計算叉積演算法的CrossProduct()函式即可,還需要一個判斷兩個矩形是否有交的演算法。矩形求交也是最簡單的求交演算法之一,原理就是根據兩個矩形的最大、最小座標判斷。圖4展示了兩個矩形沒有交集的各種情況:
圖4 矩形沒有交集的幾種情況
圖5展示了兩個矩形有交集的各種情況:
圖5 矩形有交集的幾種情況
從圖4和圖5可以分析出來兩個矩形有交集的幾何座標規律,就是在x座標方向和y座標方向分別滿足最大值最小值法則,簡單解釋這個法則就是每個矩形在每個方向上的座標最大值都要大於另一個矩形在這個座標方向上的座標最小值,否則在這個方向上就不能保證一定有位置重疊。由以上分析,判斷兩個矩形是否相交的演算法就可以如下實現:
186 bool IsRectIntersect(const Rect& rc1, const Rect& rc2) 187 { 188 return ( (std::max(rc1.p1.x, rc1.p2.x) >= std::min(rc2.p1.x, rc2.p2.x)) 189 && (std::max(rc2.p1.x, rc2.p2.x) >= std::min(rc1.p1.x, rc1.p2.x)) 190 && (std::max(rc1.p1.y, rc1.p2.y) >= std::min(rc2.p1.y, rc2.p2.y)) 191 && (std::max(rc2.p1.y, rc2.p2.y) >= std::min(rc1.p1.y, rc1.p2.y))); 192 } |
完成了排斥試驗和跨立試驗的演算法,最後判斷直線段是否有交點的演算法就水到渠成了:
204 bool IsLineSegmentIntersect(const LineSeg& ls1, const LineSeg& ls2) 205 { 206 if(IsLineSegmentExclusive(ls1, ls2)) //排斥實驗 207 { 208 return false; 209 } 210 //( P1 - Q1 ) ×'a1?( Q2 - Q1 ) 211 double p1xq = CrossProduct(ls1.ps.x - ls2.ps.x, ls1.ps.y - ls2.ps.y, 212 ls2.pe.x - ls2.ps.x, ls2.pe.y - ls2.ps.y); 213 //( P2 - Q1 ) ×'a1?( Q2 - Q1 ) 214 double p2xq = CrossProduct(ls1.pe.x - ls2.ps.x, ls1.pe.y - ls2.ps.y, 215 ls2.pe.x - ls2.ps.x, ls2.pe.y - ls2.ps.y); 216 217 //( Q1 - P1 ) ×'a1?( P2 - P1 ) 218 double q1xp = CrossProduct(ls2.ps.x - ls1.ps.x, ls2.ps.y - ls1.ps.y, 219 ls1.pe.x - ls1.ps.x, ls1.pe.y - ls1.ps.y); 220 //( Q2 - P1 ) ×'a1?( P2 - P1 ) 221 double q2xp = CrossProduct(ls2.pe.x - ls1.ps.x, ls2.pe.y - ls1.ps.y, 222 ls1.pe.x - ls1.ps.x, ls1.pe.y - ls1.ps.y); 223 224 //跨立實驗 225 return ( (p1xq * p2xq <= 0.0) && (q1xp * q2xp <= 0.0) ); 226 } |
IsLineSegmentExclusive()函式就是呼叫IsRectIntersect()函式根據結果做排斥判斷,此處不再列出程式碼。
3.7 點和多邊形關係的演算法實現
好了,現在我們已經瞭解了向量叉積的意義,以及判斷直線段是否有交點的演算法,現在回過頭看看文章開始部分的討論的問題:如何判斷一個點是否在多邊形內部?根據射線法的描述,其核心是求解從P點發出的射線與多邊形的邊是否有交點。注意,這裡說的是射線,而我們前面討論的都是線段,好像不適用吧?沒錯,確實是不適用,但是我要介紹一種用計算機解決問題時常用的建模思想,應用了這種思想之後,我們前面討論的方法就適用了。什麼思想呢?就是根據問題域的規模和性質抽象和簡化模型的思想,這可不是故弄玄虛,說說具體的思路吧。
計算機是不能表示無窮大和無窮小,計算機處理的每一個數都有確定的值,而且必須有確定的值。我們面臨的問題域是整個實數空間的座標系,在每個維度上都是從負無窮到正無窮,比如射線,就是從座標系中一個明確的點到無窮遠處的連線。這就有點為難計算機了,為此我們需要簡化問題的規模。假設問題中多邊形的每個點的座標都不會超過(-10000.0, +10000.0)區間(比如我們常見的圖形輸出裝置都有大小的限制),我們就可以將問題域簡化為(-10000.0, +10000.0)區間內的一小塊區域,對於這塊區域來說,>= 10000.0就意味著無窮遠。你肯定已經明白了,數學模型經過簡化後,演算法中提到的射線就可以理解為從模型邊界到內部點P之間的線段,前面討論的關於線段的演算法就可以使用了。
射線法的基本原理是判斷由P點發出的射線與多邊形的交點個數,交點個數是奇數表示P點在多邊形內(在多邊形的邊上也視為在多邊形內部的特殊情況),正常情況下經過點P的射線應該如圖6(a)所示那樣,但是也可能碰到多種非正常情況,比如剛好經過多邊形一個定點的情況,如圖6 (b),這會被誤認為和兩條邊都有交點,還可能與某一條邊共線如圖6 (c)和(d),共線就有無窮多的交點,導致判斷規則失效。還要考慮凹多邊形的情況,如圖6(e)。
圖6 射線法可能遇到的各種交點情況
針對這些特殊情況,在對多邊形的每條邊進行判斷時,要考慮以下這些特殊情況,假設當前處理的邊是P1P2,則有以下原則:
1)如果點P在邊P1P2上,則直接判定點P在多邊形內;
2)如果從P發出的射線正好穿過P1或者P2,那麼這個交點會被算作2次(因為在處理以P1或P2為端點的其它邊時可能已經計算過這個點了),對這種情況的處理原則是:如果P的y座標與P1、P2中較小的y座標相同,則忽略這個交點;
3)如果從P發出的射線與P1P2平行,則忽略這條邊;
對於第三個原則,需要判斷兩條直線是否平行,通常的方法是計算兩條直線的斜率,但是本演算法因為只涉及到直線段(射線也被模型簡化為長線段了),就簡化了很多,判斷直線是否水平,只要比較一下線段起始點的y座標是否相等就行了,而判斷直線是否垂直,也只要比較一下線段起始點的x座標是否相等就行了。
應用以上原則後,掃描線法判斷點是否在多邊形內的演算法流程就完整了,圖7就是演算法的流程圖:
最終掃描線法判斷點是否在多邊形內的演算法實現如下:
228 bool IsPointInPolygon(const Polygon& py, const Point& pt) 229 { 230 assert(py.IsValid()); /*只考慮正常的多邊形,邊數>=3*/ 231 232 int count = 0; 233 LineSeg ll = LineSeg(pt, Point(-INFINITE, pt.y)); /*射線L*/ 234 for(int i = 0; i < py.GetPolyCount(); i++) 235 { 236 /*當前點和下一個點組成線段P1P2*/ 237 LineSeg pp = LineSeg(py.pts[i], py.pts[(i + 1) % py.GetPolyCount()]); 238 if(IsPointOnLineSegment(pp, pt)) 239 { 240 return true; 241 } 242 243 if(!pp.IsHorizontal()) 244 { 245 if((IsSameFloatValue(pp.ps.y, pt.y)) && (pp.ps.y > pp.pe.y)) 246 { 247 count++; 248 } 249 else if((IsSameFloatValue(pp.pe.y, pt.y)) && (pp.pe.y > pp.ps.y)) 250 { 251 count++; 252 } 253 else 254 { 255 if(IsLineSegmentIntersect(pp, ll)) 256 { 257 count++; 258 } 259 } 260 } 261 } 262 263 return ((count % 2) == 1); 264 } |
在圖形學領域實施的真正工程程式碼,通常還會增加一個多邊形的外包矩形快速判斷,對點根本就不在多邊形周圍的情況做快速排除,提高演算法效率。這又涉及到求多邊形外包矩形的演算法,這個演算法也很簡單,就是遍歷多邊形的所有節點,找出各個座標方向上的最大最小值。以下就是求多邊形外包矩形的演算法:
266 void GetPolygonEnvelopRect(const Polygon& py, Rect& rc) 267 { 268 assert(py.IsValid()); /*只考慮正常的多邊形,邊數>=3*/ 269 270 double minx = py.pts[0].x; 271 double maxx = py.pts[0].x
3.6 用向量的叉積判斷直線段是否有交
向量叉積計算的另一個常用用途是直線段求交。求交演算法是計算機圖形學的核心演算法,也是體現速度和穩定性的重要標誌,高效並且穩定的求交演算法是任何一個CAD軟體都必需要重點關注的。求交包含兩層概念,一個是判斷是否相
3.6 用向量的叉積判斷直線段是否有交 向量叉積計算的另一個常用用途是直線段求交。求交演算法是計算機圖形學的核心演算法,也是體現速度和穩定性的重要標誌,高效並且穩定的求交演算法是任何一個CAD軟體都必需要重點關注的。求交包含兩層概念,一個是判斷是否相交,另一個是
我的專業是計算機輔助設計(CAD),算是一半機械一半軟體,《計算機圖形學》是必修課,也是我最喜歡的課程。熱衷於用程式碼擺平一切的我幾乎將這本教科書上的每種演算法都實現了一遍,這種重複勞動雖然意義不大,但是收穫很多,特別是丟棄了多年的數學又重新回到了腦袋中,算是最大的收
我的專業是計算機輔助設計(CAD),算是一半機械一半軟體,《計算機圖形學》是必修課,也是我最喜歡的課程。熱衷於用程式碼擺平一切的我幾乎將這本教科書上的每種演算法都實現了一遍,這種重複勞動雖然意義不大,但是收穫很多,特別是丟棄了多年的數學又重新回到了腦袋中,算是最大的收穫吧
list.c檔案如下
#include "list.h"
/*返回head連結串列POS節點的位置*/
LINK list_moov_pos(LINK head,int pos){
LINK node = head;
while(--pos) node = node->pNe
from sklearn import datasets
import numpy as np
iris =datasets.load_iris()
X = iris.data[:,[2,3]]
y = iris.target
np.unique(y) #np.unique(y)返回儲 排序演算法
排序演算法中包括:簡單排序、高階排序
簡單排序
簡單排序常用的有:氣泡排序、選擇排序、插入排序
氣泡排序程式碼如下:
1 private static void bubbleSrot(int[] arr) {
2
3 for (int
寫一下幾種常見排序演算法,清一下腦子
歸併排序
/**
* Created by PhpStorm.
* User: leon
* Date: 2018/3/14
* Time: 下午2:37
*/
function mergeSort(&am
卷積計算
全連線層和卷積層的根本區別在於:全連線層(Dense層)從輸入空間中學到的是全域性模式,而卷積層學到的是區域性模式。
因為這個特性,所以卷積神經網路有兩個有趣的性質:
平移不變性:卷積神經網路在影象右下角學到的某個模式,它可以在任何地方識別出來這個模式;而對 img 之一 keys open isp println 轉換成 hang zha JSON格式的數據傳遞是最常用的方法之一,以下列出了常用的幾種形態以及與Javabean之間的轉換:
String json1="{‘name‘:‘zhangsan‘,‘age‘ 嘗試 產生 統一 規則 存在 允許 成本 garbage 找到 前言:
首先思考垃圾收集(Garbage Collection,GC)需要完成的三件事情
1)哪些內存需要回收?
2)什麽時候回收?
3)如何回收?
再上一個博客中提到了Java內存運行時 pack ack 構造 rop struct service() throws esc println 1. <bean> 元素的 init-method/destroy-method屬性指定初始化之後 /銷毀之前調用的操作方法
2. 指定方法上加上@PostC 疑問 自己 img nts 標記 ava 類關系 繼承 contain 一、繼承關系 繼承指的是一個類(稱為子類、子接口)繼承另外的一個類(稱為父類、父接口)的功能,並可以增加它自己的新功能的能力。在Java中繼承關系通過關鍵字extends明確標識,在設計時一般 元素選擇器 類選擇器 範圍 命名沖突 post ora before 重復 --
Css選擇器
常用的選擇器有如下幾種:
1、標簽選擇器
標簽選擇器,此種選擇器影響範圍大,建議盡量應用在層級選擇器中。
舉例:
*{margin:0;padding:0}
div{c 物理內存 是什麽 nts iat 其他 輸入緩沖 BE virt getc 應用程序與驅動程序據我所知,細分可以分6種,ReadFile,WirteFile方式的緩沖區設備讀寫,直接方式讀寫,和其他方式讀寫。Io設備控制操作(即DeviceControl)的緩沖內存模式IO 直線 情況 算法 n) src 隨著 多邊形 取整 兩個 第二章:光柵圖形學算法
1、光柵顯示器:光柵掃描式圖形顯示器簡稱光柵顯示器,是畫點設備,可看作是一個點陣單元發生器,並可控制每個點陣單元的亮度
2、由來:隨著光柵顯示器的出現,為了在計算機上處理、顯示圖形,需要發展一
SpringBoot與Dubbo整合有幾種方式,通常需要根據專案實際情況來進行選擇。
SpringBoot與dubbo整合的三種方式:
1)匯入dubbo-starter,在application.properties配置屬性,使用@Service【暴露服務】使用@Referen 填充 tro 如何 sql 網絡路由 2.3 ply ios 查找 1.1 TCP SYN拒絕服務攻擊
一般情況下,一個TCP連接的建立需要經過三次握手的過程,即:
1、 建立發起者向目標計算機發送一個TCP SYN報文;
2、目標計算機收到這個SYN報文後,在內存中創建T
以下排序演算法,預設的排序結果是從小到大。
一.氣泡排序:
1.氣泡排序思想:越大的元素,就像越大的氣泡。最大的氣泡才能夠浮到最高的位置。
具體來說,即,氣泡排序有兩層迴圈,外層迴圈控制每一輪排序中操作元素的個數——氣泡排序每一輪都會找到遍歷到的元素的最大值,並把它放在最後,下一輪排序時
利用Chrome的後臺網路,分析了通過JQuery的$.ajax()把 json 資料 post 給 PHP時的幾種情況:
無法在PHP中通過$_POST 以及 $_REQUEST 獲取json資料,即
$json = $_POST['json']; |