有一个问题是这样:0,1,···,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第3个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3.
思路:首先建立一个循环链表,在对链表不断进行遍历的时候用一个flag变量作为标志位,当遍历第遍历到第二个数时就删除下一个数,也就是第三个数,再将flag置为0,直到链表中只剩一个节点时,取它的数据域即可。
话不多说,上代码:
typedef int data_t;
typedef struct yuesefu //先定义结构体a
{
data_t data;
struct yuesefu *next;
}*circle;
int main(int argc, char *argv[])
{
int n,a,len=0,flag=1; //变量依次代表 输入的数字个数,输入的数字,链表长度,标志位
circle head,p,r; //p,r作为辅助指针
head=(circle)malloc(sizeof(data_t)); //创建头节点
p=head;
scanf("%d",&n);
while(n--) //循环用于给新节点数据域赋值
{
scanf("%d",&a);
circle q=(circle)malloc(sizeof(data_t));
q->data=a;
p->next=q;
p=q;
len++;
}
p->next=head->next; //将尾节点连接到首节点(首节点不是头节点,一般是头节点的下一个节点)
p=head->next;
r=p;
free(head); //释放头节点,使链表成为一个循环链表
while(len!=1)
{
if(flag==2)
{
r=p->next; //当计数到2时,将指针r指向p的下一个节点,也就是计数为3的节点
printf("%d ",r->data);
p->next=r->next; //将p指向r的下一个节点,也就是删除r节点
free(r); //释放r所指空间内存
flag=0; //标志位清零
len--; //链表长度减1
}
p=p->next; //继续从新的节点开始计数
flag++;
}
putchar('\n');
printf("最后剩余的元素为:%d\n",p->data);
return 0;
}
需要注意的一点是在对标志位赋初值和重置标志位的时候对应的数值,我们通常开始计数时从1开始,所以标志位初值应赋值为1,而在重置标志位时可以理解为将需要删除的节点标记为0,那么从下一个新节点开始就是从1开始计数