河内塔与堆Java

时间:2017-06-07 21:15:05

标签: java stack towers-of-hanoi

我正在研究Java中的河内塔问题。我选择使用Stacks作为钉子并且除了移动方法之外一切都有效。我有规范和JUnit测试类,目前我正在通过7个测试中的6个但是在移动测试中失败了。规格如下:

enter image description here

enter image description here

这是我的Towers课程:

package edu.metrostate.ics240.p2.towers;
import java.util.Stack;

public class Towers {
    private static final int DEFAULT_SIZE = 5;
    private static final int MAX_SIZE = 64;
    private static final int MIN_PEG = 1;
    private static final int MAX_PEG = 3;
    private static Stack<Integer>[] tower = new Stack[4];
    private int numOfRings;

public Towers(int n) {
    if (n < 1 || n > MAX_SIZE) 
        throw new IllegalArgumentException(
                String.format("Number of rings (%s) cannot be less than 1 or exceed 64 ", n));
    numOfRings = n;
    tower[1] = new Stack<Integer>();
    tower[2] = new Stack<Integer>();
    tower[3] = new Stack<Integer>();
    for (int i = 1; i <= numOfRings; i++)
        tower[1].push(i);
}
public Towers() {
    numOfRings = DEFAULT_SIZE;
    tower[1] = new Stack<Integer>();
    tower[2] = new Stack<Integer>();
    tower[3] = new Stack<Integer>();
    for (int i = 1; i <= numOfRings; i++)
        tower[1].push(i);
}

private static void pegCheck(int pegNumber){
    if (pegNumber < MIN_PEG || pegNumber > MAX_PEG) 
        throw new IllegalArgumentException(
                String.format("Peg number (%s) cannot be less than 1 or exceed 3 ", pegNumber));
}
public int getRingCount(int pegNumber) {
    pegCheck(pegNumber);

    switch (pegNumber) {
    case 1:
        if (tower[1].isEmpty()) 
            return 0;
        else 
            return tower[1].size();
    case 2:
        if (tower[2].isEmpty()) 
            return 0;
        else 
            return tower[2].size();
    case 3:
        if (tower[3].isEmpty()) 
            return 0;
        else 
            return tower[3].size();
    default:
        return 0;
    }
}
public int getTopDiameter(int pegNumber) {
    pegCheck(pegNumber);

    switch (pegNumber) {
    case 1:
        if(getRingCount(1) > 0){
            return tower[1].get(tower[1].peek() - tower[1].size());
        }else
            return 0;
    case 2:
        if(getRingCount(2) > 0){
            return tower[2].get(tower[2].peek() - tower[2].size());
        }else
            return 0;
    case 3:
        if(getRingCount(3) > 0){
            return tower[3].get(tower[3].peek() - tower[3].size());
        }else
            return 0;
    default:
        return 0;
    }
}
public boolean move(int startPeg, int endPeg) {
    pegCheck(startPeg);
    pegCheck(endPeg);
    Stack<Integer> startTower = tower[startPeg];
    Stack<Integer> endTower = tower[endPeg];


    if (getRingCount(startPeg) > 0 && endPeg != startPeg && getRingCount(endPeg) > 0 && getTopDiameter(startPeg) < getTopDiameter(endPeg)) {
        int topRing = startTower.pop();
        endTower.push(topRing);
        return true;
    }else
        return false;
}
}

最后是JUnit测试:

import static org.junit.Assert.*;
import org.junit.Test;
import edu.metrostate.ics240.p2.towers.*;
import java.util.Random;

public class TowersTest {
    private static final int MAX_NUM_RINGS = 64;
    private static final long SEED = 20170604001L;
    private static final Random RAND = new Random(SEED);

@Test
public void testDefaultConstruction() {
    Towers t = new Towers();
    assertEquals(5, t.getRingCount(1));
    assertEquals(0, t.getRingCount(2));
    assertEquals(0, t.getRingCount(3));

    assertEquals(1, t.getTopDiameter(1));
    assertEquals(0, t.getTopDiameter(2));
    assertEquals(0, t.getTopDiameter(3));
}

@Test
public void testConstruction() {
    int numRings = RAND.nextInt(MAX_NUM_RINGS);
    Towers t = new Towers(numRings);
    assertEquals(numRings, t.getRingCount(1));
    assertEquals(0, t.getRingCount(2));
    assertEquals(0, t.getRingCount(3));

    assertEquals(1, t.getTopDiameter(1));
    assertEquals(0, t.getTopDiameter(2));
    assertEquals(0, t.getTopDiameter(3));
}

@Test
public void testMove() {
    int numRings = RAND.nextInt(64);

    Towers t = new Towers(numRings);

    assertTrue(t.move(1, 2));
    assertEquals(numRings - 1, t.getRingCount(1));
    assertEquals(1, t.getRingCount(2));
    assertEquals(0, t.getRingCount(3));

    assertEquals(2, t.getTopDiameter(1));
    assertEquals(1, t.getTopDiameter(2));
    assertEquals(0, t.getTopDiameter(3));

    assertTrue(t.move(1, 3));
    assertEquals(numRings - 2, t.getRingCount(1));
    assertEquals(1, t.getRingCount(2));
    assertEquals(1, t.getRingCount(3));

    assertEquals(3, t.getTopDiameter(1));
    assertEquals(1, t.getTopDiameter(2));
    assertEquals(2, t.getTopDiameter(3));
}

@Test
public void testInvalidConstructor(){
    Towers t = null;
    try {
        t = new Towers(0); // illegal value
        fail("Expected exception");
    } catch (IllegalArgumentException iae) {
        // expected
    }

    try {
        t = new Towers(MAX_NUM_RINGS + 1); // illegal value
        fail("Expected exception");
    } catch (IllegalArgumentException iae) {
        // expected
    }
}
@Test
public void testPreconditionGetRingCount() {
    Towers t = new Towers();
    try {
        t.getRingCount(0);
        fail("Exception expected");
    } catch (IllegalArgumentException iae) {
        // expected
    }
    try {
        t.getRingCount(4);
        fail("Exception expected");
    } catch (IllegalArgumentException iae) {
        // expected
    }
}

@Test
public void testPreconditionTopRing() {
    Towers t = new Towers();
    try {
        t.getTopDiameter(0);
        fail("Exception expected");
    } catch (IllegalArgumentException iae) {
        // expected
    }
    try {
        t.getTopDiameter(4);
        fail("Exception expected");
    } catch (IllegalArgumentException iae) {
        // expected
    }
}

@Test
public void testIllegalMoves(){
    Towers t = new Towers();

    t.move(1, 2);
    t.move(1, 3);

    assertFalse(t.move(1, 1)); // can't move to itself
    assertFalse(t.move(1, 2)); // moving larger ring to smaller
    assertFalse(t.move(1, 3)); // moving larger ring to smaller
    assertFalse(t.move(3, 2));
}
}

