分裂数组 - 我的实现是否正确?

时间:2010-10-09 22:29:00

标签: java data-structures split

我正在为学校编写混合数据结构的代码,并正在调试代码。基本上,此结构是双链接列表和数组的组合,其中每个列表节点包含一组设置大小。由于这是一个有序结构,因此必须做出规定,将完整数组识别并分成两个节点。

这是我的代码,用于将节点拆分为两个,然后将父节点的数组值的后半部分复制到子节点。

public Chunk<E> split(Chunk<E> node) {
  Chunk<E> newChunk= new Chunk<E>();
  newChunk.index= node.index++;

  //connect to previous node
  node.next= newChunk.next;
  newChunk.prev= node.prev;

  //connect to next node
  newChunk.next= node.next.next;
  node.next.prev= newChunk.prev;

  //adds the latter half of the array contents to the new node
  //and erases the same contents from the old node
  for (int i=chunkSize/2; i<node.numUsed; i++) {
   newChunk.items[i-chunkSize/2]= node.items[i];
   node.items[i]=null;
  }

  //update capacity counter for both chunks
  node.numUsed=chunkSize/2;
  newChunk.numUsed= chunkSize/2;

  return newChunk;

}

toArray()方法从列表中返回空值,所以我认为这种拆分方法正在发生。

我的问题是:

  • 新节点与列表其余部分的链接是否正确?
  • 循环内的值的归零是否为空打印输出?
  • 2 个答案:

    答案 0 :(得分:2)

    要彻底回答这个问题,你应该写一些单元测试。例如:

    package so3898131;
    
    import static org.junit.Assert.*;
    
    import org.junit.Test;
    
    public class ChunkTest {
    
      /** Ensure that the simplest possible case works as expected. */
      @Test
      public void testEmptySplit() {
        Chunk<Object> old = new Chunk<Object>();
        Chunk<Object> split = old.split(old);
        assertEquals(0, split.chunkSize);
        assertEquals(0, split.items.length);
        assertEquals(0, split.index);
        assertEquals(1, old.index);
      }
    
      @Test
      public void testSplitWithOneItem() {
        // TODO: make sure that after splitting one of the chunks contains
        // one element, the other none.
      }
    
      @Test
      public void testSplitWithTwoItems() {
        // TODO: make sure that after splitting a chunk with two elements
        // each of the new chunks contains exactly one of the elements.
        // Use assertSame(..., ...) to check it.
      }
    }
    

    这会向我发送NullPointerException,因为node.next可能是null,在这种情况下您无法访问node.next.next。这可能意味着您的代码不起作用。至少它不起作用期待它。

    更新:您的代码不正确。我写了一个像这样的单元测试:

    @Test
    public void testSplitLinkage() {
      Chunk<Object> old = new Chunk<Object>();
      assertNull(old.prev);
      assertNull(old.next);
    
      Chunk<Object> split = old.split(old);
    
      assertNull(old.prev);
      assertSame(split, old.next);
      assertSame(old, split.prev);
      assertNull(split.next);
    }
    

    然后我修改了代码,以便成功运行此测试。我不得不用以下代码替换一些行:

    // connect to previous and next node
    Chunk<E> one = node, two = newChunk, three = node.next;
    one.next = two;
    two.prev = one;
    two.next = three;
    if (three != null)
      three.prev = two;
    

    答案 1 :(得分:0)

    更好的问题是:“如何通过调试来隔离(追踪)源代码中错误的位置?”

    首先,您需要一种方法来重现问题。看来你已经有了。在一个非平凡的代码库中,您将需要对问题进行二进制搜索。在程序执行中有两个点A和B,其中程序在A中处于有效状态但不在B中,选择A和B之间的点C并检查C处的所有内容是否正确。如果是,则错误发生在C和B,其他在A和C之间。递归,直到你把它缩小到代码的一小部分,通常非常明显。

    这就留下了如何验证目前执行是否正确的问题。有多种方法可以做到这一点,但在调试器中执行程序,使用断点暂停执行,并检查变量是否包含预期值可能是最有益的。