2014-07-23 3 views
0

바이너리 검색 트리 데이터베이스를 만들려고합니다. 여기서 사전 항목을 검색 할 수 있습니다. 내 코드에서이 문제를 해결하는 방법을 알아 내려고 노력 중입니다. 템플릿 추상 클래스 인 사전 필수 기본 클래스가 주어졌으며 BST 또는 BinarySearchTree 클래스를 파생시키는 데 사용되지만 문제가 발생합니다. Visual Studio 2012에서 컴파일 할 때 내 함수를 계속 말합니다.
(예 : int SearchableADT :: loadFromFile (std :: string)은 추상입니다.)추상 클래스를 인스턴스화 할 수 없습니다 - 제대로 작동하려면 어떻게 수정합니까?

또한이 생성자는 정확합니까? 난 그냥 NULL에서 머리를 설정하는 생성자를 원하지만, 나는 어딘가에 생성자에서 SearchableADT를 사용해야할지 모르겠다.

감사합니다. 나는 그것을 필요로한다!

#include <cstring> 
#include <string> 
#include <iostream> 
#include <fstream> 
using namespace std; 

template <typename T> 
class SearchableADT 
{ 
public: 
    virtual int loadFromFile(string filename)= 0; 
    //virtual void clear(void) = 0; 
    virtual void insertEntry(T value) = 0; 
    virtual void deleteEntry(T value) = 0; 
    virtual bool isThere(T value) = 0; 
    virtual int numEntries(void) = 0; 
}; 

template <typename T> 
class BST : public SearchableADT<T> 
{ 
public: 
    BST():SearchableADT<T> {head = NULL;} //default constructor 
    virtual int loadFromFile(string filename); 
    //virtual void clear(void); 
    virtual void insertEntry(T value); 
    virtual void deleteEntry(T value); 
    virtual bool isThere(T value); 
    virtual int numEntries(void); 
private: 
    struct t_node 
    { 
     string data; 
     t_node* L; //left node 
     t_node* R; //right node 
    }; 
    t_node* head; // head of the whole BST 
    t_node* cPTR; // current pointer 
    t_node* pPTR; // parent pointer 
    t_node* tPTR; //temporary pointer 

}; 
template <typename T> 
bool BST<T>::isThere(T value) 
{ 
    bool found = false; 

if(head == NULL) 
{ 
    cout<<"Error: No data found in ADT\n"; 
    return found; 
} 

cPTR = head; 
//loops through the tree until the entry is found 
while(cPTR != NULL) 
{ 
    if(cPTR->data == info) 
    { 
     found = true; 
     break; 
    } 

    else 
    { 
     pPTR = cPTR; 
     if(info > cPTR->data) 
      cPTR = cPTR->R; 
     else 
      cPTR = cPTR->L; 
    } 
} 
if(!found) 
{ 
    cout<<"'"<<info<<"' was not found in the dictionary\n"; 
} 
return found; 
}//end of isThere() function 

template <typename T2> 
void BST<T2>::insertEntry(T2 info) 
{ 
    t_node* t = new t_node; 
    t->data = info; 
    t->L = NULL; 
    t->R = NULL; 
    pPTR = NULL; 
    if(head->data == NULL) 
     head = t; 
    else 
    { 
     t_node* cPTR; //current pointer 
     cPTR = head; 

     //checks to see if the data just entered is 
     //greater than the head 
     while(cPTR) 
     { 
      pPTR = cPTR; 
      if(t->data > cPTR->data) 
       cPTR = cPTR->R; 
      else 
       cPTR = cPTR->L; 
     } 

     //checks to see if the data just entered is 
     // less than the parent data that was 
     // set equal to cPTR; 
     if(t->data < pPTR->data) 
     { 
      pPTR->L = t; 

     } 
    else 
    { 
     pPTR->R = t; 
    } 
} 
}//end of insertEntry() function 

template <typename T2> 