我想我知道我的问题在哪里。如果getTopDiameter(),则getRingCount(pegNum) > 0的前提条件返回顶部环大小,但如果堆栈为空或者挂钩上没有环,则返回0。由于tower[1]是唯一使用响铃初始化而另外两个不挂起的挂钩,getTopDiameter()会返回0,因为当前tower[2]tower[3]上没有响铃。在move()方法中,其中一个先决条件要求getTopdiameter(startPeg)小于getTopDiamater(endPeg),但如果endPeg初始化为0环且因此为空getTopDiamater(endPeg)返回0,在这种情况下显然不小于1。我只是无法弄清楚这一点。非常感谢任何帮助,谢谢你提前!

更新 通过所有测试用例的修订代码:

package edu.metrostate.ics240.p2.towers;

import java.util.Stack;

public class Towers {
    private static final int DEFAULT_SIZE = 5;
    private static final int MAX_SIZE = 64;
    private static final int MIN_PEG = 1;
    private static final int MAX_PEG = 3;
    @SuppressWarnings("unchecked")
    private static Stack<Integer>[] tower = new Stack[4];
    private int numOfRings;

public Towers(int n) {
    if (n < 1 || n > MAX_SIZE)
        throw new IllegalArgumentException(
                String.format("Number of rings (%s) cannot be less than 1 or exceed 64 ", n));
    numOfRings = n;
    tower[1] = new Stack<Integer>();
    tower[2] = new Stack<Integer>();
    tower[3] = new Stack<Integer>();
    for (int i = numOfRings; i >= 1; i--)
        tower[1].push(i);
}

public Towers() {
    numOfRings = DEFAULT_SIZE;
    tower[1] = new Stack<Integer>();
    tower[2] = new Stack<Integer>();
    tower[3] = new Stack<Integer>();
    for (int i = numOfRings; i >= 1; i--)
        tower[1].push(i);
}

private static void pegCheck(int pegNumber) {
    if (pegNumber < MIN_PEG || pegNumber > MAX_PEG)
        throw new IllegalArgumentException(
                String.format("Peg number (%s) cannot be less than 1 or exceed 3 ", pegNumber));
}

public int getRingCount(int pegNumber) {
    pegCheck(pegNumber);
    if (tower[pegNumber].isEmpty()) {
        return 0;
    } else
        return tower[pegNumber].size();
}

public int getTopDiameter(int pegNumber) {
    pegCheck(pegNumber);
    if (getRingCount(pegNumber) > 0) {
        return tower[pegNumber].get(tower[pegNumber].size() - 1);
    }
    return 0;
}

public boolean move(int startPeg, int endPeg) {
    pegCheck(startPeg);
    pegCheck(endPeg);

    if (endPeg != startPeg) {
        if (getRingCount(startPeg) > 0) {
            if (getRingCount(endPeg) == 0 || getTopDiameter(startPeg) < getTopDiameter(endPeg)) {
                int topRing = tower[startPeg].pop();
                tower[endPeg].push(topRing);
                return true;
            }

        }
    }
    return false;
}
}

1 个答案:

答案 0 :(得分:1)

你说:

  

在move()方法中,前提条件之一要求getTopdiameter(startPeg)小于getTopDiamater(endPeg),但如果endPeg初始化为0环且因此为空,则getTopDiamater(endPeg)返回0,这显然不是在这种情况下小于1

但是,如果您阅读了所提供图片中的前提条件,则表示 SELECT * from TableA WHERE Active = ( CASE @Status WHEN 'N' THEN ('N' AND CONVERT(DATE,ISNULL(DateDeactivated,'01/01/2016')) BETWEEN CONVERT(DATE,GETDATE()-30) AND CONVERT(DATE,GETDATE()) WHEN 'Y' THEN 'Y' ELSE 'Y' END) 小于getTopdiameter(startPeg) 如果getTopDiamater(endPeg)至少有一个响铃所以把它写成你需要的条件

endPeg

- 编辑 -

你需要将条件分成不同的if语句(或者还有条件或条件)来处理塔没有钉子的情况 - 当前条件是你的条件,它在第一次移动时失败作为条件{{ 1}}将是假的。如果getRingCount(endPeg) > 0 && getTopdiameter(startPeg) < getTopDiamater(endPeg)) 那么您可以直接进行移动而无需检查直径是否兼容。为了便于阅读,我建议你最初将你的条件分开 - 你可以随后根据需要将它们组合起来 - 像这样的伪代码

getRingCount(endPeg) > 0