加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

【数据结构】 单向链表

发布时间:2020-12-15 06:32:06 所属栏目:安全 来源:网络整理
导读:一、链表 链表 :是一种常见的数据结构,所 有的数据以节点的形式存储在一个线性结构中,但是,链表的节点并不是顺序存储的,而是通过节点的指针把所有节点连接起来;对链表的操作主要就是对节点的操作,对链表的 插入 和 删除 操作的 时间复杂度是O(1), 但

一、链表

链表:是一种常见的数据结构,所有的数据以节点的形式存储在一个线性结构中,但是,链表的节点并不是顺序存储的,而是通过节点的指针把所有节点连接起来;对链表的操作主要就是对节点的操作,对链表的插入删除操作的时间复杂度是O(1),但是对链表的随机访问时间复杂度是O(n)

节点:数据 + 指针域(数据域存放具体的数据、各节点之间通过指针域连接起来)

1、单向链表

链表中最简单的一种是单向链表,它包含两个域,一个信息域和一个指针域。这个链接指向列表中的下一个节点,而最后一个节点则指向一个空值。


一个单向链表包含两个值: 当前节点的值和一个指向下一个节点的链接

一个单向链表的节点被分成两个部分。第一个部分保存或者显示关于节点的信息,第二个部分存储下一个节点的地址。单向链表只可向一个方向遍历。

本例使用C++类模版实现单向链表,主要提供以下接口:
1、创建链表
2、在链表的尾节点、及其他索引插入新节点
3、删除指定索引的节点
4、更新指定索引的节点的值

1.1、单向链表的节点结构

使用类模版封装链表的节点结构,链表的节点除了存储数据之外还要还要存储指针,而且链表应该还能对节点的指针进行操作

template <class T>
class CListNode
{
protected:
	//节点的值
	T m_nodeValue;
	//节点对应的指针,用于指向下一节点
	CListNode<T> * m_link;
public:
	//默认构造函数
	CListNode();
	//构造函数
	CListNode(const T& value);
	//获取节点的值
	const T& GetNodeValue() const;
	//设置节点的值
	void SetNodeValue(T value);
	//设置节点的指针
	void SetNodeLink(CListNode<T> * next);
	//获取节点的指针
	CListNode<T>* GetNodeLink();
};

1.1.1、节点的构造函数实现

主要是初始化节点的值和指针

template<class T>
CListNode<T>::CListNode():m_link(0)
{
}

template<class T>
CListNode<T>::CListNode(const T& value):m_nodeValue(value),m_link(0)
{
}

1.1.2、设置和获取节点的值

template<class T>
const T& CListNode<T>::GetNodeValue() const
{
	return m_nodeValue;
}

template<class T>
void CListNode<T>::SetNodeValue(T value)
{
	m_nodeValue = value;
}

1.1.3、设置和获取节点的指针

template<class T>
void CListNode<T>::SetNodeLink(CListNode<T> * next)
{
	m_link = next;
}

template<class T>
CListNode<T>* CListNode<T>::GetNodeLink()
{
	return m_link;
}

1.2、单向链表的定义和实现

template <class T>
class CLinkList
{
private:
	//链表的头节点
	CListNode<T> * m_head;
	//链表的尾节点
	CListNode<T> * m_tail;
private:
	//获取指定索引的指针(从头节点开始(索引0))
	CListNode<T> * GetLink(size_t index);
	//获取链表节点个数
	size_t GetCount() const;
	//获取链表的头节点
	CListNode<T> *GetHead() const;
public:
	CLinkList();
	virtual ~CLinkList();
	//链表表尾插入节点
	bool AddTail(const T value);
	//在链表指定位置插入节点
	bool InsertAt(unsigned int index,const T& value);
	//删除链表指定位置的节点
	bool RemoveAt(size_t index,T & value);
	//获取指定位置节点的值
	bool GetNodeAt(size_t index,T & value); 
	//更新指定位置节点的值
	bool UpdateAt(size_t index,const T & value);
	//删除链表所有节点
	bool RemoveAll();
	//重载链表输出运算
	friend ostream & operator<<(ostream & os,const CLinkList<T> & alist)
	{
		CListNode<T> * pNode = alist.GetHead();
		while(pNode = pNode->GetNodeLink())
		{
			os << pNode->GetNodeValue() << " ";
			
		}
		return os;
	}
	
};

