日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

递归分形--山脉

發(fā)布時(shí)間:2023/12/18 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 递归分形--山脉 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

繪制面板

public class DrawPanel extends JFrame{static Graphics g;ImageObserver imageObserver;public Graphics getG() {return g;}public void ShowUi() {//流式布局this.setLayout(new FlowLayout());Button button1 = new Button("山脈");Button button2 = new Button("三角");Button button3 = new Button("矩形");Button button4 = new Button("3D");Dimension dimension = new Dimension(20,20);button1.setSize(dimension);button2.setSize(dimension);button3.setSize(dimension);button4.setSize(dimension);this.setSize(600, 500);this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setLocationRelativeTo(null);this.add(button1);this.add(button2);this.add(button3);this.add(button4);this.setVisible(true);//得到畫(huà)布,一定要設(shè)置在可見(jiàn)之后this.g = this.getGraphics();//每種圖形的動(dòng)作監(jiān)聽(tīng)ButtonAction buttonAction = new ButtonAction(this.g, this);Triangle triangle = new Triangle(g);Rect rect = new Rect(g);Draw3D draw3D = new Draw3D(g);button1.addActionListener(buttonAction);button2.addActionListener(triangle);button3.addActionListener(rect);button4.addActionListener(draw3D);}public void paint(Graphics g){super.paint(g);Color c = new Color(9, 7, 7, 60);g.setColor(c);g.fillRect(0,0, this.getWidth(), this.getHeight());Color color = new Color(129, 62, 19, 255);Font font = new Font("楷體", Font.BOLD, 20);g.setFont(font);g.setColor(color);String s = "Coding like poetry";g.drawString(s, 200, 100);}

注意:

  • button需要流式布局,傳入dimension確定大小
  • Graphics對(duì)象從JFrame中獲取

綁定按鍵事件

其中以下動(dòng)作是綁定按鍵事件:

ButtonAction buttonAction = new ButtonAction(this.g, this);Triangle triangle = new Triangle(g);Rect rect = new Rect(g);Draw3D draw3D = new Draw3D(g);button1.addActionListener(buttonAction);button2.addActionListener(triangle);button3.addActionListener(rect);button4.addActionListener(draw3D);

先創(chuàng)建每個(gè)監(jiān)聽(tīng)器對(duì)象,其中每個(gè)對(duì)象都繼承自ActionListener,并且傳入一個(gè)Graphics對(duì)象用于畫(huà)圖

paint方法

用于繪制畫(huà)布,設(shè)置背景文字等

隨著窗口的加載而加載,也就是說(shuō)在拖動(dòng)窗口時(shí),會(huì)再次調(diào)用此方法

繪制山脈RandomNoise

public class RandomNoise {private int[] xLabel;private int[] yLabel;public void draw(Graphics g, int startX, int endX, int startY, int endY, int deep, int range) {range *= 0.62;//定義填充xLabel = new int[] {startX, endX, startX,endX,startX };yLabel = new int[] {startY, endY, 500, 500, startY};if(deep-- < 0) {Color color = new Color(71, 76, 56, 100);g.setColor(color);g.drawLine(startX, startY, endX, endY);g.fillPolygon(xLabel, yLabel, 5);return;}//count和遞歸次數(shù)的關(guān)系int midX = startX + ((endX - startX) / 2);int midY = startY + ((endY - startY) / 2);//取得隨機(jī)數(shù),記錄遞歸次數(shù)midY = swift(midY, range);//左邊draw(g, startX, midX, startY, midY, deep, range);//右邊draw(g, midX, endX, midY, endY, deep,range);}public int swift(int y, double count) {return y += (Math.random() * 2-1) * count;} }

注意:

  • 在遞歸函數(shù)壓棧的時(shí)候,是劃分點(diǎn)
  • 基條件內(nèi)些了畫(huà)圖方法,所以彈棧的時(shí)候是開(kāi)始劃線

效果:

繪制三角形

遞歸思想兩大要點(diǎn):

  • 基條件
  • 劃分子問(wèn)題,不用想是如何完成的
  • 三角形demo:

