C++ 数据结构之链表

链表

一、 何为链表

引用维基百科的介绍, 链表(Linked list)是一种常见的基础数据结构, 是一种线性表, 但是并不会按照线性的顺序存储结构,是一种”在物理空间上非连续、非顺序的存储结构”。

由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而顺序表相应的时间复杂度分别是O(logn)和O(1)。

链表通常由一连串节点组成,每个节点包含:

- 链域:   它的值是线性表的上一个/下一个元素的位置,即地址。
- 数据域: 它的值是存储的相应实例数据的值。

二、链表的优缺点

优点

  1. 使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。
  2. 相比数组结构,对于元素的插入和删除操作来说,链表的效率要比数组高,因为每个节点都有链域存储指向下一个节点的指针,因此进行插入和删除的操作时不需要频繁的移动其他的元素,只需要修改对应位置附近节点的链域的值即可。

缺点

  1. 查询链表只能通过指针顺序访问,效率相对低下,查询可能需要O(n)的时间复杂度。
  2. 因为链表的每个节点都含有链域,所占用的空间较多。

三、单链表的实现(C++)

  • 定义节点的结构
template<class T>
struct ListNode
{
  T m_tElement;          // 数据域
  ListNode<T>* m_pNext;  // 链域
  // 构造函数
  ListNode(){}
  ListNode(const T& theElement) {this->m_tElement = theElement;}
  ListNode(const T& theElement, ListNode<T>* theNext)
  {
    this->m_tElement = theElement;
    this->m_pNext = theNext;
  }
}
  • 定义链表类
template<class T>
class SingleList
{
public:
    // 构造函数与析构函数
    SingleList();
    SingleList(const SingleList<T>& theList);
    ~SingleList();
    
    // 类方法 
    bool empty() const {return m_iLength == 0;}      // 判断链表是否为空
    int size() const {return m_iLength;}             // 返回链表长度
    int indexOf(const T& theElement) const;          
    T& get(int theIndex) const;
    void insert(int theIndex, const T& theElement);
    void delete(int theIndex);
    void update(int theIndex, const T& theElement);
    
private:
    void checkIndex(theIndex);  // 确认是否索引值是否合法
    int m_iLength;              // 链表的长度
    ListNode<T>* m_pFirstNode;  // 链表的头节点
}
  • 构造函数的实现
// 无参构造函数
template<class T>
SingleList<T>::SingleList()
{
  m_pFirstNode = NULL;
  m_iLength = 0;
}
// 复制构造函数
template<class T>
SingleList<T>::SingleList(const SingleList<T>& theList)
{
  m_iLength = theList.m_iLength;
  // 判断源链表是否为空链表
  if(m_iLength == 0)
  {
    m_pFirstNode = NULL;
    return;
  }
 
  ListNode<T>* otherNode = theList.m_pFirstNode;
  m_pFirstNode = new ListNode<T>(otherNode->m_tElement);
  ListNode<T>* thisNode = m_pFirstNode;
  otherNode = otherNode->m_pNext;
  
  while (otherNode != NULL)
  { 
    // 当源链表后续还有节点时,复制链表剩下的其他节点
    thisNode->m_pNext = new ListNode<T>(otherNode->m_tElement);
    thisNode = thisNode->m_pNext;
    otherNode = otherNode->m_pNext;
  }
  thisNode->next = NULL;
}
  • 析构函数的实现
template<class T>
SingleList<T>::~SingleList()
{
  while (m_pFirstNode != NULL)
  {
    ListNode<T>* tempNode = m_pFirstNode;
    delete m_pFirstNode;
    m_pFirstNode = tempNode;
  }
}
  • 类方法的实现

    int indexOf(const T& theElement) const

// 返回指定元素的索引值
template<class T>
int SingleList<T>::indexOf(const T& theElement) const
{
  ListNode<T>* currNode = m_pFirstNode;
  int index = 0;
  while (currNode != NULL && currNode->m_tElement != theElement)
  {
    currNode = currNode->m_pNext;
    ++index;
  }
  if (currNode == NULL)
  {
    return -1;
  }
  if (currNode != NULL)
    return index;
}

​ T& get(int theIndex) const

// 返回指定索引的元素
template<class T>
T& SingleList<T>::get(int theIndex) const
{
  checkIndex(theIndex);
  ListNode<T>* currNode = m_pFirstNode;
  // 找到索引值对应的元素
  for(int i = 0; i < theIndex; ++i)
    currNode = currNode->m_pNext;
  // 返回元素的值
  return currNode->m_tElement;
}

​ void insert(int theIndex, T& theElement)

// 在指定位置插入元素
template<class T>
void SingleList<T>::insert(int theIndex, const T& theElement)
{ // 判断索引值是否合法
  checkIndex(theIndex);
  if (theIndex == 0)
  {
    m_pFirstNode = new ListNode<T>(theElement, m_pFirstNode)
  }
  if (theIndex > 0)
  {
     ListNode<T>* currNode = m_pFirstNode;
     // 因为要在指定位置插入元素, 因此去找指定位置的前一个元素
     for (int i = 0; i < theIndex - 1; ++i)
        currNode = currNode->m_pNext;
     ListNode<T>* newNode = new ListNode<T>(theElement, currNode->m_pNext);
  }
  ++m_iLength;
}

​ void delete(int theIndex)

// 删除指定位置的元素
template<class T>
void SingleList<T>::delete(int theIndex)
{
  checkIndex(theIndex);
  ListNode<T>* targetNode;
  if (theIndex == 0)
  {
    targetNode = m_pFirstNode;
    m_pFirstNode = m_pFirstNode->m_pNext;
  }
  if (theIndex > 0)
  {
    ListNode<T>* prevNode = m_pFirstNode;
    for (int i = 0; i < theIndex - 1; ++i) 
      prevNode = prevNode->m_pNext;
    targetNode = prevNode->m_pNext;
    prevNode->m_pNext = targetNode->m_pNext;
  }
  delete targetNode;
  --m_iLength;
}

​ void update(int theIndex, const T& theElement)

// 修改指定位置元素的值
template<class T>
void SingleList<T>::update(int theIndex, const T& theElement)
{
  // 判断索引值是否合法
  checkIndex(theIndex);
  // 
  if (theIndex == 0)
  {
    m_pFirstNode->m_tElement = theElement;
    return ;
  }
  
  ListNode<T>* currNode = m_pFirstNode;
  for (int i = 0; i < theIndex; ++i)
    currNode = currNode->m_pNext;
  currNode->m_tElement = theElement;
}

​ void checkIndex(int theIndex)

// 检查索引值是否合法
template<class T>
void SingleList<T>::checkIndex(int theIndex)
{
  if (theIndex < 0 || theIndex > m_iLength - 1)
    std::cout << "Error Index Value" << std::endl;
}

四、结语

这是我第一次做类似的学习笔记,借鉴了网上许多的博客以及书籍的资料和内容,在这里做个记录,若是有错误或不恰当之处,希望各路大神能不吝赐教,指点小弟不足之处。

    原文作者:KinBozz
    原文地址: https://www.jianshu.com/p/c525121f729e
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