Josephu 问题为:设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
一种最通常的想法是弄个数组,将每一个位置的值都初始化为1,然后进行遍历,数到m时,将其置为0。遇到为0的就跳过继续向下,到最后一个就循环回来。直到只剩一个元素为止。
数组的实现方法:
#include <stdio.h> #include <malloc.h> #define n 1000000 #define m 4 int main() { int flag, i, j = 0; int k=0; int list[n]; int arr[n]; for (i = 0; i < n; i++){ arr[i] = 1; } for (i = 1; i < n; i++) { flag = 0; while (flag < m) { if (j == n) j = 0; //到了末尾就循环 if (arr[j]){ //当为1时记录经过的个数,0时跳过 flag++; } j++; } arr[j - 1] = 0; //删除出队的数据 list[k] = j; //将数据存入结果数组中 k++; } list[k]=j-1; //存入最后一个数 /* for(i=0;i<n;i++){ printf(" %d ",list[i]); } */ printf("\n"); }
当数据为1000000时,Fedora 测试时间为real 0m0.270s
或者采用循环链表,即数到了就删除一个节点。直到只剩一个节点为止。虽然指针的操作比数组要慢,但是随着程序的循环进行,链表中的元素越来越少,遍历的数据量也就相应的减少了。
链表实现方法:
#include<stdio.h> #include<stdlib.h> #define N 1000000 #define M 4 typedef struct node{ int id; struct node* next; }node; int main(){ int i=1; node *pre=NULL; node *head; int list[N]; for(i;i<=N;i++){ //队列的初始化 node *n=(node*)malloc(sizeof(node)); n->id=i; if(pre){ pre->next=n; }else{ head=n; //第一个元素 } pre=n; } pre->next = head; //循环队列 int j=0; node *p=head; node *q=p; while(p->next != p){ for(i=1;i<M;i++){ //向后数M个 q=p; p=p->next; } q->next = p->next; //删除节点 list[j]=p->id; //记录结果 j++; free(p); p=q->next; //找回P的位置 } list[j]=p->id; //最后一个数据 /* for(j=0;j<N;j++){ printf(" %d ",list[j]); } */ printf("\n"); }
非常巧的是,这种算法在数据达到100万的时候正好与数组的算法效率相当。Fedora测试耗时real 0m0.276s
这里要介绍的一种优化了的方法,既能达到数组的访问速度,又能像链表一样有选择性的遍历。
大体的逻辑是这样的:要想要数组的访问速度,存储结构必然是数组。链表的特性是存储了下一个数据的指针。所以就想到在数组中存储下一个数据的位置。访问时,数组中的内容作为下一个数据的地址。想要修改“链表”的格式,只修改数据内容就行了。这就实现了跳跃有选择的访问。
#include<stdio.h> #include<stdlib.h> #define N 1000000 #define M 4 int main(){ int a[N]; int i,j=0,k=0; int list[N]; for(i=0;i<N;i++){ a[i]=i+1; //每一个位置的内容是下一个位置 } a[9]=0; //最后一个要指回来 while(j != a[j]){ //位置和内容一致了就是剩下最后一个了 for(i=1;i<M;i++){ j=a[j]; //通过访问数组值的方式访问数组 } list[k]=a[j]; //记录数据 k++; a[j]=a[a[j]]; //相当于循环队列中的删除节点 } list[k]=a[j]; //记录最后一个 /* for(i=0;i<N;i++){ if(list[i] == 0){ list[i]=N; //因为是循环的所以最后一个数据为N,而不是地址0 } printf(" %d ",list[i]); } */ printf("\n"); }
应用这种数据结构,程序的访问速度就快的多了。当数据为100万时,测试耗时仅:real 0m0.026s 与前两种方法差出几乎十倍!
本篇博客出自 阿修罗道,转载请注明出处:http://blog.csdn.net/fansongy/article/details/6882586