    public void drawTri(Graphics g, int x1, int y1, int x2, int y2, int x3, int y3,int deep, double range, boolean flag) {xLabel = new int[] {x1, x2, x3};yLabel = new int[] {y1, y2, y3};int swiftY1 = 0;int swiftY2 = 0;int swiftY3 = 0;if(deep-- < 0) {Color color = new Color(31, 191, 167, 190);g.fillPolygon(xLabel, yLabel, 3);g.setColor(color);g.drawPolygon(xLabel, yLabel, 3);return;}range *= 0.62;count++;//通過(guò)初始點(diǎn),和長(zhǎng)度計(jì)算三個(gè)點(diǎn)//取中點(diǎn),x三個(gè),y一個(gè)int midX1 = (x1 + x2) / 2;int midX2 = (x2 + x3) / 2;int midX3 = (x3 + x1) / 2;int midY1 = (y1 + y2) / 2;int midY2 = (y2 + y3) / 2;int midY3 = (y3 + y1) / 2;//通過(guò)震蕩,如果已經(jīng)被劃分過(guò),則不用劃分,檢測(cè)是否被劃分的機(jī)制是什么?if (flag) {//拿到之前的中點(diǎn),如何拿到之前的中點(diǎn)?swiftY1 = midY1;swiftY2 = midY2;swiftY3 = midY3;} else{swiftY1 = swift(midY1, range);swiftY2 = swift(midY2, range);swiftY3 = swift(midY3, range);}drawTri(g, x1, y1, midX1, swiftY1, midX3, swiftY3, deep, range, false);drawTri(g, midX1, swiftY1, x2, y2, midX2, swiftY2, deep, range,false);drawTri(g, midX3, swiftY3, midX2, swiftY2, x3, y3, deep, range, false);//需要遞歸中間三角, 這樣的子問(wèn)題不一樣 // drawTri(g, midX2, swiftY2, midX3, swiftY3, midX1, swiftY1, deep, range, true);}

    問(wèn)題:遞歸中間的倒三角形

    沒(méi)有遞歸中間的倒三角:

    倒三角遞歸的時(shí)候,問(wèn)題在于三角形邊中點(diǎn)已經(jīng)被處理了,再處理必然會(huì)導(dǎo)致兩次結(jié)果不相同:

    導(dǎo)致中間有斷層

    初步解決辦法:

    給倒三角遞歸的一部分打上標(biāo)記。即,flag = true。

    正三角flag = false

    通過(guò)查看遞歸過(guò)程,在到倒三角遞歸時(shí),依然在選取中點(diǎn),震蕩值。所以會(huì)造成中間的誤差。

    如何在此次遞歸時(shí)能夠調(diào)用之前已經(jīng)震蕩好的值?

    • 維護(hù)點(diǎn)和邊之間的關(guān)系。

    方案一:map

    if(flag){swiftY1 = map.get(midX1);swiftY2 = map.get(midX2);swiftY3 = map.get(midX3);} else{swiftY1 = swift(midY1,range);swiftY2 = swift(midY2,range);swiftY3 = swift(midY3,range);map.put(midX1,swiftY1);map.put(midX2,swiftY2);map.put(midX3,swiftY3);}

    把X中點(diǎn)和處理后的Y點(diǎn)通過(guò)映射確定。

    map.put(midX1,swiftY1);map.put(midX2,swiftY2);map.put(midX3,swiftY3);

    通過(guò)遞歸函數(shù)確定倒三角形的midX1就是x1 和 y1的值

    drawTri(g, midX2, swiftY2, midX3, swiftY3, midX1, swiftY1, deep, range, true);public void drawTri(Graphics g, int x1, int y1, int x2, int y2, int x3, int y3,int deep, double range, boolean flag) {

    問(wèn)題:取某條邊的中點(diǎn)是不準(zhǔn)確的,可能會(huì)有兩個(gè)相等的中點(diǎn),此時(shí)哈希沖突了,覆蓋了原來(lái)的值,任然會(huì)有空隙。

    改進(jìn):方案二 - 邊對(duì)象作為Key

    問(wèn)題1:在存入對(duì)象時(shí),new一個(gè)新對(duì)象放在map中,但是如何取出對(duì)象?

    問(wèn)題2:在遞歸倒三角的時(shí)候,flag為true,但是倒三角中還有正三角,那么此時(shí)就無(wú)法遞歸正三角,

    所以取消標(biāo)志位flag

    第一層是沒(méi)有影響的,因?yàn)閭魅氲臅r(shí)候flag為true;但是到了第二層沒(méi)有辦法遞歸正的三角形。

    檢測(cè)核心代碼如下:

    if(map.containsKey(lineObject.getLine(x1, y1, x2, y2) )) {swiftY1 = map.get(lineObject.getLine(x1, y1, x2, y2));} else if (map.containsKey(lineObject.getLine(x2, y2, x3, y3))) {swiftY2 = map.get(lineObject.getLine(x2, y2, x3, y3));} else if(map.containsKey(lineObject.getLine(x2, y2, x3, y3)) ) {swiftY3 = map.get(lineObject.getLine(x3, y3, x1, y1));} else{swiftY1 = swift(midY1,range);swiftY2 = swift(midY2,range);swiftY3 = swift(midY3,range);}//邊對(duì)象對(duì)應(yīng),震蕩點(diǎn)//存入邊對(duì)象map.put(new LineObject(x1, y1, x2, y2), swiftY1);map.put(new LineObject(x2, y2, x3, y3), swiftY2);map.put(new LineObject(x3, y3, x1, y1), swiftY3);

    問(wèn)題3:

    map.containsKey(lineObject.getLine(x1, y1, x2, y2)

    檢查的是對(duì)象地址而不是中間的值,所以判斷會(huì)跳過(guò):

    最外層的點(diǎn)確定好以后,開(kāi)始遞歸頂三角,然后頂三角中的倒三角,此時(shí)倒三角傳入的值是已經(jīng)處理過(guò)的,

    問(wèn)題4:鍵的匹配出現(xiàn)問(wèn)題,該如何查找map中的鍵 ?

    此時(shí)鍵是一個(gè)LineObject對(duì)象,map如何查找?

    通過(guò)迭代器遍歷鍵對(duì)象,再比較四個(gè)點(diǎn):

    public boolean verify(int x1, int y1, int x2, int y2) {Iterator<Object> iterator = map.keySet().iterator();while(iterator.hasNext()) {LineObject next = (LineObject) iterator.next();if(next.x1 == x1 && next.x2 == x2 && next.y1 == y1 && next.y2 == y2) {shiftY = map.get(next);return true;}}return false;}

    在遞歸函數(shù)中的校驗(yàn)部分如下:

    if(verify(x2, y2, x1, y1)){shiftY1 = shiftY;} else{shiftY1 = shift(midY1,range);}if (verify(x3, y3, x2, y2)) {shiftY2 = shiftY;} else {shiftY2 = shift(midY2,range);}if(verify(x1, y1, x3, y3)) {shiftY3 = shiftY;} else{shiftY3 = shift(midY3,range);}

    此時(shí)傳入的點(diǎn)一定要對(duì)應(yīng)。

    完成效果

    效果如圖:

    改進(jìn)問(wèn)題4

    在問(wèn)題4的改進(jìn)方法中,用迭代器遍歷鍵,效率是非常低下的。

    在遞歸層數(shù)逐漸增加的時(shí)候,山脈出現(xiàn)的速度會(huì)非常慢

    在Java編程思想中有這樣一句話:

    當(dāng)鍵為一個(gè)對(duì)象時(shí),一定要重寫(xiě)hashCode和equals方法

    也就是說(shuō)一定要通過(guò)鍵對(duì)象去查找值,如果是迭代器遍歷,那么用HashMap來(lái)做什么呢?

    所以重寫(xiě)hashCode和equals:

    @Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;LineObject that = (LineObject) o;return x1 == that.x1 &&y1 == that.y1 &&x2 == that.x2 &&y2 == that.y2;}@Overridepublic int hashCode() {return Objects.hash(x1, y1, x2, y2);}

    再修改校驗(yàn)機(jī)制:

    public boolean verify(int x1, int y1, int x2, int y2) {LineObject lineObject = new LineObject(x1, y1, x2, y2);if(map.containsKey(lineObject)){shiftY = map.get(lineObject);return true;}return false;}

    此時(shí)可以看到和之間的不同就是

    • 新建一個(gè)對(duì)象,拿這個(gè)對(duì)象去查找;而不是用迭代器去比較,時(shí)間復(fù)雜度大大降低

    初步修改參數(shù)(遞歸層數(shù),去除填充)得到的圖形如下:

    山脈群

    通過(guò)拼接多個(gè)三角形就能形成圖下效果:

    各位小伙伴多多交流 😃
    個(gè)人網(wǎng)站:blog.vanguo996.cn
    vx:

    總結(jié)

    以上是生活随笔為你收集整理的递归分形--山脉的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。