单链表一

本文介绍了单链表的基本概念,包括数据结构组成与实现方式,并详细解析了单链表的插入与删除算法。
         单链表是一种最简单的数据结构,也叫线性链表。用它来表示线性关系时,用指针表示结点之间的逻辑关系。因此单链表的一个存储结点包含两个部分:
        

Data

link

    其中data部分称为数据域,用于存储线性表的一个数据元素,其数据类型由用户的参数决定。link部分称为指针域或者链域,用于存放一个指针,该指针表示该链表中下一个结点的开始地址。
    该结构采用一个LinkNode类来实现:
   
    template<class T>
    class LinkNode{    //链表结点类
    public:
         int data;
         LinkNode<T> *link;
         //---------只初始化指针域的构造函数------
         LinkNode(LinkNode<T> *ptr=NULL)
         {
              link=ptr;
         }
         //--------初始化数据域和指针域-----------
         LinkNode(const T& item,LinkNode<T> *ptr=NULL)
         {
              data=item;
              link=ptr;
         }
        };


    
    该类使用了C++的模板类,这样就可以在调用时传入具体的类型,具有灵活性。
    在类定义的开始处使用了C++的宏定义:
    #ifndef LIST_H
    #define LITS_H

    #endif // !LIST_H
    防止重复定义头文件。
    单链表的的结构图如下:
     图片
    

    链表的第一个结点可以通过链表的头指针first找到,其他结点的地址则在前驱结点的link域中,链表的最后一个结点没有后继,在链表的link域中放一个NULL值。
    链表类使用基类和派生类的方法实现,基类是上述的LinkNode类,派生类继承LinkNode类,其定义如下:

    
template<class T>
class List:public  LinkNode<T>{
public:
	LinkNode<T> *first;		//链表头指针
public:
	//----------只初始化头指针的构造函数----------
	List()
	{
		//初始化链表头指针
		first=new LinkNode<T>;
	}
	//---------初始化数据成员和指针的构造函数-----
	List(const T& x)
	{
		first=new LinkNode<T>(x);
	}

	//---------复制构造函数--------------
	List(List<T>& L );
	//---------析构函数------------------
	~List()
	{
		makeEmpty();
	}

	//---------------单链表相关操作-----------
	int Length()const;				//计算链表长度
	LinkNode<T> *getHead()const{return first;}//返回附加头结点的地址
	LinkNode<T> *getHead(LinkNode<T> *p){first=p;}//设置附加头结点的地址
	LinkNode<T> *Search(T x);		//搜索包含数据x的元素
	LinkNode<T> *Locate(int i);		//搜索第i个元素的地址
	T	*getData(int i);			//取出第i个元素的值
	void setData(int i,T& x);		//将第i个元素设置为x
	bool IsEmpty()const				//判断表是否为空
	{
		return first->link==NULL?true:false;
	}
	bool IsFull()const{return false;}//判断表满
	void Sort();					//排序
	void makeEmpty();				//清空链表
	bool Insert(int i,const T &x);		//在第i个元素后面插入元素
	bool Remove(int i,T &x);		//删除第i个元素,x返回该删除的值
	
	void output();					//输出

	//------------建立单链表的两种方法---
	void InputFront(T endTag);		//前插法建立单链表
	void InputRear(T endTag);		//后插法建立单链表

	//操作符重载函数
	List<T>& operator=(List<T>& L);	//重载函数,赋值


			
};

     利用单链表表示线性表,将使得插入和删除变得很方便,只要修改链中结点的位置,无需移动表中的元素,就能实现高效的插入和删除。插入算法:
     1、若Ai是链表中的第一个结点中的数据,则新结点newNode应该插入到第一个结点之前,这时必须修改链表的头指针first,插入时要修改指针为:
     newNode->link=first;first=newNode
     2、若Ai不是链表中的第一个元素,也不是最后一个结点,首先让一个检测结点current指向Ai所在结点,再将新结点插入到Ai所在结点之后。此时需要修改指针为:
     newNode->link=current->link;current->link=newNode
    3、当Ai是链表中的最后一个结点,新结点追加在表尾,这时先让current指向含An的结点,即表中最后一个结点,再指向
    newNode->link=current->link;current->link=newNode;
   
    插入结点的代码如下:
   
//---------单链表的插入--------
template<class T>
bool List<T>::Insert(int i,const T& x)
{
	//链表为空或者插入到第一个元素之前,此时i=0
	if(i==0 || first==NULL)
	{
		//建立一个新结点
		LinkNode<T> *newNode=new LinkNode<T>(x);
		//如果建立该结点失败,输出提示信息
		if(newNode==NULL)
		{
			cerr<<"存储分配错误\n";
			exit(1);
		}
		//将新建立的结点的link指针赋值为first,将first赋值为newNode
		newNode->link=first;
		first=newNode;

	}
	else
	{
		//在链表的中间或者尾部插入新结点,在第i个结点处插入元素,则需先找到该位置
		LinkNode<T> *current=first;
		//循环查找第i个结点
		for(int k=1;k<i;k++)
		{
			if(current==NULL)
				break;
			else
			{
				current=current->link;
			}
		}
		//如果i>该链表的长度
		if(current==NULL && first!=NULL)
		{
			cerr<<"链表太短,已经到达链表尾部\n";
			return false;
		}
		else
		{
			//将该结点插到链表中间
			LinkNode<T> *newNode=new LinkNode<T>(x);
			//如果建立该结点失败,输出提示信息
			if(newNode==NULL)
			{
				cerr<<"存储分配错误\n";
				exit(1);
			}

			newNode->link=current->link;
			current->link=newNode;
		}

	}

	return true;

}

   单链表的删除算法也分为两种情况:
   1、在链表的第一个位置处删除,这时需要先用指针del保存第一个结点的地址,再将链表的头指针指向其下一个结点,使其成为新的链表的首元素结点,最后删除由del保存的原首元素地址。
   del=first;first=first->link;delete del;
   2、在链表的中间或者尾部删除,首先用del保存第i个结点的地址,再让第i-1个结点的link指针保存第i+1个结点的地址,通过重新拉链,把第i个结点从链中分离出来,最后再删除del保存的结点。
del=current->link;current->link=del->link;delete del;

 
//---------单链表的删除---------
template<class T>
bool List<T>::Remove(int i, T& x)
{
	//把链表中第i个元素删去,i从1开始
	LinkNode<T> *del,*current;
	//如果i==1,则用del记录这个指针,然后重新拉链
	if(i<=1)
	{
		del=first;
		first=first->link;
	}
	else
	{
		//如果不是第一个结点,首先要遍历找到第i-1个结点
		current=first->link;				//记录当前的头指针
		for(int k=1;k<i-1;k++)
		{
			if(current=NULL)
				break;
			else
			{
				current=current->link;
			}
		}

		//空链表或者链表太短
		if(current==NULL||current->link==NULL)
		{
			cerr<<"链表的长度太短,已经到达尾部\n";
			return false;
		}

		//删除中间结点和尾结点
		del=current->link;
		current->link=del->link;

	}

	//取出被删结点中的数据值
	x=del->data;
	//删除这个指针
	delete del;

	return true;

}

当寻找第i-1个基点时有三种情况,第一种是current=NULL,链表太短。第二种情况是current!=NULL,但是current->link==NULL,此时也无法
删除,第三种情况就是正常的可以删除的情况。
   单链表的重点是插入和删除元素。
   
 
  

 

 

 

 

 

 

 

 

 

 

 

 

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值