單循環鏈表的約瑟夫問題(C++)

在解決約瑟夫問題上,利用無表頭的單循環鏈表是相當簡單的,可以將約瑟夫問題當作鏈表的刪去節點操作。

約瑟夫問題:已知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;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章