一、循环链表 Circular List
将单向链表的头节点与尾节点相连便构成了一个循环链表。其生成与单向链表类似,仅仅多了首尾相连这一步。
Jose *head,*tail ;
void creatList (int n)
{
//创建头节点
head = new Jose ;
head->next = NULL;
head->code = 1 ;
//在头节点后插入后续节点
Jose *current = head;
for(int i=2 ; i<=n ;i++)
{
Jose *p = new Jose ;
p->code = i ;
current->next = p ;
current = current->next ;
}
//储存尾节点
tail = current ;
//连接首尾节点
current->next = head ;
}
二、约瑟夫环问题
问题:
一共有n个人围成一个圈,并设定一个淘汰的数字m。然后从第一个人从1开始报数,每个报m的人都将被淘汰,然后下一人重新从1开始报数,直到只剩下一个人为止。
在创建好循环链表之后,这道题便变成了将每个报m的节点删去,直到只剩一个节点。
于是只需要使用循环遍历链表并从1开始计数,当到m时删除此处节点便完成了约瑟夫环问题。
Jose *fakehead = new Jose ;
fakehead->next = head ;
Jose *current = fakehead ;
//Jose *current = tail ;
//用头节点开始遍历较为复杂,可从尾节点开始遍历或者新建一个虚假的头节点
while(current->next != current )
{
for(int i=0 ; i<m-1; i++ )
{
current=current->next ;
}
//报数到m,删除此处节点
Jose *temp =current->next ;
current->next = current->next->next ;
delete temp ;
}
cout<<current->code<<endl;
delete current ;
delete fakehead ;
但这种做法有个问题:当节点个数很大时,依次遍历的时间较长,很有可能超出运行要求时间,可通过算法进行简化。预知后事如何,且听下回分解……