本算法将元素x插入到线性表中,并保持线性表的有序性。
{low=1;high=num;//题目要求下标从1开始
while(low<=high)∥对分查找元素x的插入位置。
{mid=(low+high)/2;
if(A[mid]==x){low=mid+1;break;}
elseif(A[mid]>x)high=mid-1;elselow=mid+1;
}
for(i=num;i>=low;i--)A[i+1]=A[i];∥元素后移。
A[i+1]=x;∥将元素x插入。
}算法结束。
[算法讨论]算法中当查找失败(即线性表中无元素x)时,变量low在变量high的右面(low=high+1)。
移动元素从low开始,直到num为止。
特别注意不能写成for(i=low;i<=num;i++)A[i+1]=A[i],这是一些学生容易犯的错误。
另外,题中未说明若表中已有值为x的元素时不再插入,故安排在A[mid]==x时,用low(=mid+1)记住位置,以便后面统一处理。
查找算法时间复杂度为O(logn),而插入时的移动操作时间复杂度为O(n),若用顺序查找,则查找的时间复杂度亦为O(n)。
2.解答:
(1)顺序表
分析:
将顺序表的第一个元素与最后一个元素互换,第二个元素与倒数第二个元素互换。
void invert(SeqList *L, int *num)
{
int j;
ElemType tmp;
for(j=0;j<=(*num-1)/2;j++)
{tmp=L[j];
L[j]=L[*num-j-1];
L[*num-j-1]=tmp;}
}
(2)单链表
void invert(LinkList L)
{
Node *p,*q,*r;
if(L->next==NULL) return; /*链表为空*/
p=L->next;
q=p->next;
p->next=NULL; /*摘下第一个结点,生成初始逆置表*/
while(q!
=NULL) /*从第二个结点起依次头插入当前逆置表*/
{
r=q->next;
q->next=L->next;
L->next=q;
q=r;
}
}
3.解答:
(1)定位LOCATE(L,X)
在带头结点类单链表上实现的算法为:
intlocate_lklist(lklisthead,datatypex)
/*求表head中第一个值等于x的的序号,不存在这种结点时结果为0*/
{p=head->next;j=1;/*置初值*/
while((p!
=NULL)&&(p->data!
=x))
{p=p->next;j++}/*未达表结点又未找到值等于X的结点时经,继续扫描*/
if(p->data==x)return(j);
elsereturn(0);
}
在无头结点的单链表上实现的算法为:
intWlocate(lklisthead,datatypeX)
/*求表head中第一个值等于x的结点的序号。
不存在这种结点时结果为0*/
{p=head;j=1;/*置初值*/
while((p!
=NULL)&&(p->data!
=x))
{p=p->next;j++}/*未达表结点又未找到值等于X的结点时经,继续扫描*/
if(p->data==X)return(j);
elsereturn(0);
}
(2)按序号查找find(L,i)
在带头结点的单链表上实现的算法为:
pointerfind_lklist(lklisthead,inti);
{j=1;p=head->next;
while((j<1)&&(p!
=NULL)){p=p->next;j++}
if(i==j)return(p);
elsereturn(NULL);
}
在无头结点的单链表上实现的算法为:
pointerfind_lklist(lklisthead,inti);
{j=1;p=head;
while((j<1)&&(p!
=NULL)){p=p->next;j++}
if(i==j)return(p);
elsereturn(NULL);
}
(3)、插入INSERT(L,X,i)
在带头结点单链表上实现的算法为:
voidinsert_lklist(lklisthead,datatypex,intI)
/*在表haed的第i个位置上插入一人以x为值的新结点*/
{p=find_lklist(head,i-1);/*先找第i-1个结点*/
if(p==NULL)reeor(“不存在第i个位置”)/*若第i-1个结点不存在,退出*/
else{s=malloc(size);s->data=x/*否则生成新结点*/
s->next=p->next/*结点*p在链域值传给结点*s的链域*/
p->next=s;/*修改*p的链域*/
}
}
在无头结点的单链表上实现的算法为:
voidWinsert(lklisthead,dataytpeX,inti)
/*在表haed的第i个位置上插入一人以x为值的新结点*/
{if(i<=0)error(“i<=0”);
else{s=malloc(size);s->data=X;/*否则生成新结点*/
if(i==1){s->next=head;head=s;}
else{p=wfind_lklist(lklisthead,i-1);
if(p==NULL)error(“i>n+1”);
else{s->next=p->next;p->next=s;}
}
}
(4)删除DELDTE(L,i)
在带头结点的单链表上实现的算法为:
voiddelete_lklist(lklisthead,inti)/*删除表head的第i个结点*/
{p=find_lklist(head,i-1)/*先找待删结点的直接前驱*/
if((p!
==NULL)&&(p->next!
=NULL))/*若直接前趋存在且待结点存在*/
(q=p->next;/*q指向待删结点*/
p->next=q->next/*摘除待结点*/;
free(q);/*释放已摘除结点q*/
}
elseerror(“不存在第i个结点”)/*否则给出相关信息*/
}
在无头结点的单链表上实现的算法为:
voidWdelete(lklisthead,inti)
/* 删除表head的第i个结点,若该链表仅有一个结点时,赋该结点指针NULL*/
{if(i<=0)error(“I<=0”
else{if(i==0){q=head;head=head->next;free(q);}
else{p=wfind_lklist(head,i-1);/*找链表head中第i-1结点指针*/
if(p!
=NULL)&&(p->next!
=NULL)
{q=p->next;p->next=q->next;free(q);}
elseerror(“不存在第I个结点”);
}
}
}
4.【解答】算法如下:
LinkList merge(LinkList A, LinkListB, LinkList C)
{Node *pa,*qa,*pb,*qb,*p;
pa=A->next; /*pa表示A的当前结点*/
pb=B->next;
p=A; /*利用p来指向新连接的表的表尾,初始值指向表A的头结点*/
while(pa!
=NULL && pb!
=NULL) /*利用尾插法建立连接之后的链表*/
{ qa=pa->next;
qb=qb->next;
p->next=pa; /*交替选择表A和表B中的结点连接到新链表中;*/
p=pa;
p->next=pb;
p=pb;
pa=qa;
pb=qb;
}
if(pa!
=NULL) p->next=pa; /*A的长度大于B的长度*/
if(pb!
=NULL) p->next=pb; /*B的长度大于A的长度*/
C=A;
Return(C);
}
5.[题目分析]在顺序存储的线性表上删除元素,通常要涉及到一系列元素的移动(删第i个元素,第i+1至第n个元素要依次前移)。
本题要求删除线性表中所有值为item的数据元素,并未要求元素间的相对位置不变。
因此可以考虑设头尾两个指针(i=1,j=n),从两端向中间移动,凡遇到值item的数据元素时,直接将右端元素左移至值为item的数据元素位置。
voidDelete(ElemTypeA[],intn)
∥A是有n个元素的一维数组,本算法删除A中所有值为item的元素。
{i=1;j=n;∥设置数组低、高端指针(下标)。
while(i{while(i=item)i++;∥若值不为item,左移指针。
if(iif(i}
[算法讨论]因元素只扫描一趟,算法时间复杂度为O(n)。
删除元素未使用其它辅助空间,最后线性表中的元素个数是j。
若题目要求元素间相对顺序不变,请参见本章三、填空题25的算法。
6.分析设置两个指针,分别指向*S及其后继,然后按循环链表特性,顺序往下查找*s的
直接前趋,找到后删除;
voidDELETE_Xlklist(lklistS)
{p=s;q=p->next;
while(q->nest!
=s)
{p=q;q=q->next;}
p->next=s;free(q);
}
7.分析:
在链表L中依次取元素,若取出的元素是字母,把它插入到字母B中,然后在L中删除该元素;若取出的元素是数字,把它插入到数字链D中,然后在L中删除该元素。
继续取下一个元素,直到链表的尾部。
最后B、D、L中分别存放的是字母字符、数字字符和其它字符。
设原表有头结点、头指针L,新建数字字符链D,字母字符链B,其它字符链R。
voidDISM_lklist(lklistL,lklistD,lklistB,lklistR)
{D=malloc(sizeof(int));D->next=D;/*建D循环链表头结点*/
B=malloc(sizeof(char));B->next=B;/*建B循环链表头结点*/
p=L;q=p->next;
while(q!
=null)
{if((q->data<=’9’)&&(q->data>=’0’))
{p->next=q->next;/*在表L中摘除q结点*/
q->next=D->next;D->next=q;/*将q结点插入D中*/
q=p->next;/*移动q指针*/
}
elseif(q->data<=’z’)&&(q->data>=’a’)||(q->data<=’z’)&&(q->data>=’a’))
{p->next=q->next;/*在表L中删除q结点*/
q->next=B->next;B->next=q;/*将q结点插入B中*/
q=p->next;/*移动q指针*/
}else{p=q;q=p->next;}/*移动q指针*/
}
p->next=L;R=L;/*使R为循环表*/
}
8.约瑟夫环问题
【解答】算法如下:
typedefstructNode
{
intpassword;
intnum;
structNode*next;
} Node,*Linklist;
voidJosephus()
{
LinklistL;
Node*p,*r,*q;
intm,n,C,j;
L=(Node*)malloc(sizeof(Node)); /*初始化单向循环链表*/
if(L==NULL){printf("\n链表申请不到空间!
");return;}
L->next=NULL;
r=L;
printf("请输入数据n的值(n>0):
");
scanf("%d",&n);
for(j=1;j<=n;j++) /*建立链表*/
{
p=(Node*)malloc(sizeof(Node));
if(p!
=NULL)
{
printf("请输入第%d个人的密码:
",j);
scanf("%d",&C);
p->password=C;
p->num=j;
r->next=p;
r=p;
}
}
r->next=L->next;
printf("请输入第一个报数上限值m(m>0):
");
scanf("%d",&m);
printf("*****************************************\n");
printf("出列的顺序为:
\n");
q=L;
p=L->next;
while(n!
=1) /*计算出列的顺序*/
{
j=1;
while(j {
q=p; /*q为当前结点p的前驱结点*/
p=p->next;
j++;