您的位置:首页 > 编程语言 > Java开发

贪心算法+Java实现C的函数指针

2015-11-12 17:16 495 查看
先囧一下,其实本来没有这篇的。

最近在读算法的相关书籍,正好读到贪心算法,大家知道算法的书籍大多是通过C或C++来提供源码的,贪心算法经常会涉及到多个计算结果的对比然后取最优解,C++的处理方式一般都是函数指针,提供一个类似函数指针的数组,然后遍历循环每个函数获得result的结果集。然而java是没有指针的,当然更没有函数指针这一说,那遇到这种情况我们代码要怎么写呢。

百度喵了一眼,看到两个字,接口。

没错,就是接口。接口 + 多态,抽象来看不就是一个方法,多个实现嘛。不过区别在于函数指针可以随便指定函数,而接口相当于一个规范,不满足这个规范的方法我们是无法通过接口去调用的。不过,既然现在需求是循环一系列函数获取某个值并进行比较,那这些函数一定是遵循一个规范的,所以我们用接口一定可以搞定。

顺便简单介绍下贪心算法:

贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。

贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。

贪心算法的经典问题就是0-1背包问题,N个物品,1个背包,每个物品的重量为w1到wN,价值为p1到pN,背包能承载的最大重量为C,求解最优的装法。当然前提是物品只有装和不装两个选择,不存在装多个的问题,所以叫01背包问题。

好了,铺垫完了,上代码:

package com.amuro.greedy;

public class Goods
{
public int weight;
public int price;
}


首先定义我们的物品类,封装重量和价值。下面定义接口:

package com.amuro.greedy.algorithm;

import java.util.List;

import com.amuro.greedy.Goods;

public interface IGreedy
{
public static final int CAPACITY = 150;

public int getResult(List<Goods> goodsList);
}


很简单,就一个getResult方法来获取算法的结果,而CAPACITY为设定的背包的最大重量。然后来看三个贪心的实现,分别是:每次取最贵的,每次取最轻的(让物品数量最多),每次取价格密度最高的(price / weight):

package com.amuro.greedy.algorithm;

import java.util.ArrayList;
import java.util.List;

import com.amuro.greedy.Goods;

/**
* 每次优先选最贵的
* @author Amuro
*
*/
public class Greedy1 implements IGreedy
{

@Override
public int getResult(List<Goods> goodsList)
{
if(goodsList == null || goodsList.size() == 0)
{
return -1;
}

@SuppressWarnings("unchecked")
List<Goods> tempList = (List<Goods>) ((ArrayList<Goods>)goodsList).clone();

int result = 0;
int currentWeight = 0;

while(true)
{
Goods maxPriceGoods = selectTheMostExpensiveGoods(tempList);

currentWeight += maxPriceGoods.weight;

if(currentWeight > 150)
{
break;
}

result += maxPriceGoods.price;
tempList.remove(maxPriceGoods);
}

return result;
}

private Goods selectTheMostExpensiveGoods(List<Goods> tempList)
{
Goods maxPriceGoods = tempList.get(0);

for(int i = 1; i < tempList.size(); i++)
{
Goods goods = tempList.get(i);

if(goods.price > maxPriceGoods.price)
{
maxPriceGoods = goods;
}
}

return maxPriceGoods;
}

}


package com.amuro.greedy.algorithm;

import java.util.ArrayList;
import java.util.List;

import com.amuro.greedy.Goods;

/**
* 每次选最轻的
* @author Amuro
*
*/
public class Greedy2 implements IGreedy
{

@Override
public int getResult(List<Goods> goodsList)
{
if(goodsList == null || goodsList.size() == 0)
{
return -1;
}

@SuppressWarnings("unchecked")
List<Goods> tempList = (List<Goods>) ((ArrayList<Goods>)goodsList).clone();

int result = 0;
int currentWeight = 0;

while(true)
{
Goods lightestGoods = selectedTheLightestGoods(tempList);

currentWeight += lightestGoods.weight;

if(currentWeight > 150)
{
break;
}

result += lightestGoods.price;
tempList.remove(lightestGoods);
}

return result;
}

private Goods selectedTheLightestGoods(List<Goods> tempList)
{
Goods lightestGoods = tempList.get(0);

for(int i = 1; i < tempList.size(); i++)
{
Goods goods = tempList.get(i);
if(goods.weight < lightestGoods.weight)
{
lightestGoods = goods;
}
}

return lightestGoods;
}

}


