您当前的位置: 首页 >  链表

惊鸿一博

暂无认证

  • 2浏览

    0关注

    535博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

线性表_循环链表(增减删查 + 约瑟夫环问题 代码实现 )

惊鸿一博 发布时间:2017-04-20 23:57:53 ,浏览量:2

1.概念

循环链表是链式存储结构。它的特点是表中最后一个结点的指针域指向头结点,整个链表形成一个环。

判断空链表的条件是

head==head->next;

rear==rear->next;

循环链表的特点是无须增加存储量,仅对表的链接方式稍作改变,即可使得表处理更加方便灵活。①循环链表中没有NULL指针。涉及遍历操作时,其终止条件就不再是像非循环链表那样判别p或p->next是否为空,而是判别它们是否等于某一指定指针,如头指针或尾指针等。 ②在单链表中,从一已知结点出发,只能访问到该结点及其后续结点,无法找到该结点之前的其它结点。而在单循环链表中,从任一结点出发都可访问到表中所有结点,这一优点使某些运算在单循环链表上易于实现。

约瑟夫环问题由来:

据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第 k个人。接着,再越过k-1个人,并杀掉第 k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
17世纪的法国数学家加斯帕在《数目的游戏问题》中讲了这样一个故事:15个教徒和15 个非教徒在深海上遇险,必须将一半的人投入海中,其余的人才能幸免于难,于是想了一个办法:30个人围成一圆圈,从第一个人开始依次报数,每数到第九个人就将他扔入大海,如此循环进行直到仅余15个人为止。问怎样排法,才能使每次投入大海的都是非教徒。
代码实现为第m个人(如m=3)

2.代码

//循环链表(circular linked list)的实现  增减删查

#include 
#include 

/*链表存储结构的定义*/

typedef struct CLinkList
{
	int data;
	struct CLinkList *next; //指向下一个链表元素的指针
}node;

/*****************************************************/
/*                   对循环链表的操作                 */
/*****************************************************/
/*函数作用:初始化循环链表*/
/*参    数:pNode-循环链表第一个结点*/
void ds_init(node **pNode)
{
	int item;             //存储输入内容
	node *temp;           //临时存储的结点指针
	node *target;         //用于动态查找的结点指针
	printf("请输入结点的值,输入0完成初始化 \n");
	while (1)
	{
		scanf("%d", &item); //将输入内容存入变量item对应的地址中
		fflush(stdin);      //清空缓存区
		if (item == 0)
		{
			return;
		}
		if ((*pNode) == NULL)  //循环链表中 插入第一个结点
		{
			*pNode = (node*)malloc(sizeof(struct CLinkList)); //为结点分配内存地址
			if (!(*pNode))  exit(0);                    //分配地址失败为0,退出程序
			(*pNode)->data = item;                      //将第一个结点数据设成item
			(*pNode)->next = *pNode;      //链表仅有一个结点时,该结点的next指向自己
		}
		else
		{
			/*找到最后一个结点赋值给target 即next指向第一个结点的结点*/
			for (target = (*pNode); target->next != (*pNode); target = target->next);
			/*生成新的结点*/
			temp = (node*)malloc(sizeof(struct CLinkList));
			if (!temp)  exit(0);
			temp->data = item;
			temp->next = *pNode;
			target->next = temp;
		}
	}
}

/*函数作用:插入结点*/
/*参    数: pNode-链表第一个结点, i-插入位置*/
void ds_insert(node **pNode, int i)
{
	node *temp;                 //临时存储新插入的结点指针
	node *target;               //用于动态查找的结点指针
	node *p;                    //存储要插入位置的原来的元素
	int item;
	int j = 1;                  //线性表起始下标为1
	printf("请输入要插入的结点的值  \n");
	scanf("%d", &item);         //将输入内容存入变量item对应的地址中


	if (i == 1)          //在第一个位置插入结点//      
	{
		temp = (node*)malloc(sizeof(struct CLinkList));
		if (!temp)  exit(0);

		temp->data = item;
		/*找到最后一个结点赋值给target 即next指向第一个结点的结点*/
		for (target = (*pNode); target->next != (*pNode); target = target->next);
		temp->next = (*pNode);      // 使插入结点指向 原来的头结点(变成了第二个元素)
		target->next = temp;        //将尾结点 指向 插入的结点
		*pNode = temp;              //设置新的头结点为 插入的结点
	}
	else
	{
		target = *pNode;            //将头结点赋给target

						    //i为插入的位置,获取要插入位置的的前一个结点,并赋给target
						    //如i=4,则jnext;
		}
		temp = (node*)malloc(sizeof(struct CLinkList));
		if (!temp)  exit(0);
		temp->data = item;
		p = target->next;           //将要插入位置i原来的元素提取出来
		target->next = temp;        //将要插入的元素放到i的位置
		temp->next = p;             //将原来的元素 连接到 新插入的元素的后面
	}
}

/*函数作用:删除结点*/
/*参    数:pNode-链表第一个结点, i-删除位置*/
void ds_delete(node **pNode, int i)
{
	node *target;
	node *temp;
	int j = 1;
	if (i == 1)  //删除第一个结点时
	{
		//找到最后一个结点
		for (target = *pNode; target->next != *pNode; target = target->next);
		temp = *pNode;             //提取出第一个结点
		*pNode = (*pNode)->next;   //将结点2赋给第一个结点
		target->next = *pNode;     //最后一个结点指向 新的第一个结点(原结点2)
		free(temp);                //释放原来的第一个结点内存空间
	}
	else
	{
		target = *pNode;            //将头结点赋给target
		for (; j < (i - 1); j++)    //获取要删除的结点的前一个结点
		{
			target = target->next;
		}
		temp = target->next;        //提取要删除的结点i
		target->next = temp->next;   //要删除结点i的前一结点的next 指向 要删除结点i的后一结点
		free(temp);
	}
}
/*函数作用:返回结点所在位置 int*/
/*参    数:pNode-链表第一个结点地址, elem-查找位置*/
int ds_search(node  *pNode, int elem)
{
	node *target;
	int i = 1;
	//直到查找到要删除元素,或链表结尾为止,将查找到的结点赋给target ,此时i加到该结点对应位置
	for (target = pNode; target->data != elem && target->next != pNode; i++)
	{
		target = target->next;
	}
	if (target->next == pNode)          //若到链表结尾未找到元素
		return 0;
	else
		return i;
}

/*函数作用:遍历显示链表中元素*/
/*参    数:pNode-链表第一个结点地址 */
void ds_traverse(node *pNode)
{
	node *temp;
	temp = pNode;
	printf("********************链表中元素如下*********************\n");
	do
	{
		printf("%4d ", temp->data);
	} while ((temp = temp->next) != pNode);
	printf("\n");
}

int main()
{
	node *pHead = NULL;
	char opp = 'A';                  //记录操作字符
	int find;                  //记录结点位置
	printf("1.初始化链表 \n\n2.插入结点 \n\n3.删除结点 \n\n4.返回结点位置 \n\n5.遍历链表 \n\n请选择你的操作\n");
	while (opp != '0')
	{
		scanf("%c", &opp);
		switch (opp)
		{
		case '1':
			ds_init(&pHead);
			printf("\n");
			ds_traverse(pHead);
			break;
		case '2':
			printf("输入要插入结点的位置?");
			scanf("%d", &find);
			ds_insert(&pHead, find);
			printf("在位置%d插入值后:\n", find);
			ds_traverse(pHead);
			printf("\n");
			break;
		case '3':
			printf("输入要删除的结点的位置?");
			scanf("%d", &find);
			ds_delete(&pHead, find);
			printf("删除第%d个结点后:\n", find);
			ds_traverse(pHead);
			printf("\n");
			break;
		case '4':
			printf("你要查找数值为多少的结点的位置?");
			scanf("%d", &find);
			printf("元素%d所在位置:%d\n", find, ds_search(pHead, find));
			printf("\n");
			break;
		case '5':
			ds_traverse(pHead);
			printf("\n");
			break;
		case '0':
			exit(0);

		}
	}
	return 0;
}
/*
* JosephProblem 
* 41个人一群人围坐成一圈,从1号开始,每三人个去除一个人,然后以原去除的人后面的那个人为第一个,每三个人去除一个人,知道所有人全部去除 求去除编号顺序
*/
#include 
#include 

/*链表存储结构的定义*/
typedef struct node
{
	int data;
	struct node *next; //指向下一个链表元素的指针
}node;

/*初始化循环链表*/
node *create(int n)
{
	node *p = NULL;    //临时结点,作为指针使用
	node *head;        //头结点,作为开始索引
	head = (node*)malloc(sizeof(node));
	p = head;          //指向头结点
	node *s = NULL;    //作为当前结点
	int i = 1;         //循环链表开始索引
	if (0 != n)        //创建元素个数不为0
	{
		while (i data = i++;          //i结点值为i
			p->next = s;            //指向下一节点
			p = s;                  //当前结点赋给指针P
		}
		s->next = head->next;         //尾结点指向第一个结点
		free(head);
		return  s->next;
	}
}

int main()
{
	int n = 41;          //环总数
	int m = 3;           //步长
	int i;
	node *p = create(n); //创建循环链表 
	node *temp;

	m %= n;              //设定步长使用
	while (p != p->next) //未删除到空链表时
	{
		for (i = 1; i < m - 1; i++)
		{
			p = p->next;      //若步长为m=3,循环1次,执行for后p指向结点2,输出结点3的值
		}
		printf("%d->", p->next->data);
		temp = p->next;         //提取要去除的结点(p是node2 temp是node3)
		p->next = temp->next;   //删除结点的前一结点指向删除结点的后一结点
		free(temp);
		p = p->next;            //原删除结点的后一结点重新作为第一个结点进行下一轮循环
	}
	printf("%d\n", p->data);       //输出最后结点
	return 0;
}

3.结果

关注
打赏
1663399408
查看更多评论
立即登录/注册

微信扫码登录

0.0415s