循环链表版本-----约瑟夫环
其实就是单链表的首位相连,不过需要注意的是链表需要注意这个头插法的尾节点应该插在第二个
然后需要注意的是,在删除的时候,我一般是用前后两节点进行扫描,然后前面那个一旦符合我要删除的条件,那么我就把后面那个指向前面那个的下一个。然后把前面的那个地址释放掉,然后用后一个指向的地址给前一个就实现了移动。
如图
链表版本的约瑟夫便是如此:利用上面两个操作直到最后一个节点自己指向自己,那么就表示,只剩下一个人了。
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; typedef struct Lnode { int data; Lnode *next; } Lnode,*linklist; int main() { int n; int tmp,t; linklist a,p,q; scanf("%d",&t); while(t--) { scanf("%d",&n); a=(linklist)malloc(sizeof(Lnode)); p=a; for (int i=1; i<=n; i++) { q=(linklist)malloc(sizeof(Lnode)); q->data=i;//给每个位置编号 p->next=q; p=q; } p->next=a->next;//由于是头插法,需要把尾指针指向头结点的下一个节点(头插法,那么头结点其实是空节点仅仅是用来访问的) q=p;//这个首先应该是最后一个节点,一定注意不是第一个头节点,头插法的第一个节点是没有值的 p=a->next; int cnt=0; int k=1; while(p->next!=p)//当只剩下一个的时候退出 { cnt=(cnt+1); if (cnt%k==0)//叫到k号人出队 { cnt=0; q->next=p->next; free(p); p=q->next; k++; } else { p=p->next;//移动 q=q->next; } } printf("%d\n",q->data); } return 0; } /* 6 1 3 6 4 5 1 */
有不懂欢迎咨询
QQ:1326487164(添加时记得备注)