数据结构与算法joseph环Word格式.docx
《数据结构与算法joseph环Word格式.docx》由会员分享,可在线阅读,更多相关《数据结构与算法joseph环Word格式.docx(7页珍藏版)》请在冰豆网上搜索。
结果说明-------------------------------------------------------09
总结------------------------------------------------------------10
需求分析
编号是1,2,……,n的n个人按照顺时针方向围坐一圈,每个人只有一个密码(正整数)。
一开始任选一个正整数作为报数上限值m,从第一个人开始顺时针方向自1开始顺序报数,报到m时停止报数。
报m的人出列,将他的密码作为新的m值,从他在顺时针方向的下一个人开始重新从1报数,如此下去,直到所有人全部出列为止。
设计一个程序来求出出列顺序。
算法分析
1.该单循环链表的逻辑结构
由于题目要求“从第一个人开始顺时针方向自1开始顺序报数,报到m时停止报数。
报m的人出列,将他的密码作为新的m值,从他在顺时针方向的下一个人开始重新从1报数,如此下去”,队伍中编号最大的人报数完毕后编号最小的人应紧接着报数,所以创建链表时链表中最后一个结点的next指针直接指向首结点而不是头结点比较合适。
该单循环链表的逻辑结构如下:
2.删除出列的结点
某结点出列后,应将该结点从单循环链表里删除,则需要找到该结点的前一个结点,并由p指向它,通过修改指针域使结点p的直接后继为s的直接后继,即p->
next=s->
next。
当m=1时,即将出列的结点的前一个结点就是还未进行移动的当前的s指针指向的结点。
当要删除的结点恰好为head指向的结点时,删除前应修改head指向的结点为s->
3.判断是否所有人全部出列
由于结点出列后的删除操作,整个单循环链表的表长是逐渐缩短的,直至单链表只剩下头结点和首结点:
此时已经无法在进行删除结点操作,因为该结点的直接后继就是自己。
但实际上,当只剩下一个人时无论m为何值此人直接出列就可以了。
也就是说,当链表里只剩下最后一个结点时已经不必进行删除操作,直接输出该结点的编号即可。
于是问题就转化成如何判断链表里只剩最后一个结点,判断head->
next是否与head相等可以解决问题。
算法设计
1.PersonList结构体
每个结点包含编号,密码以及指向下一个结点的指针域三个数据。
typedefstructnode
{
intpassword;
//密码
intnumber;
//编号
structnode*next;
//指针域
}PersonList;
2.CreateList函数
该函数的功能是建立单循环链表,并从键盘读入每个编号的密码,入口参数n为单循环链表所包含的结点的个数,函数返回一个PersonList类型的指针。
PersonList*CreateList(intn)
PersonList*head,*s,*r;
head=(PersonList*)malloc(sizeof(PersonList));
head->
next=NULL;
number=1;
printf("
请输入编号为1的人的密码:
"
);
scanf("
%d"
&
head->
password);
//从键盘中读取编号为1的人的密码
getchar();
//接收回车
r=head;
for(inti=2;
i<
=n;
i++)
{
s=(PersonList*)malloc(sizeof(PersonList));
s->
number=i;
printf("
请输入编号为%d的人的密码:
i);
scanf("
s->
//从键盘读入每个编号的密码
getchar();
r->
next=s;
//插入新结点
r=s;
//将尾指针指向新结点
}
r->
next=head;
//将最后一个结点的指针域指向首结点
returnhead;
}
3.Exports函数
该函数的功能是模拟出列的过程,并按照出列的顺序输出每个人的编号,入口参数head为单循环链表,入口参数m为初始报数上限值。
voidExports(PersonList*head,intm)
PersonList*s,*p;
s=head;
m=m-1;
出列顺序为:
while(head!
=head->
next)//当链表里有一个以上的结点时
if(m!
=1)//若m=1可跳过for循环
for(inti=1;
=m-1;
i++)//报数直到第m-1个结点
s=s->
next;
p=s;
//p指向第m-1个结点
s=s->
//s指向第m个结点
%4d"
s->
number);
//输出第m个结点的编号
m=s->
password;
//将第m个结点的密码作为新的m值
if(s==head)//若要删除的结点恰好是首结点,移动head指针
head=s->
p->
//删除第m个结点
s=p;
//s指向报数1结点的前一个结点,为下一次报数做准备
//输出链表里剩下的唯一一个结点
完整代码
#include<
stdio.h>
stdlib.h>
m--;
while(head->
next!
=head)
=1)
if(s==head)
voidmain()
intm,n;
请输入报数上限值:
m);
请输入参加报数的人数:
n);
PersonList*q=CreateList(n);
Exports(q,m);
\n"
结果说明
第一轮报数m=7编号为7的人出列
第二轮报数m=4编号为1的人出列
第三轮报数m=5编号为6的人出列
第四轮报数m=4编号为2的人出列
第五轮报数m=2编号为4的人出列
第六轮报数m=1编号为5的人出列
第七轮报数m=9编号为8的人出列
第八轮报数m=7编号为9的人出列
第九轮报数m=8编号为3的人出列
第十轮报数m=3编号为10的人出列
总结
课本里提供了单循环链表的置空,建立,求表长,取结点,定位,插入,删除等操作代码,理解每个方法的原理便于面对实际问题时化繁为简灵活运用。