单循环链表的约瑟夫问题(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;
}



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