zoukankan      html  css  js  c++  java
  • Josephus排列

    思考与分析:

               对于m为常数,能够用循环链表,用head,tail标志头尾指针使其易于表示循环结构。循环输出后删除结点n次,每次外层循环时。内层都固定循环m次。所以执行时间为O(mn)=O(n).

               对于m为很数。能够用顺序统计树,用size属性记录每一个结点在当前树中所在的位置。

    经过一个取余过程,每次都能正确找到并输出删除每一个结点,在经过n次循环,每次循环都要找到一个结点输出并删除它,所以每次循环都要花费O(lgn)时间。

    总的执行时间是O(nlgn).

    代码例如以下:

    m为常数时:

    #include <iostream>
    using namespace std;
    #define n 10
    #define m 3
    #define LEN sizeof(struct circular_list)
    struct circular_list
    {
       int key;
       struct circular_list* next;
    };
    struct circular_list*tail=NULL;
    struct circular_list*Insert(struct circular_list*&head,int k)
    {
    	struct circular_list*z=new struct circular_list[LEN];
    	z->key=k;
        if (head==NULL)
        {
    		head=tail=z;
    		head->next=tail;
        }
    	else
    	{
    		tail->next=z;
    		z->next=head;
    		tail=z;
    	}
    	return head;
    }
    struct circular_list* Delete(struct circular_list*&head,struct circular_list*z)
    {
       struct circular_list*p=head;
       while (p->next!=z)
       {
    	   p=p->next;
       }
       if (head==tail)
       {
    	   p->next=NULL;
       }
       else 
       {
    	   if (head==p->next)
    	   {
    	     head=p->next->next;
    	   }
    	   else if (tail==p->next)
    	   {
    		 tail=p;
    	   }
    	   p->next=p->next->next;
       }
       return p->next;
    }
    void n_m_Josephus(struct circular_list*&head)
    {
       struct circular_list*p=head;
       while (p)
       {
    	   int i=0;
    	   while (i!=m-1)
    	   {
    		   p=p->next;
    		   i++;
    	   }
    	   struct circular_list*z=p;
    	   cout<<z->key<<" ";
           p=Delete(head,z);
       }
    }
    void main()
    {
        int a[n]={0};
    	for (int i=0;i<n;i++)
    	{
    		a[i]=i+1;
    	}
    	int j=0;
    	struct circular_list*head=NULL;
        while (j!=n)
        {
    		head=Insert(head,a[j]);
    		j++;;
        }
        struct circular_list*p=head;
    	do 
    	{
    		cout<<p->key;
    		p=p->next;
    	} while (p!=head);
    	cout<<endl;
    	n_m_Josephus(head);
    }

    m不是常数时

    #include <iostream>
    #include <time.h>
    using namespace std;
    #define BLACK 0
    #define RED 1
    #define Nil -1
    #define LEN sizeof(struct OS_Tree)
    struct OS_Tree
    {
       struct OS_Tree*right,*left;
       struct OS_Tree*parent;
       int key,color,size;//size表示子树的结点数。

    }; struct OS_Tree*root=NULL,*nil=NULL; void LEFT_ROTATE(struct OS_Tree*x) {//左旋转:分三个步骤①②③来叙述旋转代码的。 struct OS_Tree*y=x->right;//设置y结点。

    x->right=y->left;//本行代码以及以下的if结构表达的是“y的左孩子成为x的右孩子”。① if(y->left!=nil) { y->left->parent=x; } y->parent=x->parent;//本行代码以及以下的if-else结构表达的过程是“y成为该子树新的根”。

    ② if(x->parent==nil) { root=y; } else if(x==x->parent->left) { x->parent->left=y; } else x->parent->right=y; y->left=x;//本行代码以及以下一行都表达了“x成为y的左孩子”。③ x->parent=y; y->size = x->size; //对附加信息的维护 x->size = x->left->size + x->right->size +1; } void RIGHT_ROTATE(struct OS_Tree*x) {//右旋转:分三个步骤①②③来叙述旋转代码的。

    struct OS_Tree*y=x->left;//设置y结点。 x->left=y->right;//本行代码以及以下的if结构表达的是“y的左孩子成为x的右孩子”。① if(y->right!=nil) { y->right->parent=x; } y->parent=x->parent;//本行代码以及以下的if-else结构表达的过程是“y成为该子树新的根”。② if(x->parent==nil) { root=y; } else if(x==x->parent->right) { x->parent->right=y; } else x->parent->left=y; y->right=x;//本行代码以及以下一行都表达了“x成为y的左孩子”。③ x->parent=y; y->size = x->size; //对附加信息的维护 x->size = x->left->size + x->right->size +1; } void RB_INSERT_FIXUP(struct OS_Tree*z) { while (z->parent->color==RED) { if (z->parent==z->parent->parent->left) { struct OS_Tree*y=z->parent->parent->right;//叔结点 if (y->color==RED)//情况一:叔结点为红色 {//给p1,y,p2着色以保持性质5。而且攻克了z的父结点和z都是红色结点问题 z->parent->color=BLACK; y->color=BLACK; z->parent->parent->color=RED; z=z->parent->parent;//把z的祖父结点当成新结点z进入下一次循环 } else { if (z==z->parent->right)//情况二:检查z是否是一个右孩子且叔结点为黑色。前提是p1结点不是叶子结点 {//使用一个左旋让情况2转变为情况3 z=z->parent; LEFT_ROTATE(z);//因为进入if语句后可知旋转结点不可能是叶子结点,这样就不用推断z是否是叶子结点了。 } z->parent->color=BLACK;//情况三:是z是一个左孩子且叔结点为黑色。改变z的父和祖父结点颜色并做一次右旋,以保持性质5 z->parent->parent->color=RED; RIGHT_ROTATE(z->parent->parent);//因为p2可能是叶子结点,所以不妨用一个if推断 } } else//以下else分支相似于上面,注意到else分支的情况2和情况3所做旋转正好是if分支情况的逆。 { struct OS_Tree*y=z->parent->parent->left; if (y->color==RED) { z->parent->color=BLACK; y->color=BLACK; z->parent->parent->color=RED; z=z->parent->parent; } else { if (z==z->parent->left) { z=z->parent; RIGHT_ROTATE(z); } z->parent->color=BLACK; z->parent->parent->color=RED; LEFT_ROTATE(z->parent->parent); } } } root->color=BLACK;//最后给根结点着为黑色。

    } void RB_INSERT(struct OS_Tree*z) { struct OS_Tree*y=nil; struct OS_Tree*x=root; while (x!=nil) { x->size++; y=x; if (z->key<x->key) { x=x->left; } else x=x->right; } z->parent=y; if (y==nil) { root=z; } else if(z->key<y->key) { y->left=z; } else y->right=z; z->left=nil;//给插入结点左右孩子赋值为空。 z->right=nil; z->color=RED;//给插入结点着为红色。 z->size=1; z->left->size=0; z->right->size=0; RB_INSERT_FIXUP(z); } void RB_TRANSPLANT(struct OS_Tree*u,struct OS_Tree*v) { if (u->parent==nil) root=v; else if(u==u->parent->left) u->parent->left=v; else u->parent->right=v; v->parent=u->parent; } struct OS_Tree*TREE_MINIMUM(struct OS_Tree*x)//求二叉查找树当前结点最小值 { while (x!=nil&&x->left!=nil) { x=x->left; } return x; } struct OS_Tree*TREE_MAXINUM(struct OS_Tree*x)//求二叉查找树当前结点最大值 { while (x!=nil&&x->right!=nil) { x=x->right; } return x; } struct OS_Tree*TREE_PREDECESSOR(struct OS_Tree*x)//查找二叉查找树的前驱 { if (x->left!=nil) { return TREE_MAXINUM(x->left); } struct OS_Tree*y=x->parent; while (y!=nil&&x==y->left) { x=y; y=y->parent; } return y; } struct OS_Tree*TREE_SUCCESSOR(struct OS_Tree*x)//查找二叉查找树的后继 { if (x->right!=nil) { return TREE_MINIMUM(x->right); } struct OS_Tree*y=x->parent; while (y!=nil&&x==y->right) { x=y; y=y->parent; } return y; } //非递归版本号的二叉查找树查找函数 struct OS_Tree*ITERATIVE_TREE_SEARCH(struct OS_Tree*x,int k) { while (x!=nil&&k!=x->key) { if (k<x->key) { x=x->left; } else x=x->right; } return x; } void RB_DELETE_FIXUP(struct OS_Tree*x) { struct OS_Tree*w=NULL;//w是x的兄弟结点 while (x!=root&&x->color==BLACK)//假设x是黑色而且不是根结点,才进行循环。 {//x是一个具有双重颜色的结点,调整的目的是把x的黑色属性向上移动。

    if (x==x->parent->left) { w=x->parent->right; if (w->color==RED)//情况一:x的兄弟结点w是红色的。

    {//改变w和x.p的颜色+一次旋转使其变为情况二,三,四。 w->color=BLACK; x->parent->color=RED; LEFT_ROTATE(x->parent); w=x->parent->right; } if (w->left->color==BLACK&&w->right->color==BLACK)//情况二:x的兄弟结点w是黑色的,而且w的两个子节点都是黑色。 { w->color=RED;//从x和w上去掉一重黑色。x还是黑色。而w变为红色。 x=x->parent;//x结点向上移动成为新的待调整结点。

    } else { if (w->right->color==BLACK)//情况三:x的兄弟结点w是黑色的。w的左孩子是红色的,w的右孩子是黑色的。 {//交换w和w.left的颜色+旋转使其转变为情况四。 w->left->color=BLACK; w->color=RED; RIGHT_ROTATE(w); w=x->parent->right; } w->color=x->parent->color;//以下是情况四:x的兄弟结点w是黑色的,且w的右孩子是红色的。 x->parent->color=BLACK;//置x.p和w.right为黑色+旋转使其去掉x的额外黑色。 w->right->color=BLACK; LEFT_ROTATE(x->parent); x=root;//x成为根结点,结束循环。 } } else//以下和上面的if分支相似。不做累述。 { w=x->parent->left; if (w->color==RED) { w->color=BLACK; x->parent->color=RED; RIGHT_ROTATE(x->parent); w=x->parent->left; } if (w->left->color==BLACK&&w->right->color==BLACK) { w->color=RED; x=x->parent; } else { if (w->left->color==BLACK) { w->right->color=BLACK; w->color=RED; LEFT_ROTATE(w); w=x->parent->left; } w->color=x->parent->color; x->parent->color=BLACK; w->left->color=BLACK; RIGHT_ROTATE(x->parent); x=root; } } }x->color=BLACK; } void RB_DELETE(struct OS_Tree*z) { struct OS_Tree*y=z,*x;//y为待删除或待移动结点 int y_original_color=y->color;//保存y的原始颜色,为做最后的调整做准备。 struct OS_Tree*t=z->parent; if (z->left==nil) { while (t!=nil) { t->size--; t=t->parent; } x=z->right;//x指向y的唯一子结点或者是叶子结点,保存x的踪迹使其移动到y的原始位置上 RB_TRANSPLANT(z,z->right);//把以z.right为根的子树替换以z为根的子树。 } else if (z->right==nil) { while (t!=nil) { t->size--; t=t->parent; } x=z->left;//x指向y的唯一子结点或者是叶子结点。保存x的踪迹使其移动到y的原始位置上 RB_TRANSPLANT(z,z->left);//把以z.left为根的子树替换以z为根的子树。

    } else { y=TREE_MINIMUM(z->right);//找到z.right的后继。

    struct OS_Tree*t=y->parent; y->size=z->size-1;//y替换z原来的位置,所以size属性在待删除结点z基础上-1 while (t!=nil) { t->size--; t=t->parent; } y_original_color=y->color;//y的新的原始结点被重置。 x=y->right;//x指向y的唯一子结点或者是叶子结点。保存x的踪迹使其移动到y的原始位置上 if (y->parent==z) { x->parent=y;//因为z的父结点是要删除的结点,所以不能指向它,于是指向y } else { RB_TRANSPLANT(y,y->right);//把以y.right为根的子树替换以y为根的子树。

    y->right=z->right; y->right->parent=y; } RB_TRANSPLANT(z,y);//把以y为根的子树替换以z为根的子树。 y->left=z->left; y->left->parent=y; y->color=z->color;//把已经删除的结点颜色赋值给y。保证了y以上的树结构红黑性质不变。 } if(y_original_color==BLACK) //y的原始颜色为黑色,说明须要调整红黑颜色。 RB_DELETE_FIXUP(x); } //中序遍历 void InOderTraverse(struct OS_Tree *p) { if (p!=nil) { InOderTraverse(p->left); cout<<p->key<<" "<<p->color<<" "<<"秩:"<<p->size<<endl; InOderTraverse(p->right); } } struct OS_Tree*OS_SELECT(struct OS_Tree*&x,int i)//查找顺序统计树给定秩的元素 { int r=x->left->size+1; if (i==r) { return x; } else if (i<r) { return OS_SELECT(x->left,i); } else return OS_SELECT(x->right,i-r); } int ITERATIVE_OS_RANK(struct OS_Tree*&T,struct OS_Tree*x)//确定顺序统计树的秩 { int r=x->left->size+1; struct OS_Tree*y=x; while (y!=root) { if (y==y->parent->right) { r=r+y->parent->left->size+1; } y=y->parent; } return r; } void n_m_Josephus(struct OS_Tree*x,int m,int n) { x=root; int j=0,i=n,t=1; while(root!=nil) { j=(t+m-1)%i; if(j==0) j=i; struct OS_Tree*y1=OS_SELECT(root,j);//y1表示待输出待删除结点 cout<<y1->key<<" ";//输出结点 RB_DELETE(y1);//输出后删除掉 t=j; i--; } } void main() { srand( (unsigned)time( NULL ) ); int m=0,n=0; cout<<"以下请您输入n_m_Josephus排列的m和n值"<<endl; cout<<"m="; cin>>m; cout<<"n="; cin>>n; int *array1=new int[n]; for (int j=0;j<n;j++) { array1[j]=j+1; cout<<array1[j]<<" "; } cout<<endl; nil=new struct OS_Tree[LEN]; nil->key=Nil;nil->color=BLACK; root=nil; int i=0; struct OS_Tree*ROOT=new struct OS_Tree[LEN]; ROOT->key=array1[i++]; RB_INSERT(ROOT); root=ROOT; while (i!=n) { struct OS_Tree*z=new struct OS_Tree[LEN]; z->key=array1[i]; RB_INSERT(z); i++; } InOderTraverse(root); cout<<"约瑟夫排列:"; n_m_Josephus(root,m,n); }

    总结:约瑟夫排列a部分用到了第10章知识,而b部分用到了本章知识。这是对学过的知识的简单应用。感觉这个程序还是比較有趣的。

  • 相关阅读:
    《激荡三十年》十七、国有企业改革(下)——“国退民进”
    《激荡三十年》十六、国有企业改革(中)——“抓大放小”
    《激荡三十年》十五、国有企业改革(上)——产权改革的曙光
    《激荡三十年》十四、改革深水区——整体配套体制改革
    《激荡三十年》十三、治国能臣——铁腕总理立威
    《激荡三十年》十二、中外合资——上海市长与上海大众
    《激荡三十年》十一、邓公南巡,中国再起航
    boost之thread
    七夕
    boost之mutex scoped_lock
  • 原文地址:https://www.cnblogs.com/lytwajue/p/7280456.html
Copyright © 2011-2022 走看看