约瑟夫问题
约瑟夫问题:已知n个人(以编号 1 , 2 ,3…n分别表示)围坐在一张圆桌周围,从编号为k的人开始报数,数到m的那个人出列(元素删除),它的下一个人又从 1 开始报数,数到m的那个人又出列,依此规律重复下去,直到圆桌周围的人全部出列,输出人的出列顺序。
struct Node
{
Node(int data = 0) :data_(data), next_(nullptr) {}
int data_;
Node *next_;
};
// 不带头节点的单循环链表
void Joseph(Node *head,int k,int m)
{
Node *p = head;
Node *q = head;
//起始时候,q指向了next
while (q->next_ != head)
{
q = q->next_;
}
// 从第K个人开始报数// p-> 第k个人之后
for (size_t i = 1; i < k; i++)
{
q = p;
p = p->next_;
}
// 开始删除
while (true)
{
for (size_t i = 1; i < m; i++)
{
q = p;
p = p->next_;
}
// 删除p指向的节点
cout << p->data_ << endl;
if (p == q)
{
delete p;
break;
}
q->next_ = p->next_;
delete p;
p = q->next_;
}
}
int main()
{
Node *head = new Node(1);
Node *n2 = new Node(2);
Node *n3 = new Node(3);
Node *n4 = new Node(4);
Node *n5 = new Node(5);
Node *n6 = new Node(6);
Node *n7 = new Node(7);
Node *n8 = new Node(8);
head->next_ = n2;
n2->next_ = n3;
n3->next_ = n4;
n4->next_ = n5;
n5->next_ = n6;
n6->next_ = n7;
n7->next_ = n8;
n8->next_ = head;
Joseph(head, 1, 1);
}
和上边步骤好像有点不一样,这个为准。
总结:注意临界条件的判断
因为这是一个不带头的单项循环链表,如果直接判断最后一个节点的条件:p==q时候,如果直接写成这样,将出现错误。因为如果从第一个节点开始,每次从1开始,起始时候这个条件就成立。因此,这里需要提前做判断,如果让q 指向 p 的前一个节点,加上如下代码:其实时候,让p指向第一个节点,q指向最后一个节点。