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

一、问题重述:  

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

二、实现思路:

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

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

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

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

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

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

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

	    CircLinkNode* q = p->link;

	    CircLinkNode *newNode = new CircLinkNode(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* p = first;
        for(j=1; jlink;
        }
        CircLinkNode *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() )==NULL;
	}
	void Sort()
	{
        CircLinkNode * p =first->link;
        CircLinkNode *q=NULL;
        if(NULL==p)
            return ;

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

        int Max =p->data;
        for(int i=1; idata)
               {
                   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 * p = Locate(i);
            CircLinkNode* 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* p =first->link;

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

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

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

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

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

 CircLinkNode* travel(int x,CircLinkNode*temp)
{
	    CircLinkNode* pre = temp;
	    for(int i=1;ilink;
        }
        if(pre==first)
            pre=pre->link;
        return pre;
}

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

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

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

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

CircLinkNode* pre = List.getFirst()->link;//初始从序号为1的人开始循环
CircLinkNode*  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<<"出列的人为:"<

你可能感兴趣的:(数据结构,链表,c++)