有一个单向循环链表,从头开始报数,报到m或者m的倍数的元素出队。根据出队的先后顺序再组成一个单向循环链表。
函数的原型:void reorder(Node **head,int m);
个人以为,这题目是约瑟夫环的变种。
方法就是沿循环链表依次报数,报到编号能被m整除的,就把这个节点从原链表中删除,链接到新的链表中去。
循环终止的条件,就是只剩下最后一个节点,即:p->next == p
#include "stdafx.h"
#include<iostream>
#include<algorithm>
#include<windows.h>
using namespace std;
typedef struct node{
int data;
struct node *next;
}Node,*List;
List createListWithOutHead(int n)//创建不带头结点的循环链表
{
if(n==0)
return NULL;
List head = (List)malloc(sizeof(Node));
head->data = 1;
head->next = NULL;
List p = head;
List q =NULL;
for(int i=2;i<=n;i++)
{
q = (List)malloc(sizeof(Node));
q->data = i;
q->next = NULL;
p->next = q;
p = q;
}
p->next = head;//最后一个指针指向第一个节点
return head;
}
/*
head是原链表,N是链表的长度,报到m的倍数的节点,就从原链表中删除,加入到新的循环队列中
*/
void reorder(Node **head,int m)
{
Node *p,*pre,*tail;//pre和p是遍历原链表用的,tail则是新的循环链表的末尾指针
pre = p = *head;
Node *newHead = (Node *)malloc(sizeof(Node));
newHead->next = NULL;
tail = newHead;
int count = 1;
while(p->next!=p)//循环终止的条件:只剩下唯一一个节点,自己指向自己
{
count++;
pre = p;
p = p->next;
if(count%m == 0)
{
//cout<<p->data<<" ";
//Sleep(1000);
pre->next = p->next;//将p节点从原链表中删除
tail->next = p;//把p节点接到新链表尾部
tail = p;//现在p变成新链表的尾节点了
tail->next = newHead->next;//尾指针回指头部,构成循环结构
p = pre->next;//p指向下一个可遍历的节点
count++;//计数+1
}
}
//处理剩下的唯一一个元素
//cout<<p->data<<" ";
tail->next = p;
tail = p;
tail->next = newHead->next;
*head = newHead->next;
}
void traverseWithOutHead(List head)//遍历不带头结点的循环链表
{
if(head == NULL)
return ;
List p = head;
do{
cout<<p->data<<" ";
p = p->next;
}while(p!=head);
cout<<endl;
}
int main()
{
int N = 20,m=3;//长度为20的循环链表,报数的时候,报道3的倍数的节点出队,并加入新链表当中
List head = createListWithOutHead(N);
traverseWithOutHead(head);
reorder(&head,3);
traverseWithOutHead(head);
getchar();
return 0;
}