建立单向链表
template<class T>
class Chain;//声明链类
template<class T>//实现节点类
class Node{
friend class Chain<T>;
private:
T data;
Node<T>* link;
Node(T newdata){data=newdata;}
}
template<class T> //实现链类
class Chain{
public:
Chain(){} //构造方法
~Chain();//析构函数
void Browser()const;//浏览链表中所有数据
Chain<T>& Inserts(const int k,const T& x); //向链表中第k个位置插入元素
void IsEmpty()const;//判断链表是否为空
int Length()const;//获取链表的长度
Chain<T>& Delete(const int k);
void Inverse();//反转链表
private:
Node<T>* first=NULL;//定义首指针,用来指向第一个节点
}
插入操作的实现
刚开始,first=NULL,我们想要插入元素,只需将该元素的指针域设为first即NULL,然后再让first指向该元素即可,如下图:
如果是再上面的基础上,再在后面添加元素,则需要做如下操作:
下面是实现的代码示例:
template<class T>
Chain<T>& Chain<T>::Inserts(const int k,const T& x){
if(k<0) throw *this;//链表中元素的个数最小也为0
Node<T>* p = first;
for(int i=1;i<k;i++){
p = p->link; //让指针p指向下一个元素
}//如果要向第k个位置插入元素(k>2),首先要将p移动到第k-1的位置
if(k>0 && p==NULL) throw *this;//表名k大于链表中现有元素的个数,即没有从0开始数第k减1个元素
Node<T>* pt = new Node<T>(x); //创建一个节点元素,然后将x填入其数据域
if(k>0 && p!=NULL){//进行插入操作
pt->link=p->link;//让pt节点的指针域指针指向p的下一个结点即p->link
p->link=pt;//再让p的指针域的指针指向pt,表名p所指向的元素的下一个元素为pt。
}else{
pt->link=first;//如果是向第0个位置插入元素,就让pt的指针域指向first所指向的元素
first=pt;//让first指向pt;
}
return *this;//返回插入后的链表对象
}
判断链表是否为空操作的实现
判断链表是否为空,只需要判断链表的首指针是否为NULL即可。具体代码如下:
template<class T>
bool Chain<T>::IsEmpty()const{
if(first==NULL){
return true;
}else{
return false;
}
}
浏览链表中的所有数据
首先定义一个Node型的指针,然后指向链表的第一个值,然后一位一位的往后移,直到其指向NULL,说明链表中已无数据,具体的代码如下:
template<class T>
void Chain<T>::Browser()const{
if(!IsEmpty()){//表名链表非空
Node<T>* pb = first;
while(1){
cout<<pb->data;
if(pb->link==NULL)break;//如果pb元素没有下一个节点,停止循环
cout<<"->";
pb = pb->link;//让pb指向pb的下一个节点
}
}else{
cout<<"The linkTable is Empty"<<endl;
}
}
析构函数的实现
template<class T>
Chain<T>::~Chain(){//删除所有结点
Node<T>* p;
while(first){
p = first->link;
delete first;
first = p;
}
}
获取链表的长度
由于链表的特殊结构(即下一个结点只能通过其上一个结点获得),所以必须要遍历链表,然后记录链表中元素的个数即可,具体的实现代码如下:
int Chain<T>::Length()const(){
int i=0;
Node<T>* x=first; //让x指向第一个节点
while(x){
i++;//如果x!=NULL,给i加1
x = x->link;//让x指向下一个结点
}
return i;
}
删除指定结点的操作
删除节点的操作的分为两种情况,一种是删除第0个节点,这种情况需要改变first的值,另一种情况是删除第0个以后的节点,这种情况不需要改变first的值,两种情况的图示如下:
删除第0个节点:
删除第0个节点以后的节点(这里以第2个为例):
删除指定元素的代码示例如下:
template<class T>
Chain<T>& Chain<T>::Delete(const int k){
if(k<0 || k>=Length()){//表名k超出范围
throw *this;//终止程序
}
//k符合要求,开始删除操作
Node<T>* pt = first;
for(int i=1;i<k;i++){
pt=pt->link;//将pt右移,结果是将pt移动至删除元素的前一个元素
}
if(k==0){
pt=first->link;//将pt指向要删除的元素(第0个元素)的后一个元素(第1个元素)
delete first;//删除第0个元素
first=pt;//再让first指向新的第0个元素(原来的第1个元素)
}else{
Node<T>* temp = pt->link;//指向被删除元素
pt-link = temp->link;//让pt的指针域指向要删除的元素的后一个元素
delete temp;
temp=NULL;
}
return *this;
}
反转链表
可以先定义三个指针,其中p指针指向当前元素,而q指针指向后一个元素,t指针用来做过渡变量,用来保存q指针指向的变量。
那么其反转的过程如下所示:
刚开始p指向第一个元素,而q和t设为NULL
此时,我们让原来链表的first指针指向q即可
如上,整个链表已经反转完成,下面是其代码的实现过程:
template<class T>
void Chain<T>::Inverse(){
Node<T>* p=first;
Node<T>* q=NULL;
while(p){
Node<T>* r=q;
q=p;
p=p->link;
q->link=r;
}
first=q;
}
以上方法即链表的测试程序
int main(){
Chain<int>* List = new Chain<int>();
List->Browser();//浏览元素
int k=0;
int data = 2;
List->Inserts(k,data);
List->Browser();//浏览元素
k=0;data=3;
List->Inserts(k,data);
List->Browser();
k=2;data=10;
List->Inserts(k,data);
List->Browser();
k = List->Length();
cout<<"length = "<<k<<endl;
List->Invert();
List->Browser();
*List = List->Delete(2);
List->Browser();
k = List->Length();
cout<<"length = "<<k<<endl;
Chain<int>* List2 = new Chain<int>();
List2->Inserts(0,12);
List2->Inserts(0,13);
List2->Inserts(1,15);
List2->Browser();
*List = List->Candidate(List2);
List->Browser();
cout<<"Ok!"<<endl;
return 0;
}