[英]Debugging a Map backed by an AVL tree?
This is one of three trees I am using to parse text and print out every unique word, the line numbers it appears on, and the number of times it appears. 这是我用来解析文本并打印出每个唯一单词,出现的行号以及出现的次数的三棵树之一。 I have already used a hash and tree map and have both of them working correctly.
我已经使用了哈希表和树形图,并且它们都能正常工作。 My instructor said that we need to use an AVL tree for the third map and gave us code.
我的教练说,我们需要为第三张地图使用AVL树,并提供了代码。 This is where I am unsure where to go.
这是我不确定要去的地方。 I will include the method that creates/fills the AVL map as well as the AVL map class.
我将包括用于创建/填充AVL映射以及AVL映射类的方法。 If further code is needed, I will gladly include it.
如果需要更多代码,我将很乐意将其包含在内。
public void avlMap(String fileName){
//try/catch block to check for invalid file name
try{
//creates new bufferedreader object for input file
BufferedReader inFile = new BufferedReader(new FileReader(fileName));
//creates new treeMap object named avlMap
Map avlMap = new AvlMap();
String oneLine;
//Read the words and add them to the avlMap
for (int lineNum = 1; (oneLine = inFile.readLine()) != null; lineNum++){
String delims = " !@#$%{}[]/^&*,.()-;:\'\"\t";
StringTokenizer st = new StringTokenizer(oneLine, delims);
while (st.hasMoreTokens()){
String word = st.nextToken();
WordStats stats = (WordStats) avlMap.get(word);
//if WordStats is empty/doesnt exist,
//if exists, adds line numbers into a WordStats in the value
//...field for the int's respective key
if (stats == null){
stats = new WordStats();
avlMap.put(word, stats);
}
//WordStats already exists for the word
//calls addOccurrence method and adds the line number
stats.addOccurrence(new Integer(lineNum));
}
}
//creates a new iterator object to iterate entries
Iterator itr = avlMap.entrySet().iterator();
//runs printEntry for each key in the treeMap
while (itr.hasNext()){
printEntry((Map.Entry) itr.next());
}
}
//the file name used wasn't able to be reached
catch(IOException e){
e.printStackTrace();
}
}
AvlMap class. AvlMap类。 I know it is quite lengthy, but the methods seem to be pretty much the same as the rest of the map classes I have been using.
我知道这很长,但是方法似乎与我一直在使用的其余地图类几乎相同。
public class AvlMap <AnyType extends Comparable<? super AnyType>> implements Map
{
//construct the tree
public AvlMap( ){
root = null;
}
//inserts object into the map
public void insert( AnyType x, AnyType y ){
root = insert( x, y, root );
}
//removes the key from the map
public void remove( AnyType x ){
root = remove( x, root );
}
//internal method to remove from a subtree
private AvlNode<AnyType> remove( AnyType x, AvlNode<AnyType> t ){
if( t == null )
return t; // Item not found; do nothing
int compareResult = x.compareTo( t.key );
if( compareResult < 0 )
t.left = remove( x, t.left );
else if( compareResult > 0 )
t.right = remove( x, t.right );
else if( t.left != null && t.right != null ) // Two children
{
t.key = findMin( t.right ).key;
t.right = remove( t.key, t.right );
}
else
t = ( t.left != null ) ? t.left : t.right;
return balance( t );
}
//returns the smallest item in the tree
public AnyType findMin( ){
if( isEmpty( ) )
throw new UnderflowException("Error" );
return findMin( root ).key;
}
//returns the largest item in the tree
public AnyType findMax( ){
if( isEmpty( ) )
throw new UnderflowException("Error" );
return findMax( root ).key;
}
//finds the provided item in the tree
public boolean contains( AnyType key ){
return contains( key, root );
}
//make the tree empty
public void makeEmpty( ){
root = null;
}
//tests if the tree is empty
public boolean isEmpty( ){
return root == null;
}
//prints the tree in sorted order
public void printTree( ){
if( isEmpty( ) )
System.out.println( "Empty tree" );
else
printTree( root );
}
private static final int ALLOWED_IMBALANCE = 1;
// Assume t is either balanced or within one of being balanced
private AvlNode<AnyType> balance( AvlNode<AnyType> t )
{
if( t == null )
return t;
if( height( t.left ) - height( t.right ) > ALLOWED_IMBALANCE )
if( height( t.left.left ) >= height( t.left.right ) )
t = rotateWithLeftChild( t );
else
t = doubleWithLeftChild( t );
else
if( height( t.right ) - height( t.left ) > ALLOWED_IMBALANCE )
if( height( t.right.right ) >= height( t.right.left ) )
t = rotateWithRightChild( t );
else
t = doubleWithRightChild( t );
t.height = Math.max( height( t.left ), height( t.right ) ) + 1;
return t;
}
//checks the trees balance
public void checkBalance( ){
checkBalance( root );
}
//driver for checking the trees balance
private int checkBalance( AvlNode<AnyType> t ){
if( t == null )
return -1;
if( t != null )
{
int hl = checkBalance( t.left );
int hr = checkBalance( t.right );
if( Math.abs( height( t.left ) - height( t.right ) ) > 1 ||
height( t.left ) != hl || height( t.right ) != hr )
System.out.println( "OOPS!!" );
}
return height( t );
}
//method to insert into a subtree
private AvlNode<AnyType> insert( AnyType key, AnyType value, AvlNode<AnyType> t ){
if( t == null )
return new AvlNode<>( key, value, null, null );
int compareResult = key.compareTo( t.key );
if( compareResult < 0 )
t.left = insert( key, value,t.left );
else if( compareResult > 0 )
t.right = insert( key, value, t.right );
else
; // Duplicate; do nothing
return balance( t );
}
//returns the smallest item in a subtree
private AvlNode<AnyType> findMin( AvlNode<AnyType> t )
{
if( t == null )
return t;
while( t.left != null )
t = t.left;
return t;
}
//finds the largest item in a subtree
private AvlNode<AnyType> findMax( AvlNode<AnyType> t ){
if( t == null )
return t;
while( t.right != null )
t = t.right;
return t;
}
//finds an item in a subtree
private boolean contains( AnyType x, AvlNode<AnyType> t ){
while( t != null ){
int compareResult = x.compareTo( t.key );
if( compareResult < 0 )
t = t.left;
else if( compareResult > 0 )
t = t.right;
else
return true; // Match
}
return false; // No match
}
//prints the subtree in sorted order
private void printTree( AvlNode<AnyType> t ){
if( t != null ){
printTree( t.left );
System.out.println( t.key + " " + t.value );
printTree( t.right );
}
}
//returns the height of node t or -1 if null
private int height( AvlNode<AnyType> t ){
return t == null ? -1 : t.height;
}
//rotates tree node with left child
private AvlNode<AnyType> rotateWithLeftChild( AvlNode<AnyType> k2 ){
AvlNode<AnyType> k1 = k2.left;
k2.left = k1.right;
k1.right = k2;
k2.height = Math.max( height( k2.left ), height( k2.right ) ) + 1;
k1.height = Math.max( height( k1.left ), k2.height ) + 1;
return k1;
}
//rotates tree node with right child
private AvlNode<AnyType> rotateWithRightChild( AvlNode<AnyType> k1 ){
AvlNode<AnyType> k2 = k1.right;
k1.right = k2.left;
k2.left = k1;
k1.height = Math.max( height( k1.left ), height( k1.right ) ) + 1;
k2.height = Math.max( height( k2.right ), k1.height ) + 1;
return k2;
}
//double rotates tree node. first left child with its right child, then
//...node k3 with new left child.
private AvlNode<AnyType> doubleWithLeftChild( AvlNode<AnyType> k3 ){
k3.left = rotateWithRightChild( k3.left );
return rotateWithLeftChild( k3 );
}
//double rotates tree node. first right child with its left child, then
//...node k1 with new right child
private AvlNode<AnyType> doubleWithRightChild( AvlNode<AnyType> k1 ){
k1.right = rotateWithLeftChild( k1.right );
return rotateWithRightChild( k1 );
}
private static class AvlNode<AnyType>{
// Constructors
@SuppressWarnings("unused")
AvlNode( AnyType theKey, AnyType theValue ){
this( theKey, theValue, null, null );
}
AvlNode( AnyType theKey, AnyType theValue, AvlNode<AnyType> lt, AvlNode<AnyType> rt ){
key = theKey;
value = theValue;
left = lt;
right = rt;
height = 0;
}
AnyType key; // The data in the node
AnyType value;
AvlNode<AnyType> left; // Left child
AvlNode<AnyType> right; // Right child
int height; // Height
}
//trees root
private AvlNode<AnyType> root;
//implemented methods for AvlTreeMap
@Override
public void clear() {
makeEmpty();
}
@SuppressWarnings("unchecked")
@Override
public boolean containsKey(Object key) {
contains ((AnyType)key);
return false;
}
@SuppressWarnings("unchecked")
@Override
public boolean containsValue(Object value) {
contains ((AnyType)value);
return false;
}
@Override
public Set entrySet() {
return null;
}
@Override
public Object get(Object key) {
return key;
}
@Override
public Set keySet() {
return null;
}
@SuppressWarnings("unchecked")
@Override
public Object put(Object key, Object value) {
insert ((AnyType)key, (AnyType) value);
return true;
}
@Override
public void putAll(Map m) {
}
@SuppressWarnings("unchecked")
@Override
public Object remove(Object key) {
remove ((AnyType)key);
return null;
}
@Override
public int size() {
return 0;
}
@Override
public Collection values() {
return null;
}
}
Here is my WordStats class that saves everything into a set and keeps occurrance. 这是我的WordStats类,可将所有内容保存到集合中并保持出现。
import java.util.SortedSet;
import java.util.TreeSet;
public class WordStats {
private int occurrences;
private SortedSet<Integer> lineNumbers = new TreeSet<Integer>();
public void addOccurrence(int lineNumber){
occurrences++;
lineNumbers.add(lineNumber);
}
public int getOccurrences(){
return occurrences;
}
public SortedSet<Integer> getLines(){
return lineNumbers;
}
}
When I run the program, I get the error: 运行程序时,出现错误:
Exception in thread "main"
java.lang.ClassCastException
:线程“主要”
java.lang.ClassCastException
异常:
java.lang.String
cannot be cast toWordStats
java.lang.String
无法转换为WordStats
at
driver1.avlMap(driver1.java:182)
在
driver1.avlMap(driver1.java:182)
at
driver1.main(driver1.java:36)
在
driver1.main(driver1.java:36)
Thanks in advance for any insight you can provide. 在此先感谢您提供的任何见解。 There are also not any compiler errors.
也没有任何编译器错误。
The root cause of this issue, as mentioned in the stack trace, is that you are trying to cast an object of type String
to something of type WordStats
. 如堆栈跟踪中所述,此问题的根本原因是您试图将
String
类型的对象转换为WordStats
类型的WordStats
。 I think that this occurs in this line: 我认为这发生在这一行:
WordStats stats = (WordStats) avlMap.get(word);
So let's look at avlMap.get(word)
. 因此,让我们看一下
avlMap.get(word)
。 This looks as follows: 如下所示:
@Override
public Object get(Object key) {
return key;
}
So this is problematic - it looks like every time you try to do a lookup, you're just returning the key that you were trying to look up inside the map! 所以这是有问题的-看起来每次您尝试进行查找时,您只是在返回要在地图中查找的键! That would explain the casting error - you're passing in a
String
into avlMap.get()
, which then returns it. 这将解释转换错误-您将
String
传递给avlMap.get()
,然后将其返回。 When you try casting it to a WordStats
, you're getting an error because a String
isn't a WordStats
. 当您尝试将其强制转换为
WordStats
,会遇到错误,因为String
不是WordStats
。
To fix this, I think you need your get
method to actually do a search in the AVL tree and do a lookup. 要解决此问题,我认为您需要您的
get
方法才能在AVL树中进行搜索并进行查找。 I will leave this for you to complete yourself. 我会把这个留给你完成。 I would strongly suggest not trying to integrate your map into a larger program until you've tested it more thoroughly - having all of the logic to process words layered on top of a buggy AVL tree will make debugging extremely difficult, if not impossible.
我强烈建议您在对地图进行更彻底的测试之前,不要尝试将其集成到一个更大的程序中-将所有逻辑处理单词叠放在多虫的AVL树的顶部将使调试变得非常困难,即使不是不可能。 Try writing some unit tests for your AVL tree to see whether it's working.
尝试为AVL树编写一些单元测试,以查看其是否正常工作。 You could also consider swapping out your AVL tree map for a normal
TreeMap
in the interim to see if the driver code works. 您也可以考虑在此期间将AVL树图换成普通的
TreeMap
,以查看驱动程序代码是否起作用。
As another note - you should strongly consider not implementing the raw type Map
and instead implement Map
parameterized over a key and value type. 另外请注意-您应该强烈考虑不实现原始类型
Map
,而是实现通过键和值类型参数化的Map
。 This makes the interface way easier to use and would help catch the bug that you encountered. 这使界面方式更易于使用,并有助于捕获所遇到的错误。
Hope this helps! 希望这可以帮助!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.