单循环链表
单向循环链表是单链表的另一种形式,其结构特点是链表中最后一个结点的指针不再是结束标记,而是指向整个链表的第一个结点,从而使单链表形成一个环。
和单链表相比,循环单链表的长处是从链尾到链头比较方便。当要处理的数据元素序列具有环型结构特点时,适合于采用循环单链表。
单循环链表的初始化操作:示意图
非空表示意图:
假如终端结点用尾指针 rear 指示, 则查找终端结点是 O(1), 而开始结点,其实就是 rear->next->next, 时间复杂度也是 O(1)。
下面用C++ 代码实现单循环链表:
#include<iostream>
#include<cassert>
using namespace std;
using ElemType = int;
using Status = void;
class CirLinkList
{
public:
struct Node
{
ElemType m_data;
Node *m_next;
};
enum State
{
TT_ERROR = 0,
TT_OK = 1
};
public:
CirLinkList();
~CirLinkList();
ElemType insertAt(ElemType i, ElemType elem);
ElemType removeAt(ElemType i, ElemType &elemOut);
ElemType getAt(ElemType i, ElemType &elemOut);
ElemType locationElemAt(ElemType &i, ElemType elemOut);//查找与e相等的元素,返回第一个与e相等元素在线性表中的下标,否则,返回0
Status getLength()const;
Status isEmpty()const;
ElemType destroy();
ElemType clear();
Status show();
Status backRemoveElemAt(); //尾删
Status backInsertElemAt(ElemType elem);//尾插
Status headInsetElemAt(ElemType elem); //头插
Status headRemoveElemAt(); //头删
Status reserve(); //逆置链表
ElemType priorElemAt(ElemType cur_e, ElemType &pri_e);//若cur_e是链表的数据元素,且不是第一个,则用pre_e返回它的前驱
ElemType nextElemAt(ElemType cur_e, ElemType &Nex_e); //若cur_e是链表的数据元素,且不是最后一个,则用next_e返回它的后继,
Status createTail(ElemType *datas, ElemType length);//创建长度为length的链表,数据通过数组指定,这里采用尾插法
Status createHead(ElemType *datas, ElemType length); //头插法
Node *prevElemIndexAt(Node *nodeElem); //返回nodeElem指向的前面一个节点
ElemType modify(ElemType findElem, ElemType replaceElem); //把原有的elem1修改成elem2
Node *find(ElemType preElemAddress); //返回要查找元素的前面一个的地址
private:
Node *m_head;
Node *m_tail;
};
CirLinkList::CirLinkList()
{
m_head = new Node;
assert(m_head != nullptr);
m_head->m_next = m_head;
m_tail = m_head;
cout << "\n********************单向的循环列表初始化成功!************************" << endl;
}
CirLinkList::~CirLinkList()
{
this->destroy();
}
Status CirLinkList::createHead(ElemType *datas, ElemType length) //头插法
{
m_head->m_data = length;
Node *s = new Node;
if (m_head->m_next == m_head)
{
//this->insertAt(1,datas[0]); 利用insertAt 函数创建头插法的第一个结点
s->m_data = datas[0];
m_head->m_next = s;
s->m_next = m_head;
m_tail = s;
}
//Node *s = m_head->m_next;
for (int i = 1; i < length; ++i)
{
Node *p = new Node;
p->m_data = datas[i];
p->m_next = s;
m_head->m_next = p;
s = p;
}
}
CirLinkList::Node *CirLinkList::find(ElemType preElemAddress) //返回要查找元素的前面一个的地址
{
Node *p = m_head;
while ((m_tail != p) && (m_head) != (p->m_next) && (preElemAddress) != (p->m_next->m_data))
{
p = p->m_next; //循环结束,p指向x的前面一个元素
}
if (m_head == p->m_next) //如果p指向最后一个元素,说明没有找到
{
cout << "没找到该元素!" << endl;
return nullptr;
}
return p;
}
ElemType CirLinkList::modify(ElemType findElem, ElemType replaceElem) //把原有的elem1修改成elem2
{
if (!(m_head->m_data))
{
return TT_ERROR;
}
Node *p = find(findElem);
if (nullptr != p)
{
p->m_next->m_data = replaceElem;
}
return TT_OK;
}
CirLinkList::Node *CirLinkList::prevElemIndexAt(Node *nodeElem) //返回nodeElem指向的前面一个节点
{
if (nodeElem != m_head)
{
Node *q = m_head->m_next;
while (q != m_head && q->m_next != nodeElem) //依次往后移,知道尾指针的前面一个节点
{
q = q->m_next;
}
if (q->m_next == nodeElem)
{
return q;
}
}
return nullptr;
}
Status CirLinkList::reserve() //逆置链表
{
/* 自己编写的代码,没通过
m_tail->m_next = nullptr;
Node *p = m_head->m_next;
m_tail = p;
m_head->m_next = nullptr;
Node *s = new Node;
Node *m = s;
while (p)
{
p->m_next = s;
s = p;
p = p->m_next;
}
m_head->m_next = p;
delete m;*/
if (!(m_head->m_data) || (m_head->m_data == 1))
{
cout << "链表中没有元素,或者只有一个元素,无法反转列表!" << endl;
system("pause");
exit(0);
}
Node *s = new Node; //建立一个节点
s->m_next = m_tail;
Node *p = m_tail;
while (m_tail != m_head->m_next) //把原链表的尾节点到第一个节点依次连接到新节点上
{
m_tail = prevElemIndexAt(m_tail);
m_tail->m_next = m_head;
p->m_next = m_tail;
p = p->m_next;
}
p->m_next = s; //p指向第一个节点,即新链表的最后一个节点,尾指针的next指向头结点s,链表结束
delete m_head; //释放原来的头结点
m_head = s; //把s变成新的头指针
}
ElemType CirLinkList::priorElemAt(ElemType cur_e, ElemType &pri_e)//若cur_e是链表的数据元素,且不是第一个,则用pre_e返回它的前驱
{
if (!(m_head->m_data) || (m_head->m_data == 1))
{
return TT_ERROR;