简体   繁体   中英

How can I debug my C++ Binary Search Tree?

I can't figure this out. My search tree only saves the first entry from the input list. I want to build pre, inline, and post traversals along with with some other functions (this will be done after I fix this mess).

There are many solutions, but I want to get better, so I want to know what is wrong with what I did.

BSNODE.H
#include <iostream>
#include <cstddef>
#ifndef BSNODE_H
#define BSNODE_H

template <typename T>
class BSNode
{
private:
   T        m_entry; // A data item
   BSNode<T>* m_left; // Pointer to next node
   BSNode<T>* m_right;

public:

  BSNode();
  BSNode(const T& entry);
  BSNode(const T& entry, BSNode<T>* left, BSNode<T>* right);

  void setEntry(const T& entry);
  void setLeft(BSNode<T>* left);
  void setRight(BSNode<T>* right);

  T getEntry() const ;
  BSNode<T>* getLeft() const ;
  BSNode<T>* getRight() const ;

};
#include "BSNode.cpp"

#endif
BSNODE.CPP
#include "BSNode.h"
using namespace std;

/*Class member variables
char m_entry;
BSNode* m_next;*/

template <typename T>
BSNode<T>::BSNode() : m_left(nullptr), m_right(nullptr)
{
}

template <typename T>
BSNode<T>::BSNode(const T& entry) : m_entry(entry), m_left(nullptr), m_right(nullptr)
{
}

template <typename T>
BSNode<T>::BSNode(const T& entry, BSNode<T>* left, BSNode<T>* right): m_entry(entry), m_left(left), m_right(right)
{
}

template <typename T>
T BSNode<T>::getEntry() const{
  return m_entry;
}

template <typename T>
void BSNode<T>::setEntry(const T& entry){
  m_entry=entry;
}

template <typename T>
BSNode<T>* BSNode<T>::getLeft() const{
  return m_left;
}

template <typename T>
void BSNode<T>::setLeft(BSNode<T>* left){
  m_left=left;
}

template <typename T>
BSNode<T>* BSNode<T>::getRight() const{
  return m_right;
}

template <typename T>
void BSNode<T>::setRight(BSNode<T>* right){
  m_right=right;
}
BSTINTERFACE.H

#ifndef BSTINTERFACE_H
#define BSTINTERFACE_H
#include <iostream>
#include "BSNode.h"

using namespace std;
//ItemType: What is being stored in the tree?
//KeyType: What type is used to search for an Item?
template <typename ItemType, typename KeyType>
class BinarySearchTreeInterface
{
    public:
    virtual ~BinarySearchTreeInterface(){}
    virtual void add(ItemType entry) = 0;
    virtual ItemType search(KeyType key) const = 0;
    virtual void clear() = 0;
    //More methods to come in next lab
};
#endif
BST.H

#ifndef BST_H
#define BST_H
#include <iostream>
#include "BSTInterface.h"

#include <stdexcept>


template <typename ItemType, typename KeyType>
class BST : public BinarySearchTreeInterface<ItemType, KeyType>
{
    public:
    BST():m_root(nullptr){};
    ~BST(){};
    virtual ItemType search(KeyType key) const;
    virtual void add(ItemType entry);
    virtual void clear();

    private:

    BSNode<ItemType>* m_root;
    /**add function will take in Pokemon ID with m_root as subtree. Will make for checks to see if duplicates are made **/
    void add(ItemType entry, BSNode<ItemType>* subtree);

    /**search will traverse through the tree recursively using operator overloads and doing checks for a Pokemon object with an ID taken from user**/
    ItemType search(KeyType key, BSNode<ItemType>* subtree) const;

    /**clear will use recursive calls get subtree to where it needs to get to and with recursive mix calls of subtree->getLeft subtree->getRight with delete subtree, this will
     * delete the tree**/
    void clear(BSNode<ItemType>* subtree);

};
#include "BST.cpp"
#endif
BST.CPP

#include "BST.h"
using namespace std;

template <typename ItemType, typename KeyType>
void BST<ItemType,KeyType>::clear(){
    clear(m_root);
}

template <typename ItemType, typename KeyType>
void BST<ItemType,KeyType>::clear(BSNode<ItemType>* subtree){
    if(subtree->getLeft()!= nullptr){
        clear(subtree->getLeft());
    }
    if(subtree->getRight()!=nullptr){
        clear(subtree->getRight());
    }
    delete subtree;
}

