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;
}

四、结语

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容