在解决约瑟夫问题上,利用无表头的单循环链表是相当简单的,可以将约瑟夫问题当作链表的删去节点操作。
约瑟夫问题:已知n个人围坐在一张圆桌周围。从编号为s的人开始报数,数到m的那个人出列;又从其下一个人开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。
解题思路:
1.产生length=n的单循环链表
2.重置first指针,令第s个人的位置为新的first(起点)
3.while(n)
{
删除第m个节点;
重置first指针,获得新起点;
}
通过这样,可以解决约瑟夫问题,此解法关键是重置first位置。
PS:如果有更好的解决思路,或者代码有缺陷的地方,请告知我,谢谢!
1.头文件:
#ifndef CHAIN_H
#define CHAIN_H
#include<iostream>
//约瑟夫问题利用无表头的单循环链表是最佳的
//将有表头的单循环链表稍作修改成无表头
template<class T>
class chainnode
{
template<class T>
friend class chain;
public:
chainnode()
{
next = nullptr;
data = 0;
}
~chainnode()
{
}
void setdata(const T& dat)
{
data = dat;
}
public:
T getdata()
{
return data;
}
chainnode<T>* getnext()
{
return next;
}
private:
T data;
chainnode<T>* next;
};
template<class T>
class chain
{
public:
chain()
{
length = 0;
first = nullptr;
}
~chain()
{
}
public:
bool isempty() //当循环链表中只存在表头的时候,为空
{
return first == nullptr;
}
chainnode<T>* getfirst()
{
return first;
}
void deletenode(int pos);
int getlength();
void insertbefore(T dat, int pos);
void insertafter(T dat, int pos);
T find(int pos);
void createchain(int n);
void joseph(int n, int s, int m);
private:
chainnode<T>* first; //指向第一个节点
int length;
};
template<class T>
void chain<T>::insertbefore(T dat, int pos) //在pos位置前面插入一个元素
{
if (pos< 0 || pos>length)
{
std::cout << "输入的位置数错误" << endl;
exit(1);
}
chainnode<T>* now = new chainnode < T >;
now->data = dat;
if (first == nullptr) //如果循环链表为空表
{
first = now;
first->next = now;
++length;
}
else
{
chainnode<T>* pp = first;
for (int i = 1; i < pos - 1 && pp; ++i)
pp = pp->next;
if (pp)
{
if (pos == 1)
{
now->next = first;
first->next = now;
first = now;
}
else
{
now->next = pp->next;
pp->next = now;
}
++length;
}
}
}
template<class T>
void chain<T>::insertafter(T dat, int pos)
{
if (pos < 0 || pos>length)
{
std::cout << "输入的位置数错误" << endl;
exit(1);
}
chainnode<T>* now = new chainnode < T >;
now->data = dat;
if (first == nullptr)
{
first = now;
first->next = now;
++length;
}
else
{
chainnode<T>* pp = first;
for (int i = 1; i < pos && pp; ++i)
pp = pp->next;
if (pp)
{
if (pos == length)
{
now->next = first;
pp->next = now;
}
else
{
now->next = pp->next;
pp->next = now;
}
++length;
}
}
}
template<class T>
T chain<T>::find(int pos)
{
if (first)
{
if (pos<0 || pos>length)
{
std::cout << "输入的位置数错误" << endl;
exit(1);
}
chainnode<T>* curr=first;
for (int i = 1; i < pos; ++i)
curr = curr->next;
return curr->data;
}
}
template<class T>
int chain<T>::getlength()
{
if (first == nullptr)
return 0;
chainnode<T>* current = first->next;
int len = 1;
while (current!=first)
{
++len;
current = current->next;
}
length = len;
return len;
}
template<class T>
void chain<T>::deletenode(int pos)
{
if (first)
{
if (pos<0)
{
std::cout << "输入的位置数错误" << endl;
exit(1);
}
chainnode<T>* temp = first;
if (pos == 1)
{
for (int i = 1; i < length && temp; ++i) //获得end元素的地址
temp = temp->next;
if (temp)
{
temp->next = first->next;
chainnode<T>* pp = first;
first = first->next;
std::cout << "删除的是:" << pp->getdata() << endl;
delete pp;
pp = nullptr;
--length;
}
}
else
{
for (int i = 1; i < pos-1 && temp; ++i) //获得pos-1元素的地址
temp = temp->next;
chainnode<T>* curr = temp->next; //curr是pos位置元素的地址
temp->next = curr->next;
std::cout << "删除的是:" << curr->getdata() << endl;
delete curr;
curr = nullptr;
--length;
}
}
}
template<class T>
void chain<T>::createchain(int n) //产生length为n的循环链表
{
std::cout << "请输入" << n << "个数据" << endl;
T dat;
int i = 0;
while (cin >> dat)
{
insertafter(dat, i++);
}
}
template<class T>
void chain<T>::joseph(int n, int s, int m) //n个人坐在圆桌,第s个人报数,报到第m个人出局,再循环直至所有人出局
{
createchain(n);//产生n个人
if (n < s)
{
cout << "error" << endl;
exit(1);
}
chainnode<T>* start = first;
for (int i = 1; i < s; ++i) //找到第s个人的地址
start = start->next;
first = start; //将整个链表成为以start为起始点的循环链表
chainnode<T>* temp1;
while (length)
{
for (int i = 1; i < m; ++i) //找到第m个人的地址
start = start->next;
//判断要删除的节点和first是什么关系
if ((start== first)&&(first!=first->next)) //要删除的点是头节点,且链表有多个节点
{
deletenode(1);
start = first;
}
else
{
if (start == start->next) //链表只剩下一个头节点
{
std::cout << "删除的是:" << start->getdata() << endl;
delete start;
start = nullptr;
--length;
}
else
{
temp1 = start->next;//保存新起点
deletenode(m); //第m个人出局
start = first = temp1; //设置新的起点
}
}
}
}
template<class T>
std::ostream& operator <<(std::ostream& out, chain<T>& list)
{
chainnode<T>* cc = list.getfirst();
for (int i = 1; i <= list.getlength(); ++i)
{
out <<cc->getdata() << " ";
cc = cc->getnext();
}
std::cout << std::endl;
return out;
}
#endif
2.main文件
#include<iostream>
#include"chain.h"
using namespace std;
int main()
{
chain<int> liner;
liner.joseph(10, 2, 5);
system("pause");
return 0;
}