//public add func
template <typename ItemType, typename KeyType>
void BST<ItemType,KeyType>::add(ItemType entry){

    if(m_root == nullptr){
        m_root= new BSNode<ItemType>(entry);
    }
    else{
        add(entry, m_root);
    }
}

//private add func
template <typename ItemType, typename KeyType>
void BST<ItemType,KeyType>::add(ItemType entry, BSNode<ItemType>* subtree){


 if(subtree->getEntry() > entry.getID()){
     if(subtree->getRight()!=nullptr){
        add(entry,subtree->getRight());
     }
     else{
         BSNode<ItemType>* n= new BSNode<ItemType>(entry);
         subtree->setRight(n);
     }
 }
 else if(subtree->getEntry() < entry.getID()){
     if(subtree->getLeft()!=nullptr){
        add(entry, subtree->getLeft());
     }
     else{
         BSNode<ItemType>* n= new BSNode<ItemType>(entry);
         subtree->setLeft(n);
     }
 }
 else{
     throw(std::runtime_error("There are duplicate pokemon in the file that were not added\n")); 
 }


}

//public search func
template <typename ItemType, typename KeyType>
ItemType BST<ItemType, KeyType>::search(KeyType key) const{
    return(search(key, m_root));
}

//private search func
template<typename ItemType, typename KeyType>
ItemType BST<ItemType, KeyType>::search(KeyType key, BSNode<ItemType>* subtree) const {

    //check for nullptr, check for empty
    if(subtree==nullptr){
        throw(std::runtime_error("Item not in tree\n"));
    }

    /*
      below accesses entry in BSNode which in this case is Poke Object
      and that is why the overload operator will take over and check if
      m_id == key
    */
    else if(subtree->getEntry() == key)
    {
        //remember that this returns the "ItemType",
        //in this lab it returns a pokemon object.
        return(subtree->getEntry());

    }

    else{

        //check the rest of tree
        //traverse down appropriate road
        if(subtree->getEntry() > key){
            return(search(key, subtree->getLeft()));
        }
        else{
            return(search(key, subtree->getRight()));
        }
    }

}

POKEMON.H
#ifndef POKEMON_H
#define POKEMON_H

#include <string>

using namespace std;

class Pokemon
{
    public:
    Pokemon():US_name(""),m_id(0),JP_name(""){};
    Pokemon(std::string name, int m_id, std::string jname);
    /*
        This is kept for notes, the issues with below is that Left Hand Side
        is compared to Right Hand Side but the whole object is passed in to RHS,
        it is much easier on the computer (takes less memory) to have a "KEY"
        to pass along and compare each object KEY to. In this lab it is Poke ID number
    */
    //bool operator==(const Pokemon& rhs) const;
    //bool operator<(const Pokemon& rhs) const;
    //bool operator>(const Pokemon& rhs) const;


    bool operator==(int id) const;
    bool operator<(int id) const;
    bool operator>(int id) const;
    string getUS(){return US_name;}
    int getID(){return m_id;}
    string getJP(){return JP_name;}

    void setUS(string US){
        US_name=US;
    }
    void setID(int id){
        m_id=id;
    }
    void setJP(string JP){
        JP_name=JP;
    }


    private:
    //what data do Pokemon have?
    //What are the related data?    
    std::string US_name; 
    int m_id;
    std::string JP_name;

};

#endif

POKEMON.CPP
#include "Pokemon.h"


Pokemon::Pokemon(std::string name, int id, std::string jname)
{
    US_name=name;
    m_id = id;
    JP_name=jname;
}


//bool Pokemon::operator==(const Pokemon& rhs) const
//{
    //if they ids are the same, they're the same Pokemon
    //return(m_id == rhs.m_id);
//}

bool Pokemon::operator==(int id) const
{
    return(m_id == id);
}

bool Pokemon::operator<(int id) const
{
    return(m_id < id);
}

bool Pokemon::operator>(int id) const
{
    return(m_id > id);
}
EXECUTIVE.H
#ifndef EXECUTIVE_H
#define EXECUTIVE_H
#include <iostream>
#include <string>
#include <fstream>
#include "BST.h"
#include "Pokemon.h"



using namespace std;