void BST<T2>::deleteEntry(T2 info) 
{ 
    //i use this as an example of abstraction 
    //after using this function the cPTR and pPTR are already pointing to the data needed to be found 
    if(!isThere(info)) 
    { 
     cout<<"The data: '"<<info<<"' could not be found in the ADT, sorry!\n"; 
     return; 
    } 

    //one has to account for all possibilities when deleting data 
    //1.) - Removing just a leaf node (no children) **easy 
//2.) - Removing a leaf node with 1 child **medium 
//3.) - Removing a leaf node with 2 children **hard 

//case 1 
if(cPTR->L == NULL && cPTR ->right == NULL) 
{ 
    if(pPTR-> L == cPTR) 
     pPTR->L = NULL; 
    else 
     pPTR->R = NULL; 
    delete cPTR; 
    return; 
}//end of case 1 

//case 2 
else if((cPTR->L == NULL && cPTR->R != NULL) || 
    (cPTR->L != NULL && cPTR->R == NULL)) 
{ 
    //if the left data of cptr has data and the right data is NULL 
    if(cPTR->L != NULL && cPTR->R == NULL) 
    { 
     if(pPTR->L == cPTR) 
     { 
      pPTR->L = cPTR->right; 
      delete cPTR; 
     } 
     else 
     { 
      pPTR->R = cPTR->L; 
      delete cPTR; 
     } 
    } 

    else //right child present, and left child is NULL 
    { 
     if(pPTR->L == cPTR) 
     { 
      pPTR->L = cPTR->right; 
      delete cPTR; 
     } 
     else 
     { 
      pPTR->R = cPTR->R; 
      delete cPTR; 
     } 
    } 

    //case 3 
    else if((cPTR->L != NULL && cPTR->R != NULL)) 
    { 
     tPTR=cPTR->R; 

     //if the right node doesn't have a right leaf or left leaf, delete that node 
     if((tPTR->L == NULL && tPTR->R == NULL)) 
     { 
      cPTR = tPTR; 
      delete cPTR; 
      cPTR->R = NULL; 
     } 
     else 
     { 
      if(tPTR->L != NULL) 
      { 
       t_node* secPTR; 
       secPTR = tPTR->L; 
       //cycle through left nodes until you find the lowest left node 
       while(secPTR->L != NULL) 
       { 
        secPTR = secPTR->L; 
       } 
       //because you're only setting the data equal to eachother the cPTR keeps its left and right nodes 
       //therefore it correctly replaces the data without unwanted loss of other information 
       cPTR->data = secPTR->data; 
       delete secPTR; 
       cPTR->L = NULL; 
      } 
      else 
      { 
       cPTR->data = tPTR->data; 
       cPTR->R = tPTR->R; 
       delete tPTR; 
      } 

     } 
    } 
} 
} //end of deleteEntry() function 

template <typename T2> 
int BST<T2>::numEntries() 
{ 
    int num = 0; 

    if(head->R == NULL && head-> L == NULL) 
    { 
     num++; 
    } 
    else 
    { 
     //note i learned that you could count the nodes like this via the web 
     //i could redo this with recursion if you'd like 
     num = count(head->L) + count (head->R) + 1; 
    } 
    return num; 
} 
template <typename T2> 
int BST<T2>::loadFromFile(string filename) 
{ 
    int count = 0; 
    string tempdata; 
    ifstream fin(filename); 
    if(!fin) 
    { 
     cout<< "Error: Could no open file\n"; 
     count--; 
    } 
    while(fin) 
    { 
     fin>>tempdata; 
     if(fin) 
     { 
      insertEntry(tempdata); 
      count++; 
     } 
    } 
    fin.close(); 
    return count;  
}//end of loadFromFile() function 


