单向循环链表实现约瑟夫环(c++)(数据结构)

一、问题重述:  

        n 个人围成一个圆圈,首先第 1 个人从 1 开始,一个人一个人顺时针报数,  报到第 m 个人,令其出列。然后再从下一 个人开始,从 1 顺时针报数,报到第 m 个人,再令其出列,…,如此下去,  直到圆圈中只剩一个人为止。此人即为优胜者,请输出优胜者。

二、实现思路:

        将结点的数据域存储元素的序号,通过链表的遍历、元素的查询(search)、元素的删除(remove)等方法便可以较容易实现。

三、下面是具体代码实现思路:

        首先是单向循环链表的实现:

enum InsMod {INF, INR};//头插还是尾插
template <typename T>class CircLinkNode{
public:
	T data;
	CircLinkNode<T> *link;
	CircLinkNode(CircLinkNode<T> *ptr = NULL){//建立空结点
		link = ptr;
	}
	CircLinkNode(const T &item, CircLinkNode<T> *ptr = NULL){//建立非空结点
		data = item;
		link = ptr;
	}
};

template <typename T>class CircList{
public:
	CircList()
	{
	    this->first = new CircLinkNode<T>();
	    first->link=first;

        last=first;
	}
	CircList(CircList<T> &L)//复制一个环链表
	{
	    CircLinkNode<T>* p = L.first->link;
	    CircLinkNode<T>*q = this->first->link;
	    while(p!=first)
        {
            q= new CircLinkNode<T>(p->data);
            q=q->link;
            p=p->link;
        }
        last = q;
	}
	~CircList()
	{
	    this->makeEmpty();
	    delete this->first;
	}
	void makeEmpty()
	{
	    CircLinkNode<T>*p = this->first->link;
	    CircLinkNode<T>*q = p->link;
	    while(p!=first)
        {
            delete p;
            p = q;
            q=q->link;
        }
	}
	int Length()const
	{
	    int num =1;
	    CircLinkNode<T>* p = first->link;

	    while(p!=first)
        {
            ++num;
            p=p->link;
        }
        return num;
	}
	CircLinkNode<T> *Search(T& x,int &n)
	{
	    CircLinkNode<T>* p = first->link;
         n=1;
	    while(p->data!=x)
        {
            ++n;
            p=p->link;
            if(p==first)
                exit(1);
        }
        return p;
	}
	CircLinkNode<T> *Locate(int i)
	{
	    if(i<1||i>Length())
        {
            exit(1);
        }
        int num=0;
        CircLinkNode<T>*p = first->link;
        while(p!=first)
        {
            ++num;
            if(num==i)
                return p;
            p=p->link;
        }
        return p;
	}

	bool getData(int i,T&x)const
	{
	    if(i<1||i>Length())
        {
            return false;
        }
        int num=1;
        CircLinkNode<T>*p = first->link;
        while(p!=first)
        {
            ++num;
            if(num==i)
                x = p->data;
            p=p->link;
        }
        return true;
	}
	void setData(int i, T &x)
	{
	    if(i<1||i>Length())
        {
            return;
        }
        int num=0;
        CircLinkNode<T>*p = first->link;
        while(p!=first)
        {
            ++num;
            if(num==i)
            p->data=x;
            p=p->link;
        }
	}
	bool Insert(int i, T &x)
	{
        if(i<1||i>Length()+1)
        {
            return false;
        }
        CircLinkNode<T>* p =NULL;
        if(i==1)
            p = first;
        else
	     p = Locate(i-1);

	    CircLinkNode<T>* q = p->link;

	    CircLinkNode<T> *newNode = new CircLinkNode<T>(x);

	    p->link = newNode;

	    newNode->link = q;
        if(i==Length()+1)
        {
        last = newNode;
        }
	    return true;

	}
	bool Remove(int i, T &x)
	{
        if(i<=0||i>Length())
        {
            return false;
        }
        int j=0;
        CircLinkNode<T>* p = first;
        for(j=1; j<i; j++)
        {
            p=p->link;
        }
        CircLinkNode<T> *q = p->link->link;
        x = p->link->data;
        if(i==Length())
            last = p;
        delete p->link;
        p->link = q;
        return true;
	}
	bool IsEmpty()const
	{
	    return first->link==last;
	}
	bool IsFull()const
	{
	    return (new CircLinkNode<T>() )==NULL;
	}
	void Sort()
	{
        CircLinkNode<T> * p =first->link;
        CircLinkNode<T> *q=NULL;
        if(NULL==p)
            return ;

        int num = this->Length();
        int maxIndex=1;

        int Max =p->data;
        for(int i=1; i<num; i++)
        {
            int j=1;
            for(; j<num-i+2; j++)
            {
               if(Max<=p->data)
               {
                   maxIndex = j;
                   Max = p->data;
               }
               q=p;
                p=p->link;
            }

            setData(maxIndex,q->data);
            setData(num,Max);
        }
	}
	void Inverse()//不要返回
	{
        int num = this->Length();
        for(int i=1; i<num/2+1; i++)
        {
            int j=num-i+1;
            CircLinkNode<T> * p = Locate(i);
            CircLinkNode<T>* q = Locate(j);

            T temp = p->data;
            p->data = q->data;
            q->data = temp;
        }
	}
	void input(T endTag, InsMod im = INR)
	{
	    if(im==INR)
        {
        Insert(Length()+1,endTag);
        }
        else{
        Insert(1,endTag);
        }
	}
	void output()
	{
	    CircLinkNode<T>* p =first->link;

	    while(p!=first)
        {
          cout<<p->data<<" ";

          p=p->link;
        }
        cout<<endl;
	}
	CircList<T> &operator = (CircList<T> &L)
	{
	    this->makeEmpty();

    CircLinkNode<T>* q =  L.first->link;
    while(q!=L.first)
    {
        input(q->data,INR);
        q=q->link;
    }

	}
 CircLinkNode<T>* travel(int x,CircLinkNode<T>*temp)
	{
	    CircLinkNode<T>* pre = temp;
	    for(int i=1;i<x;i++)
        {

            if(pre==first)
                --i;
             pre=pre->link;
        }
        if(pre==first)
            pre=pre->link;
        return pre;
	}
	int getNum(CircLinkNode<T>* temp)
	{
	    CircLinkNode<T>*pre = first->link;
	    int num=1;
	    while(pre!=temp)
        {
            if(pre!=first)
            ++num;
            pre=pre->link;
        }
        return num;
	}
	friend ostream& operator << (ostream &out, CircList<T> &L){
		CircLinkNode<T> *current = L.first->link;
		while (current != L.first){
			out << current->data <<'\t';
			current = current->link;
		}
		out<<endl;
		return out;
	}
	friend istream& operator >> (istream &in, CircList<T> &L){//重新输入数据,向后生成
		T val;
		L.makeEmpty();//先清空
		while (!in.eof()){
			in >> val;
			L.last->link = new CircLinkNode<T>(val);
			assert(L.last->link);
			L.last = L.last->link;
		}
		L.last->link = L.first;
		in.clear();//当以ctrl_Z结束,流关闭,必须重新打开
		return in;
	}
	CircLinkNode<T>* getFirst()
	{
	    return first;
	}
protected:
	CircLinkNode<T> *first, *last;
	void inputFront(T endTag);
	void inputRear(T endTag);
};

        根据约瑟夫环的要求,在链表类内加入travel()方法返回每次遍历要出列的人。由于笔者采用的是带头结点的链表,在遍历时必然会遇到空头节点,此时让迭代次数减一以保证遍历的正确。

 CircLinkNode<T>* travel(int x,CircLinkNode<T>*temp)
{
	    CircLinkNode<T>* pre = temp;
	    for(int i=1;i<x;i++)
        {

            if(pre==first)
                --i;
             pre=pre->link;
        }
        if(pre==first)
            pre=pre->link;
        return pre;
}

        在链表类内加入getNum()实现每次循环后,得到要查询结点此时在链表里的相对序号。

	int getNum(CircLinkNode<T>* temp)
	{
	    CircLinkNode<T>*pre = first->link;
	    int num=1;
	    while(pre!=temp)
        {
            if(pre!=first)
            ++num;
            pre=pre->link;
        }
        return num;
	}

在main函数里具体实现如下:

int main(){
	CircList<int> List;
	int x=0;
 for(int i=0;i<10;i++)//假设约瑟夫环最初有十人,序号为从1到10
 {
     x=i+1;
     List.Insert(i+1,x);
 }

CircLinkNode<int>* pre = List.getFirst()->link;//初始从序号为1的人开始循环
CircLinkNode<int>*  prev =pre;//中间指针,便于pre结点删除后能够赋值给pre继续循环
while(List.Length()!=1)
{

   pre= List.travel(3,pre);//循环设为3
   prev = pre;
   pre=pre->link;
   List.Remove(List.getNum(prev),x);
   cout<<"出列的人为:"<<x<<endl;

}
List.getData(1,x);
cout<<"ViCTOR is :"<<x<<endl;
	return 0;
}

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东北大马猴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值