约瑟夫问题折腾了很久,还询问了别人,最后终于自己敲出了一个自认为完美的解决方案。
虽然我一开始写的代码可以输出结果,但是可能是因为时间超限,原本可能是rear指针移动的原因,直接反映到析构上,这样也好。长见识了,以后如果析构出问题了,就要检查一下指针的相关移动。
难点在于仅用尾指针将结点插在尾部,不用头结点和头指针。
现在这个难点解决了!实际上所有的难点都是建立在基础上的,就像插入节点时需要先将下一个节点的地址保存一样,循环链表中的头结点也没什么不同,不过是每次插入时都要现将头结点的地址赋给新节点的next域。而头结点的地址始终保存在rear指针指向的结点的next域中,所以重中之重是每次一定要移动尾指针以确保尾指针的位置正确。
题目描述:约瑟夫(Joseff)问题求解。n个人围成一圈,编号依次为1, 2....n,从第一个人开始报数,m号出圈,再从下一个开始报数m号出圈,直至所有人出圈。求出圈的次序。要求采用仅设尾指针的单向循环链表实现。已知类的定义、部分成员函数及主函数代码如下(勿改动)。
如下是插入函数的代码:
template <class T>
void LinkList<T>::RInsert(T x)
{
Node<T>* p;
p = new Node<T>;//分配空间
p->data = x;
if (rear == NULL)
{
rear = p;
p->next = rear;
}
else
{
p->next = rear->next;
rear->next = p;
rear = rear->next;
}
}
以下是约瑟夫代码:
template <class T>
void LinkList<T>::Joseff(int m)
{
Node<T>* p;
if (rear)
{
p = rear->next;
for (int i = 1; p->next != p; i++, p = p->next)
{
if (i == m-1 )
{
Node<T>* q = p->next;
p->next = q->next;
cout << q->data << " ";
i = 0;
}
}
cout << p->data;
}
rear = NULL;
}
没想到这道约瑟夫的重点却是尾结点尾插法。
不过这种约瑟夫的写法也是简洁明了。