24、[2019统考真题]设线性表L=(a1,a2,a3,...,an-2,an-1,an)采用带头结点的单链表保存,请设计一个空间复杂度为0(1)且时间上尽可能高效的算法,重新排列L中的各结点,得到线性表L=(a1,an,a2,an-1,a3,an-1...)
链表中的结点定义如下:
typedef struct node(
int data;
struct node *next;
}NODE;
要求
1)给出算法的基本设计思想。
2)根据设计思想,采用C或C++语言描述算法,关键之处给出注释。
3)说明你所设计的算法的时间复杂度。
1)
观察发现重新排列后的链表是原链表第一个元素、倒数第一个元素、第二个元素、倒数第二个元素……合并而成,所以先将原链表从中间分开得到前半链表和后半链表,然后将后半链表翻转,最后将两链表从头开始遍历每次各取一个节点链接起来即可得到所求链表。
2)
void change_list(NODE *h){
NODE *q,*q,*head;
p=q=h;
//遍历链表,最后p指向中间节点
while(q->next!=NULL){
p=p->next;
q=q->next;
if(q->next!=Null)q=q->next;
}
q=p->next;
p->next=NULL;
//翻转后半个链表
q=reverseList(q);
head=h->next;
//将两个链表合并
while(q!=NULL){
p=q->next;
q-next=head-next;
head->next=q;
head=q->next;
q=p;
}
}
//翻转链表函数
ListNode reverseList(NODE *head){
NODE *p,*q=head,*temp;
while(q!=null){
temp=q.next;
q.next=p;
p=q;
q=temp;
}
return p;
}
3)
找中间节点的时间复杂度为O(n),翻转链表的时间复杂度为O(n),合并链表的时间复杂度为O(n),所以该算法时间复杂度为O(n)。
25、【2020统考真题】定义三元组(a,b,c)(a、b、c均为正数)的距离D=|a-b|+|b-c|+|c-a|给定3个非空整数集合S1、S2和S3,按升序分别存储在3个数组中。请设计一个尽可能高效的算法,计算并输出所有可能的三元组(a,b,c)(a∈S1,b∈S2,C∈S3)中的最小距离。例如S1={-1,0,9},S2={-25,-10,10,11),S3={2,9,17,30,41},则最小距离为2,相应的三元组为(9,10,9)。
要求:
1)给出算法的基本设计思想。
2)根据设计思想,采用C语言或C++语言描述算法,关键之处给出注释。
3)说明你所设计算法的时间复杂度和空间复杂度。
1)
假设a<=b<=c,D=b-a+c-b+c-a=2(c-a),则最大值与最小值的具体决定就D的大小,所以每次改变最小的数即可。用D_min记录最小距离,初始设为一个足够大的整数,S1、S2和S3分别存在数组A,B和C中,数组长度分别为len1,len2和len3,当i,j,k同时小于各自数组长度时,循环执行:
①计算D;
②当D<D_min时,D_min=D;
③将A[i],B[j]和C[k]比较,将较小者的下标加1;
循环结束后即可得出三元组的最短距离。
2)
#define max 0x7fffffff
//计算绝对值函数
int abs(int num){
if(num<0)
return -num;
else
return num;
}
//判断a是否为最小值
int Min(int a,int b,int c){
int num=a<b?a:b;
num=num<c?num:c;
return num;
}
int searchMin(int A[],int len1,int B[],int len2,int C[],int len3){
int i=0,j=0,k=0,D_min=max,D,min;
//遍历各个数组,更新D_min
while(i<len1&&j<len2&&k<len3){
D=abs(A[i]-B[j])+abs(B[j]-C[k])+abs(A[i]-C[k]);
if(D<D_min)D_min=D;
min=Min(A[i],B[j],C[k]);
if(A[i]==min)i++;
else if(B[j]==min)j++;
else k++;
}
return D_min;
}
3)
令n=len1+len2+len3,则该算法的时间复杂度为O(n),空间复杂度:O(1).