在解決約瑟夫問題上,利用無表頭的單循環鏈表是相當簡單的,可以將約瑟夫問題當作鏈表的刪去節點操作。
約瑟夫問題:已知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;
}