17、循环链表(解决约瑟夫问题)
1、定义链表
typedef struct _LinkNode {
int data;
struct _LinkNode *next;
}LinkNode,LinkList;
2、初始化链表
bool ListInsert_back(linkList* &L,LinkNode *node){
LinkNode *last = NULL;
//防御性编程
if(!L || !node) return false; //节点和L不能为空
if(L == L->next ){
node->next = L;
L->next = node;
}else{
last = L->next;
while(last->next != L) last = last->next;//定位尾结点
}
node->next = L;
last->next = node;
return true;
}
3、打印链表
void LinkPrint(LinkList* &L){
LinkList *p;
if(!L || L==L->next){
cout<<"链表为空!"<<endl;
return;
}
p=L->next;
while(p!=L){
cout<<p->data<<"\t";
p=p->next;
}
cout<<endl;
}
4、解决约瑟夫问题
bool Joseph(LinkList* &L,int go){ //go 是出列的数字,比如喊道3出列,go=3
LinkList *p,*q; //p 用来追踪当前节点,而 q 指向即将被删除的节点
int i=0,j=0; // i 表示当前应该淘汰的人的编号,j 是一个计数器,用于跟踪当前遍历到了哪个人。
int times=0,num=0;//times 记录了已经淘汰了几个人就是循环了几轮(1轮出去一个人),num 存储即将被淘汰人的数据值
p=L;
if(!L||p->next==L){
cout<<"链表为空"<<endl;
return false;
}
if(go<1){
cout<<"出列口令不能小于1!"<<endl;
return false;
}
do{
i+=go;
while(p->next){
if(p->next!=L)j++;//计数器加一
if(j>=i)break;//说明结束了一轮,要进行下一轮循环
p=p->next;
}
timer++;
q = p->next;//临时保存被删结点的地址以备释放空间
num=q->data;
if(timer==3)cout<<"第三个出圈的编号是"<<num<<endl;
p = q->next;//p=p->next->next 删除出列的结点
delete q;
LinkPrint(L);
}while(p->next!=L)
cout<<"最后一个出圈的是"<<num<<endl;
}
5、主函数
int main(void){
LinkList *L,*s;
int i= 0 ;
if(InitList(L)){
cout<<"成功初始化一个空的循环链表!"<<endl;
}else{
exut(-1);
}
cout<<"插入10个元素"<<endl;
while((++i)<10){
s = new LinkNode;//生成新的结点
s->data = i;
s->node = NULL;
if(ListInsert_back(L,s)){
cout << "插入成功!" << endl;
}
else {
cout << "插入失败!" << endl;
}
}
cout << "尾插法创建循环链表输出结果:\n";
LinkPrint(L);
Joseph(L, 5);
system("pause");
return 0;
}