class Executive{

private:




public:

/** These are to take in info from file **/
    string tempUS;
    int tempID;
    string tempJP;

  Executive(string filename);

  ~Executive(){

  }



};

#endif

EXECUTIVE.CPP
#include "Executive.h"


using namespace std;

Executive::Executive(string filename){

  ifstream fin;
  fin.open(filename);
  if(fin.fail()){
    cout << "File not found";
  }
  else{

    BST<Pokemon,int> Tree;


    while(fin>> tempUS >> tempID >> tempJP){

      Pokemon Poke;
      Poke.setUS(tempUS);
      Poke.setID(tempID);
      Poke.setJP(tempJP);

      try{
          Tree.add(Poke);
        }
          catch(runtime_error& rte){
            cout << rte.what() << endl;

        } 


    }

  int choice;

  do{
    cout << "Enter 0 to Exit\nEnter 1 to Add a pokemanz\nEnter 2 to Search for a pokemanz\n";
    cin >> choice;

    if(choice==1){
      string tUS, tJP;
      int tID;
      cout << "US Name: ";
      cin >> tUS;
      cout << "ID: ";
      cin >> tID;
      cout << "JP Name: ";
      cin >> tJP;

      Pokemon Poke;
      Poke.setUS(tUS);
      Poke.setID(tID);
      Poke.setJP(tJP);

      try{
          Tree.add(Poke);
        }
          catch(runtime_error& rte){
            cout << rte.what() << endl;

        } 

    }
    if(choice==2){

      int tID;
      cout << "Enter Pokemon ID:";
      cin >> tID;

      try{
        Pokemon Poke1 = (Tree.search(tID));
        cout << "<" << Poke1.getUS() << ">" << " <" << 
          Poke1.getID() << "> <" << Poke1.getJP() << ">\n";
          cout << endl;
        }
          catch(runtime_error& rte){
            cout << rte.what() << endl;

          }


    }    


  }while(choice!=0);

  Tree.clear();


  }
}


MAIN.CPP
#include <iostream>
#include "Executive.h"

using namespace std;

int main(int argc, char* argv[])
{   
    if(argc < 2)
    {
        cout << "Incorrect number of parameters!\n";
    }
    else
    {
        Executive exec(argv[1]); 
    }

  return 0;
}
MAKEFILE
run: main.o Executive.o Pokemon.o
    g++ -g -std=c++11 -g -Wall main.o Executive.o Pokemon.o -o run

main.o: main.cpp 
    g++ -g -std=c++11 -g -c -Wall main.cpp

Executive.o: Executive.h Executive.cpp BSTInterface.h BST.h BST.cpp BSNode.h BSNode.cpp
    g++ -g -std=c++11 -g -c -Wall Executive.cpp

Pokemon.o: Pokemon.h Pokemon.cpp 
    g++ -g -std=c++11 -g -c -Wall Pokemon.cpp

clean:
    rm *.o run

leak:
    valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes ./run input.txt

INPUT.TXT
Abra    63  Casey
Aerodactyl  142 Ptera
Alakazam    65  Foodin
Arbok   24  Arbok
Arcanine    59  Windie
Articuno    144 Freezer
Beedrill    15  Spear
Bellsprout  69  Madatsubomi
Blastoise   9   Kamex
Bulbasaur   1   Fushigidane

In your node-adding function

 if(subtree->getEntry() > entry.getID()){
    if(subtree->getRight()!=nullptr){
       add(entry,subtree->getRight());
    }
    else{
        BSNode<ItemType>* n= new BSNode<ItemType>(entry);
        subtree->setRight(n);
    }
}
else if(subtree->getEntry() < entry.getID()){
    if(subtree->getLeft()!=nullptr){
       add(entry, subtree->getLeft());
    }
    else{
        BSNode<ItemType>* n= new BSNode<ItemType>(entry);
        subtree->setLeft(n);
    }
}

The traverse go right when ID to add is smaller than current node's ID.

On the other hand, in your node-searching function

if(subtree->getEntry() > key){
    return(search(key, subtree->getLeft()));
}
else{
    return(search(key, subtree->getRight()));
}

The traverse go left when ID to search is smaller than current node's ID.

This mismatch is preventing IDs of nodes other than the root (1st on the list) node from being found.

You have to invert either choice to solve this issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM