在单向链表(c++实现)中,链表的最后一个节点的nex指针指向NULL,而所谓的循环单向链表即是指链表的最后一个节点的next指针指向首节点(注意不是头节点,头节点是方便链表操作而存在的结构体变量)。循环链表是一种特殊的单向链表,因此软件设计上,循环链表可继承自单向链表。
循环单向链表的实现难点在于:
(1)插入数据的位置为0时,头节点和尾节点的next指针均指向新节点;
(2)删除位置为0的节点时,头节点和尾节点的next指针都指向为位置为1的节点,然后安全删除位置为0的节点。
//CirculateList.h
//LinkList类的源码参照前面的单向链表(c++实现)
#ifndef __CIRCULATELIST_H__
#define __CIRCULATELIST_H__
#include "LinkList.h"
template <typename T>
class CirculateList : public LinkList<T>
{
protected:
typedef typename LinkList<T>::Node_t Node_t;
//获取最后一个节点
Node_t* _last() const
{
return this->position(this->m_length - 1)->next;
}
//将最后一个节点的next指针指向首节点
void _last_2_first() const
{
_last()->next = this->m_header.next;
}
public:
bool insert(int i, const T& e) //插入操作涉及到可能插入的是首节点的位置所以需要重新实现
{
bool ret = true;
i %= this->m_length + 1; //循环链表,i的值可以大于链表的m_length,插入操作时i的值为[0, m_length]
ret = LinkList::insert(i, e);
//若插入的位置是首节点,需要将最后一个节点的next指针指向新节点
if (ret && i== 0)
{
_last_2_first();
}
return ret;
}
bool insert(const T& e)
{
return insert(this->m_length, e);
}
bool remove(int i) //删除操作涉及到可能删除的是首节点所以需要重新实现
{
bool ret = true;
i %= this->m_length;
if (i == 0) //删除的位置是首节点
{
Node_t* toDel = this->m_header.next;
if (toDel != NULL)
{
this->m_header.next = toDel->next;
--this->m_length;
if (this->m_length > 0)
{
_last_2_first();
if (this->m_current == toDel)
this->m_current = toDel->next;
}
else //链表中只有一个节点,删除后就链表为空
{
this->m_header.next = NULL;
this->m_current = NULL;
}
this->DestoryNode(toDel);
}
else
ret = false;
}
else
{
ret = LinkList<T>::remove(i);
}
return ret;
}
//调用LinkList<T>对应的成员函数,需要注意i的取值要取模
bool set(int i, const T& e)
{
return LinkList<T>::set(i % m_length, e);
}
T get(int i) const
{
return LinkList<T>::get(i % m_length);
}
int find(const T& e) const //LinkList的while()循环条件是next不为0,所以这里需要重新实现find()
{
int ret = -1;
Node_t* tmp = this->m_header.next;
for (int i = 0; i < this->m_length; ++i)
{
if (tmp->value == e)
{
ret = i;
break;
}
tmp = tmp->next;
}
return ret;
}
void clear() //LinkList的while()循环条件是next不为0,所以这里需要重新实现clear()
{
while (this->m_length > 1)
remove(1); //每次都删除位置为1的节点,避免重复调用_last_2_first()函数
if (this->m_length == 1)
{
Node_t* toDel = this->m_header.next;
this->m_header.next = NULL;
this->m_length = 0;
this->m_current = NULL;
this->DestoryNode(toDel);
}
}
bool move(int i, int step)
{
return LinkList<T>::move(i % this->m_length, step);
}
bool end() //循环链表,end()为true只能说明链表中无节点
{
return (this->m_length == 0 || this->m_current == NULL);
}
~CirculateList()
{
clear();
}
};
#endif /* __CIRCULATELIST_H__ */
测试:15只猴子围成一圈从1报数到7的出局,最后谁是猴王?
void DiademaMonkey(int cnt, int start, int n)
{
CirculateList<int> c;
for (int i = 1; i <= cnt; ++i)
c.insert(i);
c.move(start - 1, n - 1);
while (c.length() > 1)
{
c.next();
c.remove(c.find(c.current()));
}
cout << c.current() << endl;
}
int main()
{
DiademaMonkey(15, 1, 7);
getchar();
return 0;
}
编译运行: