循环链表 +(约瑟夫环)

循环链表,顾名思义,循环的单链表,所以和单链表的区别也就是尾指针不再指向空,而是指向头节点,所以将首尾连接在了一起。

循环链表 +(约瑟夫环)_第1张图片

 创建结构体

typedef struct Node
{
	int data;            //数据域
	struct Node *Next;	 //指针域
}*PStu,Stu;

 创建一个头结点,将指针域指向头结点,数据域置空

PStu createList()
{
	PStu headNode = (PStu)malloc(sizeof(Stu));
	headNode->Next = headNode;
	return headNode;
}

对于循环链表来说,增,删,改,查的功能实现和单链表基本一样

增:(头插法和尾插法)

void ListByHead(PStu headNode,int number)
{
	PStu NewNode = (PStu)malloc(sizeof(Stu));		//创建新结点 
	NewNode->data = number;							//赋值 
	//头插法 
	NewNode->Next = headNode->Next;
	headNode->Next = NewNode; 
}
void ListByBear(PStu headNode,int number)
{
	//创建一个指针接收头指针
	PStu p = headNode;                  
	//循环遍历到链表尾 
	while(p->Next != headNode)
	{
		p = p->Next;
	} 
	if(p)
	{
		//创建新节点 
		PStu newNode = (PStu)malloc(sizeof(Stu));
		//赋值 
		newNode->data = number;
		
		p->Next = newNode;
		p = newNode;
	}
	//尾指针一定要指向头结点 
	p->Next = headNode;
} 

删:找到删除的前一个结点,和后一个结点相连在一起,然后free掉这个需要删除的结点

void deleteNode(PStu headNode,int data)
{
	//遍历找到要删除的前一个结点 
	while(headNode->Next->data != data)
	{
		headNode = headNode->Next;
	}
	//创建新节点来存储删除结点 
	PStu k = (PStu)malloc(sizeof(Stu));
	//当前删除节点 
	k = headNode->Next;
	//k->Next:a删除结点的下一个结点 
	headNode->Next = k->Next;
	//释放掉改结点 
	free(k);
}

查:之前的单链表查找的时候,运用for循环,现在也是,但是问题是,循环条件得变为

for(p = headNode;p->Next!=headNode;p = p->Next)

设置中间变量t来判断是否找到了对应的数字。

void cha(PStu headNode,int number)
{
	PStu p;
	int t;
	for(p = headNode; p->Next != headNode; p=p->Next)	
	{
		if(p->data == number)
		{
			printf("Yes");
			t = 1;
			break;
		}
		else
		{
			t = 0;
		}
	}
	if(!t)
	printf("No");
} 

改:当查询到信息后需改就很简单了

void gai(PStu headNode,int number,int gai_number)
{
	PStu p;
	int t;
	for(p = headNode; p->Next != headNode; p=p->Next)	
	{
		if(p->data == number)
		{
			printf("Yes");
			t = 1;

			p->data = gai_number;

			break;
		}
		else
		{
			t = 0;
		}
	}
	if(!t)
	printf("No");
} 

 这些便是循环链表的一点点内容,学会了循环链表,那一定要看看伟大的约瑟夫环,可以帮助你很好的掌握这些技术

问题描述:

约瑟夫(Flavius Josephu)是公元1世纪的一位著名历史学家。约瑟夫环(也称为约瑟夫问题)是一个数学的应用问题,可以简单地表述如下:
已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列,他的下一个人又从1开始报数,数到m的那个人又出列,依此规律重复下去,直到圆桌周围只剩下一个人为止。
【输入形式】参与游戏的总人数,退出游戏的数字以及游戏开始的数字。
【输出形式】游戏最后剩余的编号。
【样例输入】
15 4 2
【样例输出】
14

#include
#include
#include
#include
#include

typedef struct Node
{
	int data;
	struct Node *Next;	
}*PStu,Stu;
PStu createList()
{
	PStu headNode = (PStu)malloc(sizeof(Stu));
	headNode->data = 1;
	headNode->Next = headNode;
	return headNode;
}
void ListByBear(PStu headNode,int N)
{
	int i;
	//创建一个指针接收头指针
	PStu p = headNode;                  
	//循环遍历到链表尾 
	while(p->Next != headNode)
	{
		p = p->Next;
	}
	for(i = 2;i<=N;i++)
	{
		//创建新节点 
		PStu newNode = (PStu)malloc(sizeof(Stu));
		//赋值 
		newNode->data = i;
		
		p->Next = newNode;
		p = newNode;
	}
	//尾指针一定要指向头结点 
	p->Next = headNode;
} 
void printList(PStu headNode)
{
	PStu p = headNode;
	while(p->Next!= headNode)
	{
	    printf("%d  ",p->data);
		p = p->Next;
	}
	printf("%d",p->data);
	printf("\n");
}
int main()
{
	int i;
	int M = 4; 
	PStu w = createList();
	PStu r;
	ListByBear(w,15);
	printList(w);
	int k = 2;
//遍历到开始的位置
	for(i = 1;iNext;
	}
	while(w->Next != w)
	{
		for(i = 1;iNext;      
		}
		printf("\n%d\n",w->data);
		r->Next = w->Next;
		w = w->Next;
	}
	printList(w);
}

借用尾插法将15个数字插入到循环链表中,因为是从第二个人计数,所以需要将链表的位置的移动到第二个结点的位置,while循环条件里面遍历链表,当尾指针域指向头指针的时候,结束。for循环里面,因为每次都是报数到第四个,所以需要遍历找到删除结点的前一个结点,每次循环的时候,都将结点赋值个新创建的结点,当遍历到删除结点前一个的时候,将结点(删除结点的前一个结点)保存起来,然后通过w = w->Next将结点后移一位,此时这个结点就是要删除的,此时将r的指针域指向删除结点的下一个结点,从而跳过了删除结点,而此时结点的位置还是当前的删除结点,所以将结点后移一位(w = w->Next)。
 

你可能感兴趣的:(数据结构,链表,数据结构)