1.2.1、创建链表及获取链表的头节点

template<class T>
CListNode<T>* CLinkList<T>::GetHead() const
{
	//返回首节点指针
	return m_head;
}

template<class T>
CLinkList<T>::CLinkList()
{
	//创建首节点和尾节点
	m_head = m_tail = new CListNode<T>;
	//设置节点
	m_tail->SetNodeLink(0);
}

1.2.2、获取链表指定索引的指针

template<class T>
CListNode<T> * CLinkList<T>::GetLink(size_t index)
{
	//判断位置的合法性
	if(index < 0 || index >= GetCount())
	{
		return 0;
	}
	//从首节点开始查找
	CListNode<T> * curNode = m_head;
	while(index--)
	{	
		curNode = curNode->GetNodeLink();
	}
	//返回找到的节点
	return curNode;
}

1.2.3、获取链表的节点个数

template<class T>
size_t CLinkList<T>::GetCount() const
{
	size_t cnt = 0;
	//从首节点开始遍历,
	CListNode<T> * pLink = m_head;
	while(true)
	{
		cnt++;
		pLink = pLink->GetNodeLink();
		//链表遍历完成退出循环
		if(m_tail == pLink)
			break;
	}
	//返回链表节点个数
	return cnt;
}

1.2.4、在链表的尾节点插入新节点

template<class T>
bool CLinkList<T>::AddTail(const T value)
{
	//创建新节点
	CListNode<T> * aNode = new CListNode<T>(value);
	//创建失败,返回false
	if(0 == aNode)
		return false;
	//在尾节点插入新节点
	m_tail->SetNodeLink(aNode);
	m_tail = m_tail->GetNodeLink();
	m_tail->SetNodeLink(0);
	if(0 == m_tail)
	{
		return false;
	}
	return true;
}

1.2.5、在链表任意指定索引中插入新节点

template<class T>
bool CLinkList<T>::InsertAt(unsigned int index,const T& value)
{
	//创建新节点
	CListNode<T> * aNode = new CListNode<T>(value);
	if(0 == aNode)
		return false;
	//获取指定位置节点的指针
	CListNode<T> * curNode = GetLink(index);
	//插入新节点
	aNode->SetNodeLink(curNode->GetNodeLink());
	curNode->SetNodeLink(aNode);
	if(0 == curNode->GetNodeLink())
	{
		return false;
	}
	return true;
}

1.2.6、删除链表中任意指定索引的节点

template<class T>
bool CLinkList<T>::RemoveAt(size_t index,T & value)
{
	//获取待删除索引的节点
	CListNode<T> * pNode = GetLink(index);
	if(0 ==pNode)
	{
		return false;
	}
	//获取待删除索引的前一个节点
	CListNode<T> * pPreNode = GetLink(index-1);
	
	if(0 != pPreNode)
	{
		pPreNode->SetNodeLink(pNode->GetNodeLink());
	}
	else
		m_head->SetNodeLink(pNode->GetNodeLink()); //在链表首节点插入新节点
	value = pNode->GetNodeValue();//返回删除节点的值
	delete pNode;
	return true;
}

1.2.7、获取链表中指定索引的节点的值

template<class T>
bool CLinkList<T>::GetNodeAt(size_t index,T & value) 
{
	//获取节点的指针
	CListNode<T> * pNode = GetLink(index);
	if(0 == pNode)
	{
		return false;
	}
	//获取节点的值
	value = pNode->GetNodeValue();
	return true;
}

1.2.9、更新链表中指定索引的节点的值

template<class T>
bool CLinkList<T>::UpdateAt(size_t index,const T & value)
{
	CListNode<T> * pNode = GetLink(index);
	if(0 == pNode)
	{
		return false;
	}
	//设置节点的值
	pNode->SetNodeValue(value);
	return true;
}

1.2.10、删除链表中所有的节点

template <class T>
bool CLinkList<T>::RemoveAll()
{
	size_t i = 1;
	T value;
	for(; i < GetCount(); ++i)
	{
		RemoveAt(i,value);
	}
	return true;
}

1.2.11、析构函数

template<class T>
CLinkList<T>::~CLinkList()
{  RemoveAll(); }

1.3、存在的问题

单向链表在获取当前节点的前一个节点时,需要从链表的首节点重新开始查找

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读