Java程序中带有图和内部类的无限循环
好的,所以我的任务是,给我一个捐款清单和一组项目(下面给出的课程),我必须看看是否所有的项目都能得到捐款的资助。如果他们不能,它必须取消分配到目前为止分配的所有资金,并返回false。 捐款有一个项目清单,他们可以捐款,并有一定的数额 我选择用一个图表来实现这一点。顶点表示一个项目,连接是它们与其他项目共享的捐赠。它是这样建立的,这样它就可以在捐款中循环,每次向它能资助的每个项目捐赠1美元。如果一个项目无法获得全额资金,但可以通过捐款从与之相关的另一个项目转移资金,则从该项目转移资金。如果无法为所有项目提供资金,则取消分配所有项目并返回false 我的两个问题是: 1) 当需要传输时,我的测试套件将进入无限循环。目前,如果有人能找到我的无限循环问题并在我真正开始工作之前提出一个解决方案使它退出,我会很高兴 这两个给定的类不需要修复,它只是出现问题的第一段代码。我也毫不怀疑,我的graph、node和connector类一点都不好,但它们目前可以工作。我只是在寻找canAllocateHelper方法中的修复程序 注意:很抱歉发布了这么多代码,但大约12小时前我发布了一个类似的问题,我被告知我没有提供足够的代码进行调试,所以我想我应该发布所有内容 我的代码:Java程序中带有图和内部类的无限循环,java,graph,infinite-loop,inner-classes,Java,Graph,Infinite Loop,Inner Classes,好的,所以我的任务是,给我一个捐款清单和一组项目(下面给出的课程),我必须看看是否所有的项目都能得到捐款的资助。如果他们不能,它必须取消分配到目前为止分配的所有资金,并返回false。 捐款有一个项目清单,他们可以捐款,并有一定的数额 我选择用一个图表来实现这一点。顶点表示一个项目,连接是它们与其他项目共享的捐赠。它是这样建立的,这样它就可以在捐款中循环,每次向它能资助的每个项目捐赠1美元。如果一个项目无法获得全额资金,但可以通过捐款从与之相关的另一个项目转移资金,则从该项目转移资金。如果无法为
package a2;
import java.util.*;
import a2.IterativeAllocator.Connector;
import a2.IterativeAllocator.Node;
public class IterativeAllocator {
/**
* @precondition: Neither of the inputs are null or contain null elements.
* The parameter donations is a list of distinct donations
* such that for each d in donations, d.getTotal() equals
* d.getUnspent(); and for each p in projects
* p.allocatedFunding() equals 0.
* @postcondition: returns false if there no way to completely fund all of
* the given projects using the donations, leaving both the
* input list of donations and set of projects unmodified;
* otherwise returns true and allocates to each project
* funding from the donations. The allocation to each
* project must be complete and may not violate the
* conditions of the donations.
*/
public static boolean canAllocate(List<Donation> donations,
Set<Project> projects) {
ArrayList<Node<Project>> nodes = getNodes(donations, projects);
Graph<?> uniGraph = createGraph(nodes);
if (donations.isEmpty()) {
return false;
}
return canAllocateHelper(donations, projects, uniGraph, 0);
}
// Helper Methods
private static boolean canAllocateHelper(List<Donation> donations,
Set<Project> projects, Graph graph, int index ) {
Donation donation = donations.get(index);
Set<Project> p = donation.getProjects();
int count = countFullyFunded(projects);
if (count == projects.size()) { return true; }
if (donation.spent()) {
if (index == donations.size() - 1) { return false; }
return canAllocateHelper(donations, projects, graph, index + 1);
}
int pCount = countFullyFunded(p);
if (pCount == p.size() && (index + 1) < donations.size() ) {
return canAllocateHelper(donations, projects, graph, index + 1);
}
for (int i=0; i < graph.size(); i++) {
Node<Project> tempNode = graph.getNode(i);
Project tempProj = tempNode.getElement();
if (donation.canBeUsedFor(tempProj)) {
if (!tempProj.fullyFunded()) {
if (donation.spent()) {
LinkedList<Connector<Project>> conns = tempNode.getConnections();
for (int k=0; k<conns.size(); k++) {
tempProj.transfer(1, conns.get(k).getSecond().getElement());
canAllocateHelper(donations, projects, graph, index);
}
}
tempProj.allocate(donation, 1);
if (canAllocateHelper(donations, projects, graph, index)) {
return true;
}
tempProj.deallocate(donation, 1);
}
}
}
return false;
}
private static ArrayList<Node<Project>> getNodes(List<Donation> donations,
Set<Project> projects) {
ArrayList<Node<Project>> nodes = new ArrayList<Node<Project>>();
Iterator<Project> pIterator = projects.iterator();
while (pIterator.hasNext()) {
Node<Project> node = new Node<Project>(pIterator.next());
nodes.add(node);
}
// Iterate through donations to get an Array of connections
for (int i=0; i < donations.size(); i++) {
Set<Project> connections = donations.get(i).getProjects();
ArrayList<Node<Project>> cArray = new ArrayList<Node<Project>>();
Iterator<Project> cIterator = connections.iterator();
while (cIterator.hasNext()) {
Node<Project> temp = new Node<Project>(cIterator.next());
cArray.add(temp);
}
// for each node, see if in cArray. If so, connect it
for (int j=0; j < nodes.size(); j++) {
if ( cArray.contains(nodes.get(j))) {
for ( int k = 0; k < cArray.size(); k++) {
nodes.get(j).connect(cArray.get(k),
donations.get(i).getTotal());
}
}
}
}
return nodes;
}
private static Graph<?> createGraph(ArrayList<Node<Project>> nodes) {
Graph<?> graph = new Graph<Object>();
for (int i=0; i < nodes.size(); i++) {
graph.addNode(nodes.get(i));
}
return graph;
}
private static int countFullyFunded(Set<Project> projects) {
Iterator<Project> projectsIterator = projects.iterator();
int count = 0;
while(projectsIterator.hasNext()) {
Project proj = projectsIterator.next();
if (proj.fullyFunded()) {
count++;
}
}
return count;
}
// Private classes
public static class Node<E> {
private int count = 0;
private E element;
private int id;
private LinkedList<Connector<E>> connections;
public Node() {
this(null);
}
public Node(E element) {
this.element = element;
id = count++;
connections = new LinkedList<Connector<E>>();
}
public int getID() {
return id;
}
public E getElement() {
return element;
}
public void setElement(E elem) {
this.element = elem;
}
public void connect(Node<E> newPoint, int cost) {
Connector<E> a = new Connector<E>(this, newPoint, cost);
if(!connections.contains(a)) {
connections.add(a);
}
}
public LinkedList<Connector<E>> getConnections() {
return connections;
}
public void sortConnections() {
Collections.sort(connections);
}
public Iterator<Connector<E>> iterator() {
return connections.iterator();
}
public boolean equals(Node<E> other) {
if(other.connections.size() != connections.size()) {
return false;
}
LinkedList<Connector<E>> temp = new
LinkedList<Connector<E>>(other.getConnections());
return !(temp.retainAll(this.connections));
}
public String toString() {
return this.element.toString();
}
}
public static class Connector<E> implements Comparable<Connector<E>>{
private Node<E> first, second;
private int dist;
public Connector(Node<E> first, Node<E> second){
this(first, second, 0);
}
public Connector(Node<E> first, Node<E> second, int dist){
this.first = first;
this.second = second;
this.dist = dist;
}
public Node<E> getFirst(){
return first;
}
public Node<E> getSecond(){
return second;
}
public int getDistance(){
return dist;
}
public void setDistance(int distance){
this.dist = distance;
}
public boolean equals(Connector<E> other){
return first.equals(other.getFirst()) &&
second.equals(other.getSecond()) &&
dist == other.getDistance();
}
public String toString(){ return "(" + first.getElement() +
", " + second.getElement() + "): " + dist; }
public int compareTo(Connector<E> other){
return this.dist - other.dist;
}
}
private static class Graph<E> {
private ArrayList<Node<E>> nodes;
public Graph() {
nodes = new ArrayList<Node<E>>();
}
public boolean addNode(Node<Project> node) {
if (nodes.contains(node)) {
return false;
}
else {
nodes.add((Node<E>) node);
return true;
}
}
public Node<E> getNode(int index) {
return nodes.get(index);
}
public int size() {
return nodes.size();
}
public boolean equals(Graph<E> other) {
if (other.size() != nodes.size()) {
return false;
}
ArrayList<Node<E>> temp = new ArrayList<Node<E>>(other.nodes);
return temp.retainAll(nodes);
}
}
}
a2包;
导入java.util.*;
导入a2.IterativeAllocator.Connector;
导入a2.IterativeAllocator.Node;
公共类迭代分配器{
/**
*@前提条件:两个输入均不为null或包含null元素。
*参数捐赠是不同捐赠的列表
*这样,对于捐赠中的每个d,d.getTotal()等于
*d.getUnpant();并且对于项目中的每个p
*p.allocatedFunding()等于0。
*@postcondition:如果无法完全资助所有人,则返回false
*使用捐赠的给定项目,留下
*输入捐赠清单和未修改的项目集;
*否则返回true并分配给每个项目
*来自捐款的资金。分配给每个人
*项目必须完整,不得违反合同
*捐赠的条件。
*/
公共捐款(列出捐款,
设置项目){
ArrayList节点=获取节点(捐赠、项目);
图形uniGraph=createGraph(节点);
if(捐赠.isEmpty()){
返回false;
}
返回canAllocateHelper(捐赠、项目、uniGraph,0);
}
//辅助方法
私有静态布尔值canAllocateHelper(列出捐赠,
设置项目、图形、整数索引){
捐赠=捐赠。获取(索引);
Set p=generation.getProjects();
int count=countFullyFunded(项目);
if(count==projects.size()){return true;}
if(捐赠.花费()){
如果(index==.size()-1){return false;}
返回canAllocateHelper(捐赠、项目、图表、索引+1);
}
int pCount=CountFullyFund(p);
如果(pCount==p.size()&(index+1)package a2.test;
import org.junit.*;
import java.util.*;
import a2.*;
/**
* Some tests for the part2.IterativeAllocator.canAllocate method. A much more
* extensive test suite will be used to mark your code, but this should get you
* started writing your own tests to help you to debug your implementation.
*/
public class IterativeAllocatorTest {
@Test
public void basicTestTrue() {
List<Project> projects = new ArrayList<Project>();
ArrayList<Donation> donations = new ArrayList<Donation>();
projects.add(new Project("P0", 100));
projects.add(new Project("P1", 100));
projects.add(new Project("P2", 100));
donations.add(new Donation("D0", 100, new HashSet<Project>(Arrays
.asList(projects.get(0), projects.get(1)))));
donations.add(new Donation("D1", 100, new HashSet<Project>(Arrays
.asList(projects.get(1), projects.get(2)))));
donations.add(new Donation("D2", 50, new HashSet<Project>(Arrays
.asList(projects.get(0)))));
donations.add(new Donation("D3", 50, new HashSet<Project>(Arrays
.asList(projects.get(2)))));
List<Donation> actualDonations = new ArrayList<>(donations);
Set<Project> actualProjects = new HashSet<>(projects);
Assert.assertTrue(IterativeAllocator.canAllocate(actualDonations,
actualProjects));
// no donations should be added or removed from the list of donations
Assert.assertEquals(donations, actualDonations);
// no projects should be added or removed from the set of projects
Assert.assertEquals(new HashSet<>(projects), actualProjects);
// allocation should be complete and valid
checkCompleteAllocation(actualDonations, actualProjects);
}
@Test
public void basicTestFalse() {
List<Project> projects = new ArrayList<Project>();
ArrayList<Donation> donations = new ArrayList<Donation>();
projects.add(new Project("P0", 100));
projects.add(new Project("P1", 100));
projects.add(new Project("P2", 100));
donations.add(new Donation("D0", 100, new HashSet<Project>(Arrays
.asList(projects.get(0), projects.get(1), projects.get(2)))));
donations.add(new Donation("D1", 200, new HashSet<Project>(Arrays
.asList(projects.get(0)))));
List<Donation> actualDonations = new ArrayList<>(donations);
Set<Project> actualProjects = new HashSet<>(projects);
Assert.assertFalse(IterativeAllocator.canAllocate(actualDonations,
actualProjects));
// no donations should be added or removed from the list of donations
Assert.assertEquals(donations, actualDonations);
// no projects should be added or removed from the set of projects
Assert.assertEquals(new HashSet<>(projects), actualProjects);
// no allocations should have been made
checkEmptyAllocation(actualDonations, actualProjects);
}
// basic no transfer test
@Test
public void noTransferTrue() {
List<Project> projects = new ArrayList<Project>();
ArrayList<Donation> donations = new ArrayList<Donation>();
projects.add(new Project("P0", 10));
projects.add(new Project("P1", 10));
projects.add(new Project("P2", 10));
donations.add(new Donation("D0", 10, new HashSet<Project>(Arrays
.asList(projects.get(0), projects.get(1)))));
donations.add(new Donation("D1", 10, new HashSet<Project>(Arrays
.asList(projects.get(1), projects.get(2)))));
donations.add(new Donation("D2", 5, new HashSet<Project>(Arrays
.asList(projects.get(0)))));
donations.add(new Donation("D3", 5, new HashSet<Project>(Arrays
.asList(projects.get(2)))));
List<Donation> actualDonations = new ArrayList<>(donations);
Set<Project> actualProjects = new HashSet<>(projects);
Assert.assertTrue(IterativeAllocator.canAllocate(actualDonations,
actualProjects));
// no donations should be added or removed from the list of donations
Assert.assertEquals(donations, actualDonations);
// no projects should be added or removed from the set of projects
Assert.assertEquals(new HashSet<>(projects), actualProjects);
// allocation should be complete and valid
checkCompleteAllocation(actualDonations, actualProjects);
}
// helper methods
/**
* Helper method to check that each project has been completely allocated by
* the given donations, and that the total spent on each donation is equal
* to that spent on the given projects.
**/
private void checkCompleteAllocation(List<Donation> donations,
Set<Project> projects) {
// the amount spent from each donation by all of the combined projects
Map<Donation, Integer> totalSpent = new HashMap<>();
// check that each project has been completely (and properly) allocated
// and calculate totalSpent
for (Project p : projects) {
Assert.assertTrue(p.fullyFunded());
for (Map.Entry<Donation, Integer> allocation : p.getAllocations()
.entrySet()) {
Donation d = allocation.getKey();
int amount = allocation.getValue();
Assert.assertTrue(amount > 0);
Assert.assertTrue(d.canBeUsedFor(p));
Assert.assertTrue(donations.contains(d));
if (totalSpent.containsKey(d)) {
totalSpent.put(d, totalSpent.get(d) + amount);
} else {
totalSpent.put(d, amount);
}
}
}
// check that the remaining funds in each donation are correct, assuming
// that no funds were spent from each donation to begin with.
for (Donation d : donations) {
if (totalSpent.containsKey(d)) {
Assert.assertTrue(d.getUnspent() >= 0);
Assert.assertEquals(d.getUnspent(),
d.getTotal() - totalSpent.get(d));
} else {
Assert.assertEquals(d.getUnspent(), d.getTotal());
}
}
}
/**
* Helper method to check that no allocations have been made for any project
* in projects and that all donations have not been spent at all.
**/
private void checkEmptyAllocation(List<Donation> donations,
Set<Project> projects) {
for (Project p : projects) {
Assert.assertEquals(p.getCost(), p.neededFunds());
}
for (Donation d : donations) {
Assert.assertEquals(d.getUnspent(), d.getTotal());
}
}
}
package a2;
import java.util.*;
/**
* A class representing a donation. A donation has a name, the total amount of
* the donation, the unspent portion of the donation and a set of projects that
* the donation may be spent on.
*
* DO NOT MODIFY THIS FILE IN ANY WAY.
*/
public class Donation {
// name of donation
private String name;
// total donation amount
private int total;
// amount of donation that has not yet been spent
private int unspent;
// projects that the funds from this donation could be spent on
private Set<Project> projects;
/*
* invariant: name != null && total > 0 && 0 <= unspent <= total &&
* projects!=null
*/
/**
* @precondition: name!= null && total > 0 && projects != null
* @postcondition: creates a new donation with given name, total donation
* amount and projects that this donation could be spent on.
* No funds from the donation have initially been spent.
*/
public Donation(String name, int total, Set<Project> projects) {
assert name != null && projects != null && total > 0;
this.name = name;
this.total = total;
this.projects = projects;
this.unspent = total;
}
/**
* @postcondition: returns the total amount of this donation.
*/
public int getTotal() {
return total;
}
/**
* @postcondition: returns the amount of this donation that hasn't been
* spent yet.
*/
public int getUnspent() {
return unspent;
}
/**
* @postcondition: returns true iff this donation has been totally spent.
*/
public boolean spent() {
return (unspent == 0);
}
/**
* @precondition: 0 <= cost <= getUnspent()
* @postcondition: removes cost from the amount of available funds for this
* donation. The only method that should call this one
* directly is the allocate method from the Project class.
* (That is, it should only be executed as part of an
* allocation of these funds to a particular project.)
*/
public void spend(int cost) {
assert 0 <= cost && cost <= unspent;
unspent = unspent - cost;
}
/**
* @precondition: 0 <= cost <= total - getUnspent()
* @postcondition: adds cost back to the available funds for this donation.
* The only method that should call this one directly is the
* deallocate method from the Project class. (That is, it
* should only be executed as part of the deallocation of
* these funds from a particular project.)
*/
public void unspend(int cost) {
assert 0 <= cost && cost <= total - unspent;
unspent = unspent + cost;
}
/**
* @postcondition: returns true iff this donation is allowed to be spent on
* the given project.
*/
public boolean canBeUsedFor(Project project) {
return projects.contains(project);
}
/**
* @postcondition: returns a (shallow copy of) the set of the projects for
* this donation.
*/
public Set<Project> getProjects() {
return new HashSet<>(projects);
}
}
package a2;
import java.util.*;
/**
* A class representing a project and its current allocation of funds.
*
* DO NOT MODIFY THIS FILE IN ANY WAY.
*/
public class Project {
private String name; // name of project
private int cost; // total cost of the project
private int allocatedFunding; // sum of the funds currently allocated
private Map<Donation, Integer> allocations; // funds currently allocated
/*
* invariant:
*
* cost > 0 && allocatedFunding >= 0 && allocatedFunding <= cost &&
*
* allocations != null && name != null &&
*
* for each entry (d, x) in allocations,
* d!=null && x>0 && d.canBeUsedFor(this) &&
*
* allocatedFunding is the sum of values in the allocations map
*/
/**
* @precondition: name!= null && cost > 0
* @postcondition: creates a new project with given name and cost and an
* initially empty allocation of funds.
*/
public Project(String name, int cost) {
assert (name != null && cost > 0);
this.name = name;
this.cost = cost;
allocations = new HashMap<Donation, Integer>();
allocatedFunding = 0;
}
/**
* @postcondition: returns the total cost of the project.
*/
public int getCost() {
return cost;
}
/**
* @postcondition: returns true if and only if the allocated funds are equal
* to the total cost of the project.
*/
public boolean fullyFunded() {
return (cost == allocatedFunding);
}
/**
* @postcondition: returns the amount of money that is needed to completely
* fund the project.
*/
public int neededFunds() {
return (cost - allocatedFunding);
}
/**
* @postcondition: returns the amount of money currently allocated to the
* project.
*/
public int allocatedFunding() {
return allocatedFunding;
}
/**
* @postcondition: returns (a shallow copy of) the current allocations to
* the project. (Changing the returned map won't change the
* allocations of the project. To do that use the
* allocation, deallocation or transfer methods of this
* class.)
*/
public Map<Donation, Integer> getAllocations() {
return new HashMap<>(allocations);
}
/**
* @precondition: donation!=null && 0 < amount <= donation.getUnspent() &&
* amount <= neededFunds() donation.canBeUsedFor(this)
* @postcondition: spends the given amount of money from the donation by
* allocating it to this project.
*/
public void allocate(Donation donation, int amount) {
assert donation != null;
assert 0 < amount && amount <= donation.getUnspent()
&& amount <= neededFunds() && donation.canBeUsedFor(this);
addToAllocations(donation, amount);
donation.spend(amount);
}
private void addToAllocations(Donation donation, int amount) {
Integer existingAmount = allocations.get(donation);
if (existingAmount == null) {
existingAmount = 0;
}
allocations.put(donation, amount + existingAmount);
allocatedFunding += amount;
}
/**
* @precondition: donation!=null && allocations.containsKey(donation) &&
* allocations.get(donation) >= amount
* @postcondition: puts the given amount of money back into the unspent
* funds for the donation and removes it from the allocation
* to this project.
*/
public void deallocate(Donation donation, int amount) {
assert donation != null;
assert allocations.containsKey(donation);
assert allocations.get(donation) >= amount;
removeFromAllocations(donation, amount);
donation.unspend(amount);
}
/**
* @postcondition: deallocates all allocations to this project.
*/
public void deallocateAll() {
for (Map.Entry<Donation, Integer> entry : allocations.entrySet()) {
Donation d = entry.getKey();
int amount = entry.getValue();
d.unspend(amount);
allocatedFunding -= amount;
}
allocations.clear();
}
private void removeFromAllocations(Donation donation, int amount) {
int existingAmount = allocations.get(donation);
if (existingAmount > amount) {
allocations.put(donation, existingAmount - amount);
} else {
allocations.remove(donation);
}
allocatedFunding -= amount;
}
/**
* @precondition: amount <= neededFunds() && the given amount of money may
* be transferred from the source project to this project
* @postcondition: transfers $amount from source project to this project.
*/
public void transfer(int amount, Project source) {
assert amount <= neededFunds();
Iterator<Map.Entry<Donation, Integer>> it = source.allocations
.entrySet().iterator();
Map.Entry<Donation, Integer> entry;
while (it.hasNext() && amount > 0) {
entry = it.next();
if (entry.getKey().canBeUsedFor(this)) {
int transferAmount = Math.min(amount, entry.getValue());
// deallocate transferAmount from source project
entry.setValue(entry.getValue() - transferAmount);
source.allocatedFunding -= transferAmount;
if (entry.getValue() == 0) {
it.remove();
}
// allocate transfer amount to this project
this.addToAllocations(entry.getKey(), transferAmount);
// update the amount that we have left to transfer
amount = amount - transferAmount;
}
}
}
}
if (donation.spent()) {
if (index == donations.size() - 1) { return false; }
return canAllocateHelper(donations, projects, graph, index + 1);
}
int pCount = countFullyFunded(p);
if (pCount == p.size() && (index + 1) < donations.size() ) {
return canAllocateHelper(donations, projects, graph, index + 1);
}