对于线性表的操做过程,须要对指针操做这一块比较熟悉,由于算法中用到的指针很是多,包括顺序表和链表的建表,LinkList *L都是不少题目须要用到的结构,定义结构体等等操做仍是须要多熟悉。同时,不一样状况对于顺序表和链表的选择也是不同的,顺序表的特色在于无需为表示结点间的逻辑关系而增长额外的存储空间,存储利用率提升,而且能够方便的存储表中的任一结点,存储速度快。而链表的特色在于能够方便的进行扩充而且能够方便的删除和插入。因此不少时候考虑一个算法的效率或者功能,也是在于对顺序表和链表的选择。对于线性表这一块,c++语法也不少的应用到,cin和cout,new等语句都大大简化代码长度,可读性也更强,因此线性表仍是须要好好下功夫学习。c++
6-4 顺序表操做集 (20 分)
本题要求实现顺序表的操做集。
各个操做函数的定义为:
List MakeEmpty():建立并返回一个空的线性表;
Position Find( List L, ElementType X ):返回线性表中X的位置。若找不到则返回ERROR;
bool Insert( List L, ElementType X, Position P ):将X插入在位置P并返回true。若空间已满,则打印“FULL”并返回false;若是参数P指向非法位置,则打印“ILLEGAL POSITION”并返回false;
bool Delete( List L, Position P ):将位置P的元素删除并返回true。若参数P指向非法位置,则打印“POSITION P EMPTY”(其中P是参数值)并返回false。算法
List MakeEmpty()函数建立空线性表
a=new LNode
a->last=NULL尾节点为空,建立成功返回线性表
Position Find( List L, ElementType X )函数找出函数中特定元素
if(!L)先判断是否为空
for i=0 to L->last遍历链表
if(L->date[i]==X)判断是不是要找到的数
return i若是是要找的数,返回当前的节点
bool Insert( List L, ElementType X, Position P )函数插入节点
两个if语句判断是否为满和是否非法区域
for i=L->last to P从表尾遍历至须要的位置
L->Data[P]=X;++L->Last;让p节点为X,最大长度节点后移
bool Delete( List L, Position P )函数删除指定节点元素
if(P>=L->last||P<0)判断是否越界,最大长度节点前移
for i=P to L->last从P节点开始后面的元素前移数组
·Q1:这道题是我作完后面的题目以后再回来作的,因此函数的实现基本没什么问题,编译错误的缘由是有几个判断条件,好比说删除和插入函数中的判断空没有加下去,并且把主函数都写进去了
·A1:后来对照着同窗的代码修改了一下,加上了两个判断,而且细节处也作了优化,如++L->last和--L->last都是同窗给的建议。数据结构
6-9 jmu-ds-有序链表合并 (20 分)函数
已知两个递增链表序列L1与L2,2个链表都是带头结点链表。设计函数实现L1,L2的合并,合并的链表仍然递增有序,头结点为L1的头结点。 合并后须要去除重复元素。
输入格式: 输入分两行,先输入数据项个数,再输入数据项,数字用空格间隔。
输出格式: 在一行中输出合并后新的递增链表,数字间用空格分开,结尾不能有多余空格;学习
LinkList pa=L1->next,pb=L2->next,r,s; 定义指针,r指针和s指针分别表明L1的操做指针和新链表的操做指针
while(pa!=NULL&&pb!=NULL)循环进行的条件,让指针的指向不会跑到非法区域
if的三个判断,两个链表的元素大小关系执行相应操做,目的是有序的整合到一个数组中去
接下来的两个while(pa,pb!=NULL)则是让新的链表继承本来两个链表的全部数据而且保持有序
r->next=NULL的做用是让r链表不溢出测试
·Q1:第一次没有加入当两个表的元素相同的时候的判断条件,致使了第一个测试点错误。
`A1:在判断两个表元素大小以后加入判断元素是否相同函数
·Q2:加入判断以后,测试点仍是错误,发现判断相同函数不能在判断大小函数以后
·A2:把判断相同函数加入到判断相等函数以前
·Q3:指针的做用重叠,致使内存发生错误
·A3:从新定义指针,多了两个指向next的指针优化
6-10 jmu-ds-有序链表的插入删除 (15 分)编码
链表L是一个有序的带头结点链表,实现有序链表插入删除操做。实现函数为:
函数接口定义:
void ListInsert(LinkList &L,ElemType e);//有序链表插入元素e
void ListDelete(LinkList &L,ElemType e);//链表删除元素e设计
void ListInsert(LinkList &L,ElemType e)函数实现插入元素e
LinkList s,p定义指针指向L和新链表
动态分配内存以后开始while循环遍历链表
if(p->next==NULL)当p指向最后一个数,即插入元素位置为最后一个
if(p->data>e)插入点不为最后一个,找到插入点,以后的元素后移
void ListDelete(LinkList &L,ElemType e)函数实现删除指定元素
一样LinkList s,p定义指针指向L和新链表
while循环遍历链表,if(p->data==e)找到相应元素
开始删除操做
·Q1:第一次出现错误是编译错误,加入了一个没有的变量n做为链表长度
·A1:删除n,从新安排循环
·Q2:第二次出现的错误直接是段错误,没有定义链表末尾,内存溢出
·A2:按找同窗给的建议修改了一下,在删除函数中加入判断
约瑟夫环问题:一圈共有N我的,开始报数,报到M的人自杀,而后从新开始报数,问最后自杀的人是谁?
圆桌问题
模拟整个过程,复杂度为O(NM)。能够用数学方法来求解: 把问题从新描述一下:N我的(编号0~(N-1)),从0开始报数,报到(M-1)的自杀,剩下的人继续从0开始报数。求最后自杀者的编号。第一个自杀的人是(M-1)%N,例如上图中,41我的中,报到3的人自杀,则字一个自杀的人的编号是(3-1)%41=2。有人自杀后,下一个位置M又从零开始报数,问题变为(N-1)我的,报到为(M-1)的人自杀,问题规模减少了。定义F(N-1)为总数为N-1我的时,最后自杀的人的序号。根据上面的对比,F(N-1)能够当作是N我的自杀掉一个以后从新编码组成的新问题,与从新编码以前的序号对比多了一个M,那么F(N-1) + M就至关因而N我的自杀掉一个以后,接着继续自杀到最后一个的序号。
这道题的规则看起来很简答,就是循环报数,而后逐一剔除人员,剩下最后的一个。可是实际的思路却比较复杂,首先要实现循环报数就须要用到循环链表,而后重复遍历链表,而且重复删除数据,移动节点,操做起来就相对复杂一些,刚开始系看到这道题,想的是能不能用数组写一写看看,可是后面的定义内存太大了,主要是不知道题目的定义大小,而后就得把空间定义的很大,这样对于时间复杂度和空间复杂度都不利。以后看了用数学的方法转化成数据结构的方法来解答,大大节省了空间和时间。因此说链表作法不少时候都是更加便利。之后要多学着用链表和线性表来解答题目了