1、设计一个类来实现ADT牵涉到标识出那些需要来实现ADT操作的函数成员,如果最终能够获得一个计划良好易于使用的类,那么在这个阶段所花费的时间最终将得到回报。我们还需要认识到,我们对函数成员的描述与这个类将如何实现是没有关系的。
2、设计一个链表,为了保证封装性,需要将类型定义在类的内部:
class List
{
private:
class Node
{
public:
Node *pNext;
T m_data;
Node()
{
m_data = 0;
pNext = NULL;
}
};
//typedef Node * Link_List;
int m_Lenth;
//Link_List pHead;
Node *pHead;
}
链表的数据类型定义在类的内部,应用类的嵌套的方式
3、考虑到类的定义的完整性,需要给类添加如下的功能
构造、析构、拷贝构造函数、操作符的重载
public:
List();
List(const List &m_List);
~List();
const List&operator=(const List &m_List);
在作为ADT的链表的定义中,还需要如下的操作:判空,插入、删除、遍历、输出显示、修改、查询
<span style="white-space:pre"> </span>bool List_IsEmpty();
int List_Lenth();
void List_Insert(T num,int nPos);
void List_Delete(int nPos);
void List_Destroy();
void List_Display();
Node * List_GetHead() const;
bool List_FindElem(T num);
void List_Modify(T num, int nPos);
template<typename T>
List<T>::List(const List<T> &m_List)
{
Node *pTempNode = m_List.pHead;
this->pHead = new Node;
this->m_Lenth =0;
assert(pHead);
Node *pNewHead = pHead;
if(NULL ==pTempNode)
{
cout<<"List doesn't exists"<<endl;
return;
}
pTempNode = pTempNode->pNext;
while(NULL!=pTempNode)
{
Node *pTemp = new Node;
if(NULL!=pTemp)
{
pTemp->m_data = pTempNode->m_data;
pTemp->pNext = NULL;
}
pNewHead->pNext = pTemp;
pNewHead = pNewHead->pNext;
pTempNode = pTempNode->pNext;
++m_Lenth;
}
//m_Lenth = m_List.m_Lenth;
}
<pre name="code" class="csharp">template<typename T>
const List<T>&List<T>::operator=(const List<T> &m_List)
{
if (this == &m_List)
return *this;
Node *pTempHead = this->pHead->pNext;
Node *pTempNode = m_List.pHead->pNext;
if(NULL ==pTempNode)
{
cout<<"List doesn't exists"<<endl;
exit(0);
}
while(NULL!=pTempHead)
{
Node *pTemp = pTempHead;
pTempHead = pTempHead->pNext;
delete pTemp;
}
pTempHead = this->pHead;
while(NULL!=pTempNode)
{
Node *pTemp = new Node;
if(NULL!=pTemp)
{
pTemp->m_data = pTempNode->m_data;
pTemp->pNext = NULL;
}
pTempHead->pNext = pTemp;
pTempHead = pTempHead->pNext;
pTempNode = pTempNode->pNext;
++m_Lenth;
}
//m_Lenth = m_List.m_Lenth;
return *this;
}
上面的两个接口是拷贝构造函数和“=”操作符的重载,两个函数内部实现的方式类似,但是功能却差别很大,具体的差别见前面的文章中的叙述,这里需要注意的有如下几点:
1)、幅值操作符“= ” 返回一个 *this
2)、赋值操作符中应进行证同测试
3)、赋值时,对象中的每一部分都要进行复制
template<typename T>
void List<T>::List_Insert(T num,int nPos)
{
Node *pTempHead = this->pHead;
if(NULL == pTempHead)
{
cout<<"List is NULL ,can't Insert"<<endl;
return ;
}
if(nPos<=0||nPos>m_Lenth+1)
{
cout<<"Invalide Position"<<endl;
return;
}
int m_Count = 0;
Node *pNewNode = new Node;
pNewNode->m_data = num;
pNewNode->pNext = NULL;
while(NULL!=pTempHead)
{
++m_Count;
if(m_Count==nPos)
{
pNewNode->pNext = pTempHead->pNext;
pTempHead->pNext = pNewNode;
break;
}
pTempHead = pTempHead->pNext;
}
++m_Lenth;
}
template<typename T>
void List<T>::List_Delete(int nPos)
{
Node *pTempHead = this->pHead;
if(NULL == pTempHead||nPos>m_Lenth+1)
{
cout<<"can't Delete"<<endl;
return ;
}
int m_Count = 0;
while(NULL!=pTempHead)
{
++m_Count;
if(m_Count == nPos)
{
Node *pTemp = pTempHead->pNext;
pTempHead->pNext = pTemp->pNext;
delete pTemp;
break;
}
pTempHead = pTempHead->pNext;
}
--m_Lenth;
}
插入和删除中需要注意遍历的过程中不要越界,进行判空检查,否则会出现意想不到的错误。
template<typename T>
<span style="color:#ff6666;">typename List<T>::Node * List<T>::List_GetHead() const</span>
{
return pHead;
}
注意上面红色的部分,类模板之间嵌套时需要按照上面的方式进行调用,否则系统会报错。
void main()
{
List<int> myList;
for(int i=0;i<12;i++)
{
myList.List_Insert(i,1);
}
myList.List_Insert(15,7);
cout<<"**myList:"<<myList.List_Lenth()<<endl;
myList.List_Display();
List<int> newList = myList;
cout<<"**newList:"<<newList.List_Lenth()<<endl;
newList.List_Display();
myList.List_Insert(101,9);
List<int> newOpList;
newOpList = myList;
cout<<"**newOpList:"<<newOpList.List_Lenth()<<endl;
newOpList.List_Display();
for(int i=0;i<5;i++)
newOpList.List_Delete(1);
cout<<"**newOpList:"<<newOpList.List_Lenth()<<endl;
newOpList.List_Display();
newOpList.List_Destroy();
system("pause");
}
调试程序,输出如下的结果: