1. 程式人生 > >Melkman凸包演算法的Java實現

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