单向链表

链表是由一个个节点组成的数组,节点之间的内存并不连续,为了搞清楚链表的原理,我们先来看看节点的形式。

template<class T>
struct chainNode
{
	T element;
	chainNode<T>*next;
	
	chainNode(){}
	chainNode(const T& element;)
	chainNode(const T& element,chainNode<T>*next)
	{
		this->element=element;
		this->next=next
	}
}

以上是节点的代码,是个构造函数,里面有两个变量element和next一个用来存储元素,另一个用来存取下一个节点的

地址,通过next就能将分散栽在不同内存的节点链接起来,但是我们只能通过前面的节点找到后面的节点,所以这个叫

单向链表,里面有三个构造函数。这里提一下,结构体和类的构建和使用方法是非常类似的,可以使用结构体的地方我们

都可以用类来代替,反之大部分情况也是可以的。区别在于,构造体只能公有继承。

有了上面节点这个材料,我们就可以开始构建链表了。

template<class T>
class chain:public linearList<T>
{
	public:
	chain(int initialCapacity=10);
	chain(const chain<T>&);
	~chain();
	
	bool empty()const {return listSize==0;}
	int size() const {return listSize;}
	T& get(int theIndex) const;
	int indexOf(const T& theElement)const;
	void erase(int theIndex);
	void insert(int theIndex,const T& theElement);
	void output(ostream& out)const;
	
	protected:
	void checkIndex(int theIndex)const;
	chainNode<T>* firstNode;
	int listSize;
}

以上就是链表的类定义,里面构造函数里面有capacity这个变量,但是类定义里面并没有这个成员变量,因为,链表的最大长度是无限的,写这个只是为了和arrayList进行兼容,然后size记录了当前节点的个数,在chain类里面,只有一个firstNode成员,这个成员指向链表的第一个节点,因为知道了链表的第一个节点,我们就可以找到链表的所有节点。

template<class T>
chain<T>::chain(int initialCapacity)
{
	if(initialCapacity<1)
	{
		ostringstream s;
		s<<"Initial capacity="<<initialCapacity<<"Must be >0";
		throw illegalParameterValue(s.str());
	}
	firstNode=NULL;
	listSize=0;
}

template<class T>
chain<T>::chain(const chain<T>& theList)
{
	listSize=theList.listSize;
	if(listSize==0)
	{
		firstNode=NULL;
		return;
	}
	chainNode<T>* sourceNode=theList.firstNode;//获取第一个节点的地址
	firstNode=new chainNode<T>(sourceNode->element);//new一个新节点作为新的firstNode。
	sourceNode=sourceNode->next;//获取第二个节点的地址
	chainNode<T>* targetNode=firstNode;//构建targetNode作为以下循环的中间变量
	while (sourceNode!=NULL)
	{
		targetNode->next=new chainNode<T>(sourceNode->element);
		targetNode=targetNode->next;
		sourceNode=sourceNode->next;
	}
	targetNode->next=NULL;
}

以上为构造函数和复制构造函数,构造函数很简单我就不说了,复制构造函数就有点复杂了,得创建很多个新节点来容纳旧节点

的内容,首先获得旧节点的firstNode数据给sourceNode,获得这个数据后,旧链表就没用了。然后new一个新节点作为新链表的firstNode.然后不断new新节点将旧节点的数据写入,然后再前一个节点的next项写入新节点的地址,这样新链表就诞生了。这个过程我说的有点绕,仔细看还是能看懂的。所以说链表的复制构造非常麻烦,且浪费时间。

template<class T>
chain<T>::~chain()
{
	while(firstNode!=NULL)
	{
		chainNode<T>* nextNode=firstNode->next;
		delete firstNode;
		firstNode=nextNode;
	}
}

以上为析构函数,在删除第一个节点之前一定的先提出第二个节点的地址,否则将发生内存泄漏。

template<class T>
T& chain<T>::get(int theIndex)const
{
	checkIndex(theIndex);
	chainNode<T>*currentNode=firstNode;
	for(int i=0;i<theIndexli++)
	{
		currentNode=currentNode->next;
	}
	return currentNode->element;
}

get函数必须得从第一个节点开始往后查找,效率非常低下。


template<class T>
T& chain<T>::indexOf(const T& theElement)const
{
	chainNode<T>* currentNode=firstNode;
	int index=0;
	while(currentNode!=NULL&¤tNode.element!=theElement)
	{
		currentNode=currentNode->next;
		index++;
	}
	if(currentNode==NULL)
		return -1;
	else
		return index;
}

indexOf函数一样得从头开始查找,速度也非常慢。

template<class T>
void chain<T>::erase(int theIndex)
{
	checkIndex(theIndex);
	chainNode<T>* deleteNode;
	if(theIndex=0)
	{
		deleteNode=firstNode;
		firstNode=firstNode->next;
	}
	else
	{
		chainNode<T>*p=firstNode;
		for(int i=0;i<theIndex-1;i++)
			p=p->next;
		deleteNode=p-next;
		p->next=p->next->next;
	}
	listSize--;
	delete deleteNode;
}
template<class T>
void chain<T>::insert(int theIndex,const T& theElement)
{
	checkIndex(theIndex);
	if(theIndex==0)
		firstNode=new chainNode(theElement,firstNode);
	else
	{
		chainNode<T>* p=firstNode;
		for(int i=0;i<theIndex-1;i++)
			p=p->next;
		p->next=new chainNode(theElement,p->next);//p->next在插入之前代表的是插入之后的那个地址。插入之后才是p->next->next.
		
	}
	listSize++;
}

以上就是删除和插入的代码,插入和删除都是一样的思想,它们分两种情况,第一种插入或者删除第一个节点内容,这时只需改变第一个firstNode的数据即可,第二种插在或者删除其他的节点,这时只需要改变插入或者删除节点的前一个节点的next数据和

插入节点的next数据即可,不过再删除节点后记得要析构掉数据,防止内存泄漏。

template<class T>
void chain<T>::output(ostream& out)const
{
	for(chainNode<T>* currentNode=firstNode;currentNode!=NULL;currentNode=currentNode->next)
		out<<currentNode->element<<" ";
}
template<class T>
ostream& operator<<(ostream& out,const chain<T>& x)
{
	x.output(out);
	return out;
}

以上为输出函数。

以上就是这个链表的基本功能了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值