单向链表的操作

建立单向链表
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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值