一、链表
链表:是一种常见的数据结构,所有的数据以节点的形式存储在一个线性结构中,但是,链表的节点并不是顺序存储的,而是通过节点的指针把所有节点连接起来;对链表的操作主要就是对节点的操作,对链表的插入和删除操作的时间复杂度是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、存在的问题
单向链表在获取当前节点的前一个节点时,需要从链表的首节点重新开始查找