int main() 
{ 
    char choice 'z'; 
    string tempdata, 
      fileloc; 

cout<<"Welcome to Jordin Ray's Spell Check Application\n" 
    <<"Please pick a tree type\n" 
    <<"'b' -Binary Search Tree\n" 
    <<"'a' -AVL tree\n" 
    <<"'h' -hash table\n"; 
cin>>choice; 
cout<<"Please give the exact location of the file for download\n"; 
cin>>fileloc; 
if(choice == 'b') 
{ 
    SearchableADT<string> dictionary = new BST<string>; 
    dictionary.loadFromFile(fileloc); 
    char ch = 'z'; 
    while(ch != 'q') 
    { 
     string word = ""; 
     if(ch == 'e') 
     { 
      cout<<"Please enter the word you would like to search for\n"; 
      cin>>word; 
      dictionary.isThere(word); 
     } 
     else if (ch == 'p') 
     { 
      cout<<"Please enter the partial word you would like to look for with a '?' where the missing letter is: \n" 
       <<"Ex. - '?nd' will search for words in the dictionary that have those last two letters\n"; 
      //dictionary.partialIsThere(word); 
     } 
     else if (ch == 'c') 
     { 
      dictionary.clear(); 
     } 
     else if (ch == 's') 
     { 
      int entries; 
      entries = dictionary.numEntries(); 
      cout<<"\nThe amount of entries logged in the database is: "<<entries<<".\n"; 
     } 
     cout<<"Would you like to:\n" 
      <<"Clear the dictionary  - 'c'\n" 
      <<"Check for an entry  - 'e'\n" 
      <<"Check for a partial entry - 'p'\n" 
      <<"Report Statistics   - 's'\n" 
      <<"Quit      - 'q'"; 
     cin>>ch; 
    }//end of while loop 
} 
return 0; 
}//end of main 
+0

이 문제는 http://stackoverflow.com/questions/3251549/creating-an-interface-for-an-abstract-class-template-in-c에서 해결되었습니다. – eferion

답변

1

Mac에서 Clang ++로 코드를 컴파일하려고 시도했지만 문제가 템플릿/상속 믹싱보다 훨씬 일찍 시작되었습니다. 즉 라인 23 :

error: expected '(' 
    BST():SearchableADT<T> {head = NULL;} //default constructor 

error: use of undeclared identifier 'info' 
    if(cPTR->data == info) 

하고 : 라인 (59)에서 다음 오는 고정시킨 후

(용액베이스 생성자는 인수리스트가 필요 () 추가) 및 나는이 단계에서 포기했다. 기타 사소한 문제가 있습니다. C++에서는 #include <cstring>에 대한 필요가 없습니다. C 스타일 문자열을 예상하는 모든 함수에 대해 항상 c_str() 메서드를 std::string으로 사용할 수 있습니다. 또한 const의 정확성을 관찰해야합니다. loadFromFile(string filename)loadFromFile(const string& filename)처럼 보입니다. 기타

이제 주요 문제. 나는 템플릿 기반 클래스가 왜 필요한지 모르겠습니다. 템플릿을 사용하지 않고 문자열을 저장하는 클래스를 작성하면 전체 디자인을 훨씬 쉽게 처리 할 수 ​​있습니다.

실제로 구체적인 템플릿 클래스가 파생 된 추상 템플릿 기본 클래스를 가질 수 있습니다. 모든 순수 가상 메소드에 대한 구체적인 구현을 제공했는지 확인하십시오.

#include <string> 
#include <iostream> 

template<typename T> 
class AbstractBase { 
    public: 

    virtual const T& func() const = 0; 

}; 

template<typename T> 
class Derived: public AbstractBase<T> { 
    public: 

    // stores x 
    Derived(const T& x): AbstractBase<T>(), _x(x) {} 

    // returns x 
    const T& func() const { return _x; } 

    private: 
    T _x; 
}; 

int main(int argc, char *argv[]) { 
    Derived<std::string> d("foo"); 
    std::cout << d.func() << std::endl; 
    return 0; 
} 

그러나 템플릿/상속 혼합 설계 문제가 구현 될 수-방법 중 일부는 경우에 나중에 후면의 추한 머리를하지 않는 것 : 여기 당신이 시작 도움이 될 만들어 낸 예는 특정 템플릿 매개 변수에 대해 이해해야합니다. 위 예제는 func()이 값을 반환하기 때문에 "싸다"였습니다. 2 * _x을 반환하는 함수 twice()을 추가하면 어떻게됩니까? _x이 숫자 인 경우 문제는 없지만 문자열은 어떻게됩니까? 아니면 벡터? 당신은 요점을 얻습니다 :-)

+0

문제는 제가 템플릿을 만들 필요가 있다고 말하는 지침이 있다는 것입니다. BST의 기능을 제대로 구현하는 방법을 알아 내려고 노력하고 있습니다. 모든 템플릿 기능을 만들지 않고도 오류가 발생하기 때문에 인스턴스를 생성 할 수 없습니다. 어떤 충고? – StingRay21

관련 문제