Melkman凸包演算法的Java實現
座標物件:
public class Point{ private float x; //X座標 private float y; //Y座標 private double arCos; //與P0點的角度 public float getX() { return x; } public void setX(float x) { this.x = x; } public float getY() { return y; } public void setY(float y) { this.y = y; } public double getArCos() { return arCos; } public void setArCos(double arCos) { this.arCos = arCos; } }
演算法與測試:
package Melkman; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * Melkman求凸包演算法 * @author zl */ public class Melkman { private Point[] pointArray;//座標陣列 private final int N;//資料個數 private int D[]; // 陣列索引 public Melkman(List<Point> pList) { this.pointArray = new Point[pList.size()]; N = pList.size(); int k = 0; for (Point p : pList) { pointArray[k++] = p; } D = new int[2 * N]; } /** * 求凸包點 * * @return 所求凸包點 */ public Point[] getTubaoPoint() { // 獲得最小的Y,作為P0點 float minY = pointArray[0].getY(); int j = 0; for (int i = 1; i < N; i++) { if (pointArray[i].getY() < minY) { minY = pointArray[i].getY(); j = i; } } swap(0, j); // 計算除第一頂點外的其餘頂點到第一點的線段與x軸的夾角 for (int i = 1; i < N; i++) { pointArray[i].setArCos(angle(i)); } quickSort(1, N - 1); // 根據所得到的角度進行快速排序 int bot = N - 1; int top = N; D[top++] = 0; D[top++] = 1; int i; for (i = 2; i < N; i++) {// 尋找第三個點 要保證3個點不共線!! if (isLeft(pointArray[D[top - 2]], pointArray[D[top - 1]], pointArray[i]) != 0) break; D[top - 1] = i; // 共線就更換頂點 } D[bot--] = i; D[top++] = i; // i是第三個點 不共線!! int t; if (isLeft(pointArray[D[N]], pointArray[D[N + 1]], pointArray[D[N + 2]]) < 0) { // 此時佇列中有3個點,要保證3個點a,b,c是成逆時針的,不是就調換ab t = D[N]; D[N] = D[N + 1]; D[N + 1] = t; } for (i++; i < N; i++) { // 如果成立就是i在凸包內,跳過 //top=n+3 bot=n-2 if (isLeft(pointArray[D[top - 2]], pointArray[D[top - 1]], pointArray[i]) > 0 && isLeft(pointArray[D[bot + 1]], pointArray[D[bot + 2]], pointArray[i]) > 0) { continue; } //非左轉 則退棧 while (isLeft(pointArray[D[top - 2]], pointArray[D[top - 1]], pointArray[i]) <= 0) { top--; } D[top++] = i; //反向表非左轉 則退棧 while (isLeft(pointArray[D[bot + 1]], pointArray[D[bot + 2]], pointArray[i]) <= 0) { bot++; } D[bot--] = i; } // 凸包構造完成,D數組裡bot+1至top-1內就是凸包的序列(頭尾是同一點) Point[] resultPoints = new Point[top - bot - 1]; int index = 0; for (i = bot + 1; i < top - 1; i++) { System.out.println(pointArray[D[i]].getX() + "," + pointArray[D[i]].getY()); resultPoints[index++] = pointArray[D[i]]; } return resultPoints; } /** * 判斷ba相對ao是不是左轉 * * @return 大於0則左轉 */ private float isLeft(Point o, Point a, Point b) { float aoX = a.getX() - o.getX(); float aoY = a.getY() - o.getY(); float baX = b.getX() - a.getX(); float baY = b.getY() - a.getY(); return aoX * baY - aoY * baX; } /** * 實現陣列交換 * * @param i * @param j */ private void swap(int i, int j) { Point tempPoint = new Point(); tempPoint.setX(pointArray[j].getX()); tempPoint.setY(pointArray[j].getY()); tempPoint.setArCos(pointArray[j].getArCos()); pointArray[j].setX(pointArray[i].getX()); pointArray[j].setY(pointArray[i].getY()); pointArray[j].setArCos(pointArray[i].getArCos()); pointArray[i].setX(tempPoint.getX()); pointArray[i].setY(tempPoint.getY()); pointArray[i].setArCos(tempPoint.getArCos()); } /** * 快速排序 * * @param top * @param bot */ private void quickSort(int top, int bot) { int pos; if (top < bot) { pos = loc(top, bot); quickSort(top, pos - 1); quickSort(pos + 1, bot); } } /** * 移動起點,左側為小,右側為大 * * @param top * @param bot * @return 移動後的位置 */ private int loc(int top, int bot) { double x = pointArray[top].getArCos(); int j, k; j = top + 1; k = bot; while (true) { while (j < bot && pointArray[j].getArCos() < x) j++; while (k > top && pointArray[k].getArCos() > x) k--; if (j >= k) break; swap(j, k); } swap(top, k); return k; } /** * 角度計算 * * @param i 指標 * @return */ private double angle(int i) { double j, k, m, h; j = pointArray[i].getX() - pointArray[0].getX(); k = pointArray[i].getY() - pointArray[0].getY(); m = Math.sqrt(j * j + k * k); // 得到頂點i 到第一頂點的線段長度 if (k < 0) j = (-1) * Math.abs(j); h = Math.acos(j / m); // 得到該線段與x軸的角度 return h; } public static void main(String args[]) { // File file = new File("G:/yl.txt"); File file = new File("G:/data.txt"); BufferedReader br = null; try { br = new BufferedReader(new FileReader(file)); } catch (FileNotFoundException e) { e.printStackTrace(); } List<Point> pointList = new ArrayList<Point>(); String str = null; try { str = br.readLine(); } catch (IOException e) { e.printStackTrace(); } while (str != null) { String[] s = str.split("\\t", 2); float x = Float.parseFloat(s[0].trim()); float y = Float.parseFloat(s[1].trim()); Point p = new Point(); p.setX(x); p.setY(y); // System.out.println("檔案資料:" + x + ", " + y); pointList.add(p); try { str = br.readLine(); } catch (IOException e) { e.printStackTrace(); } } System.out.println("資料個數:" + pointList.size()); Melkman m = new Melkman(pointList); m.getTubaoPoint(); } }
相關推薦
Melkman凸包演算法的Java實現
座標物件: public class Point{ private float x; //X座標 private float y; //Y座標 private double arCos; //與P0點的角度 public float getX()
快速和改進的二維凸包演算法及其在O(n log h)中的實現(實現部分)
此篇接上一篇部落格http://blog.csdn.net/firstchange/article/details/78588669 實施選擇 陣列與列表 “List”類是一個C#集合,它使用一個數組作為其底層容器。使用“列表”而不是陣列應該有類似的效能。測試證實,
快速和改進的二維凸包演算法及其在O(n log h)中的實現(理論部分)
在國外某知名網站上瀏覽資訊時發現了一篇非常好的論文,因為是英文的,自己翻譯、整理了一下,如果想看原始的可以去以下連結:https://www.codeproject.com/Articles/1210225/Fast-and-improved-D-Convex-Hull-algorithm-
基於Graham掃描線演算法的更加強大的凸包演算法——Melkman演算法
大家好,這裡是蒟蒻霞客,thewalker88 今天我來給大家講解一種OI中很少有人使用,然而在我看來比常用的Graham掃描線演算法更為強大的演算法——Mlekman演算法 為了學習這個新演算法,你需要如下前置技能: 1),會計算幾何基礎,尤其是叉積
基本排序演算法-java實現
最近重新學習了排序演算法,之前每次看完當時理解了,但是過一段時間就又忘了,尤其是程式碼,如果放一段時間有很多base case不知道怎麼寫了,所以還是應該詳細的解讀一下再不斷了敲程式碼才能理解比較深刻。 1.氣泡排序(bubble sort) 氣泡排序是一種簡單的排序演算法。其基本思
編輯距離演算法Java實現
/** * 計算編輯距離Edit Distance * if i == 0 且 j == 0,edit(i, j) = 0 * if i == 0 且 j > 0,edit(i, j) = j * if i > 0 且j == 0,edit(i,
分散式ID 雪花演算法JAVA實現
少年不想寫,來吧:https://github.com/singgel/SnowFlake snowflake的結構如下(每部分用-分開): 概述 分散式系統中,有一些需要使用全域性唯一ID的場景,這種時候為了防止ID衝突可以使用36位的UUID,但是UUID有一些缺點,首先他相對比
氣泡排序演算法java實現
package algorithm; /** * 氣泡排序演算法 * @author su * */ public class BubbleSort { public static void main(String[] args) { int[] a = {6,2,5,4,7,1,
0-1揹包問題—回溯演算法—java實現
0-1揹包問題 【問題描述】 有n種可選物品1,…,n ,放入容量為c的揹包內,使裝入的物品具有最大效益。 表示 n :物品個數 c :揹包容量 p1,p2, …, pn:個體物品效益值 w1,w2, …,wn:個體物品容量 【問題解析】 0-1揹包問題的解指:物品1,…,n的一種放
推特雪花演算法 java實現
package twiter.snowflake; /** * twitter的snowflake演算法 -- java實現 */ public class SnowFlake { /** * 起始的時間戳 */ private final static long
最小生成樹Prim演算法java實現
package prim; import java.util.*; public class PrimTest { public static void main(String[] args) { //互動輸入圖的鄰接矩陣表示,為方便測試,直接給定了鄰接矩陣值 // System
凸包演算法(Graham掃描法)
目錄 一、概念 二、演算法步驟 三、程式碼實現 轉自:https://www.cnblogs.com/aiguona/p/7232243.html 一、概念 凸包(Convex Hull)是一個計算幾何(圖形學)中的概念。 在一個實數向量空間V中,對於給定集合X,所有
Dijkstra演算法-Java實現
給定n個城市,並建立一個n*n的距離矩陣來存放兩兩城市之間的距離,當兩個城市之間不能直達時,將距離記為無窮大。對矩陣進行初始化: for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) {
分治法求二維凸包問題java
https://blog.csdn.net/bone_ace/article/details/46239187 見解法2。 有一點需要說明的是,如果有多個到直線p1 pn的距離都最大的點,找pmax使的∠pmax p1 pn最大 下面為java程式碼 package fd; impo
反轉連結串列演算法Java實現
之前遇到反轉連結串列的演算法,比較晦澀難解,但其實挺簡單的。 目標:將一個順序連結串列反轉。 思路:用三個輔助節點,每次實現一個節點的指向反轉,即他的後繼變為他的前驅。 三個輔助節點: p q r&n
【資料結構與演算法-java實現】二 複雜度分析(下):最好、最壞、平均、均攤時間複雜度的概念
上一篇文章學習了:如何分析、統計演算法的執行效率和資源消耗? 點選連結檢視上一篇文章:複雜度分析上 今天的文章學習以下內容: 最好情況時間複雜度 最壞情況時間複雜度 平均情況時間複雜度 均攤時間複雜度 1、最好與最壞情況時間複雜度 我們首先
6種排序演算法java實現
6種排序演算法 氣泡排序 選擇排序 插入排序 計數排序 快速排序 歸併排序 1)氣泡排序 相鄰的兩個數字比較排序,先將最大的交換到最後面,然後重複。 程式碼實現 2)選擇排序 從第一個位置開始,用某個位置依次與後邊所有元
連結串列排序演算法java實現(連結串列的快速排序、插入排序、歸併排序)
難易程度:★★ 重要性:★★★ 連結串列的排序相對陣列的排序更為複雜些,也是考察求職者是否真正理解了排序演算法(而不是“死記硬背”) 連結串列的插入排序 public class LinkedInsertSort { static cla
經典排序演算法 — java 實現
排序演算法的好壞對於效率的影響十分顯著。好的排序演算法排序100萬個整數可能只需要一秒(不考慮硬體因素),不好的排序演算法可能需要一個小時甚至幾個小時。 常見的排序演算法有氣泡排序、插入排序、堆排序、快速排序等,這些排序都屬於基於比較的排序,因此這些演算法的時間
Dijkstra演算法 java實現
import java.util.HashMap; import java.util.HashSet; import java.util.Map.Entry; /** * * Dijkstra演算法 * 適用範圍:沒有權值為負數的邊 * */ // no ne