package com.amuro.greedy.algorithm;

import java.util.ArrayList;
import java.util.List;

import com.amuro.greedy.Goods;

/**
* 每次选价值密度最高的
* @author Amuro
*
*/
public class Greedy3 implements IGreedy
{

@Override
public int getResult(List<Goods> goodsList)
{
if(goodsList == null || goodsList.size() == 0)
{
return -1;
}

@SuppressWarnings("unchecked")
List<Goods> tempList = (List<Goods>) ((ArrayList<Goods>)goodsList).clone();

int result = 0;
int currentWeight = 0;

while(true)
{
Goods mostDensityGoods = selectedMostDensityGoods(tempList);

currentWeight += mostDensityGoods.weight;

if(currentWeight > 150)
{
break;
}

result += mostDensityGoods.price;
tempList.remove(mostDensityGoods);
}

return result;
}

private Goods selectedMostDensityGoods(List<Goods> tempList)
{
Goods mostDensityGoods = tempList.get(0);

for(int i = 1; i < tempList.size(); i++)
{
Goods goods = tempList.get(i);

float mostDensity = mostDensityGoods.price / mostDensityGoods.weight;
float currentDensity = goods.price / goods.weight;

if(currentDensity > mostDensity)
{
mostDensityGoods = goods;
}

}

return mostDensityGoods;
}
}


代码很好理解,就不多说了,注意拿到传进来的list记得要clone,不然做了remove操作后,原来的list也被你改了。这里发现个bug,就是循环退出的条件不够,如果所有物品重量加起来都没有超过150程序就要死循环了,嘛,如果这样这个最优解也没有意义了,各位可自行修改,本来重点也不是这个。

好,当我们涉及多个算法的时候,脑子里的第一反应是什么,没错,策略模式,我们需要封装一个类供外部调用,隐藏算法的细节和调用方式。来看GreedyManager类:

package com.amuro.greedy;

import java.util.List;

import com.amuro.greedy.algorithm.IGreedy;

public class GreedyManager
{
private List<Goods> goodsList;

private String[] algorithems = {
"com.amuro.greedy.algorithm.Greedy1",
"com.amuro.greedy.algorithm.Greedy2",
"com.amuro.greedy.algorithm.Greedy3"};

public GreedyManager(List<Goods> goodsList)
{
this.goodsList = goodsList;
}

public int doAlgorithm() throws InstantiationException, IllegalAccessException, ClassNotFoundException
{
int result = getClass(algorithems[0]).getResult(goodsList);

for(int i = 1;i < algorithems.length; i++)
{
int temp = getClass(algorithems[i]).getResult(goodsList);
if(temp > result)
{
result = temp;
}
}

return result;
}

private IGreedy getClass(String className) throws InstantiationException, IllegalAccessException, ClassNotFoundException
{
return ((IGreedy)Class.forName(className).newInstance());
}
}


OK,这篇的重点基本都在这个类了。C++的函数指针数组我们没法实现,但别忘了我们有反射,所以我们可以配置一个类名的数组供循环来调用。然后通过循环,得到每一种贪心计算结果的result,再取出最大的结果给外部调用者。以后再有新的贪心计算规则时,只要增加一个IGreedy的子类,并在数组中增加一个String就可以啦~ 传说中的对修改关闭,对扩展开放。

最后看一下客户端调用:

package com.amuro.greedy;

import java.util.ArrayList;
import java.util.List;

public class Client
{
public static void main(String[] args)
{
Client clt = new Client();
clt.doAlgorithm();
}

private List<Goods> goodsList;
private GreedyManager greedyManager;

public Client()
{
init();
}

private int[] weights = {35, 30, 60, 50, 40, 10, 25};
private int[] prices = {10, 40, 30, 50, 35, 40, 30};

private void init()
{
goodsList = new ArrayList<>();

for(int i = 0;i < weights.length;i++)
{
Goods goods = new Goods();
goods.weight = weights[i];
goods.price = prices[i];

goodsList.add(goods);
}

greedyManager = new GreedyManager(goodsList);

}

public void doAlgorithm()
{
try
{
System.out.println("Result->" + greedyManager.doAlgorithm());
}
catch (InstantiationException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
}
}


看一下输出结果:Result->170。

大家有兴趣可以自己算一下,第三种贪心算法就是最优解170~

就酱~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: