C++数据结构与算法——单向循环链表

来源:互联网 发布:淘宝客服工作感想 编辑:程序博客网 时间:2024/06/04 18:53

单向循环链表:相对于单向链表的最后一个节点的next指针指向nullptr,单向循环链表的最后一个节点的next指针指向链表头。此处主要实现了单向循环链表的插入、删除、构造、析构、输出操作符等简单功能。

注意:单向循环链表最主要关心的是插入、删除时头节点的更新问题。如,在链表头删除时需要将链表头指向下一个节点或者置为nullptr。

单向循环链表实现:

#pragma once#include <iostream>using namespace std;template<typename T>struct ChainNode{    ChainNode<T> *next;    T data;    ChainNode(const T &t) { data = t; next = nullptr; }    ChainNode(const ChainNode<T> & d):next(d.next),data(d.data){}};template<typename T>class CircularList{public:    CircularList():m_head(nullptr),m_isize(0){}    ~CircularList();    bool Insert(const T &t, const int n = 0);    bool DeleteAt(T &t, const int n);    bool IsEmpty() { return (m_isize == 0); }    void AddBack(const T &t);    ChainNode<T> *GetTail();    friend ostream &operator<< (ostream &os, const CircularList<T> & rhl)    {        ChainNode<T> *tmp = rhl.m_head;        for (int i = 0; i < rhl.m_isize;++i)        {            os << tmp->data << "  ";            tmp = tmp->next;        }        return os << endl;    }protected:    ChainNode<T> *GetAt(const int n);private:    ChainNode<T> *m_head;    int m_isize;};// 删除第n个节点// 删除主要考虑的是,要将删除节点的前一节点和后一节点连接起来,要考虑删除头节点时更新头节点的情况template<typename T>bool CircularList<T>::DeleteAt(T &t, const int n){    if (n < 0 || n > m_isize - 1)    {        return false;    }    ChainNode<T> *tmp = GetAt(n);    if (n == 0)    {        ChainNode<T> *tail = GetTail();        if (m_isize == 1)        {            m_head = nullptr;        }        else        {            m_head = tmp->next;            tail->next = m_head;        }               }    else    {        ChainNode<T> *prev = GetAt(n - 1);        prev->next = tmp->next;    }    t = tmp->data;    delete tmp;    m_isize--;    return true;}// 将t插入到第n个节点后,如果为空链表则调用addback// 插入主要考虑的是将第n个节点指向新节点,将新节点指向n+1个节点(当n为m_isize-1时需要指向m_head)template<typename T>bool CircularList<T>::Insert(const T &t, const int n){    if (IsEmpty())    {        if (n == 0)        {            AddBack(t);            return true;        }        return false;    }    // 插入的地方非法    if (n < 0 || n >= m_isize)    {        return false;    }    // 如果链表不为空,则有可以是在头、中、尾三个地方插入,以下代码满足三种情况    ChainNode<T> *tmp = GetAt(n);    ChainNode<T> *next = tmp->next;    ChainNode<T> *newnode = new ChainNode<T>(t);    tmp->next = newnode;    newnode->next = next;    ++m_isize;    return true;}template<typename T>ChainNode<T> * CircularList<T>::GetTail(){    return GetAt(m_isize - 1);}template<typename T>CircularList<T>::~CircularList(){    // 由于是单向循环链表,遍历时如果以指针是否为空或者指向head节点为结束条件都不合适,因此使用m_isize不为0为条件进行遍历    ChainNode<T> *tmp = m_head;    while ( m_isize != 0)    {        tmp = m_head->next;        delete m_head;        m_head = tmp;        --m_isize;    }}template<typename T>inline void CircularList<T>::AddBack(const T & t){    ChainNode<T> * newnode = new ChainNode<T>(t);    // 当前链表为空    if (m_head == nullptr)    {        m_head = newnode;        m_head->next = m_head;        ++m_isize;        return;    }    // 链表不为空,则将最后一个节点指向新节点,新节点指向head节点    ChainNode<T> *tmp = GetTail();    tmp->next = newnode;    newnode->next = m_head;    ++m_isize;    return;}template<typename T>ChainNode<T> * CircularList<T>::GetAt(const int n){    // 只能获取下标[0,m_isize - 1]的元素    if (n < 0 || n >= m_isize)    {        return nullptr;    }    ChainNode<T> * tmp = m_head;    for (int i = 0;i < n;++i)    {        tmp = tmp->next;    }    return tmp;}

单向循环链表测试:

#include "stdafx.h"#include "CircularList.h"#include <iostream>using namespace std;int main(){    CircularList<int> *pnode = new CircularList<int>;    pnode->AddBack(10);    pnode->AddBack(15);    pnode->AddBack(24);    pnode->AddBack(36);    cout << *pnode;    pnode->Insert(1314, 1);    cout << *pnode; // 10 15 1314 24 36    int iret = -1;    pnode->AddBack(386);// 10 15 1314 24 36 386    pnode->DeleteAt(iret, 4);// delete 36    cout << *pnode; // 10 15 1314 24 386    return 0;}
阅读全文
1 0
原创粉丝点击