我正在尝试制作一个二叉搜索树数据库,我可以在其中搜索字典条目。我试图弄清楚如何在我的代码中解决这个问题,我得到了一个先决条件基类,它也是一个模板抽象类,它用于派生 BST 或 BinarySearchTree 类,但是我遇到了问题在 Visual Studio 2012 中编译,它一直说我的函数
(例如 int SearchableADT::loadFromFile(std::string) 是抽象的;)
此外,这个构造函数看起来是正确的吗?我只希望构造函数将 head 设置为 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
最佳答案
我试图在 Mac 上用 Clang++ 编译你的代码,你的问题比模板/继承混合早得多。即第 23 行:
error: expected '('
BST():SearchableADT<T> {head = NULL;} //default constructor
(解决方案:基本构造函数需要参数列表,添加 ()
)
并且,在修复之后,第 59 行的下一个:
error: use of undeclared identifier 'info'
if(cPTR->data == info)
我在这个阶段放弃了。还有一些其他的小问题,例如在 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()
以来,上面的示例是“便宜的”只是返回一个值。如果我添加一个函数 twice()
会怎么样?返回 2 * _x
?很好如果 _x
是一个数字,但是字符串呢?还是载体?你明白了……:-)
关于c++ - 无法实例化抽象类 - 我该如何解决这个问题才能正常工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24905665/