24、设线性表L=(a1,a2,a3,...,an-2,an-1,an)采用带头结点的单链表保存,链表中的节点定义如下:
typedef struct node {
int data;
struct node* next;
}
请设计一个空间复杂度为O(1)且时间上尽可能高效的算法,重新排列题中的各个结点,得到线性表L=(a1,an,a2,an-1,a3,an-2,...)
要求:
1)给出算法的基本设计思想。
2)根据设计思想,采用C或C++语言描述算法,关键之处给出注释。
3)说明你所涉及的算法的时间复杂度。
思路
本题的难点在于,空间复杂度为O(1),其实实质上是链表的逆置,之后再进行插入,如何选择方法使链表逆置就成了一个问题,本题选用“速度双倍”的方法,p节点走一半,双倍速度的q节点就走到了末尾,将末尾链表进行逆置即可。
具体实现
#include <stdio.h>
#include <stdlib.h>
// 链表结构体
struct ListNode {
int val;
struct ListNode* next;
};
// 创建链表的函数
struct ListNode* createList() {
int val;
printf("请输入链表元素的值(输入-1结束):\n");
scanf("%d", &val);
struct ListNode* head = NULL;
struct ListNode* current = NULL;
while (val != -1) {
struct ListNode* node = (struct ListNode*)malloc(sizeof(struct ListNode));
node->val = val;
node->next = NULL;
if (head == NULL) {
head = node;
current = node;
} else {
current->next = node;
current = node;
}
scanf("%d", &val);
}
return head;
}
// 链表混合函数
struct ListNode* changeList(struct ListNode* head) {
ListNode *p, *q, *r, *s;
p=q=head;
while(q->next != NULL) { // 寻找中间节点
p = p->next; // p走一步
q = q->next;
if(q->next != NULL)
q = q->next; // q走两步
}
q = p->next; // p所指节点为中间节点,q为后半段链表的首节点
p->next = NULL;
while(q != NULL) { // 将链表后半段逆置
r = q->next;
q->next = p->next;
p->next = q;
q = r;
}
s = head; // s变成头节点
q = p->next; // q是后半段的第一个数据点
p->next = NULL;
while(q != NULL) { // 将链表后半段插入指定位置
r = q->next;
q->next = s->next;
s->next = q;
s = q->next;
q = r;
}
return head;
}
// 打印链表的函数
void printList(struct ListNode* head) {
struct ListNode* current = head;
while (current != NULL) {
printf("%d ", current->val);
current = current->next;
}
printf("\n");
}
int main() {
struct ListNode* list = createList();
struct ListNode* result = changeList(list);
printf("重新排列后的链表:");
printList(result);
return 0;
}
25、求元素间的距离。
定义三元组(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)说明你所涉及的算法的时间复杂度。
思路
本题初始使用一个足够大的整数来记录距离,由数学公式可推知,两个数距离的和其实就是最小值与最大值之间的距离的2倍,所以我们只需要固定一个值,假定为c,寻找与其最接近的a、b的值,将最大的和最小的相减即可得到最小的距离。
具体实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LEN 10000
#define INT_MAX 0x7fffffff
// 计算绝对值
int absNum(int a) {
if(a<0)
return -a;
else
return a;
}
// a是否是三个数中的最小值
bool minNum(int a, int b, int c) {
if(a < -b && a <= c)
return true;
return false;
}
int createArr(int num[]) {
char str[MAX_LEN];
int n,i,j=0;
// 将输入的内容按照字符串读入
scanf("%s", str);
// 读取字符串中不含‘{’‘}’的内容
for (i = 0; str[i] != '}'; i++) {
if (str[i] != '{') {
str[j++] = str[i];
}
}
// 读取要删除的数字
n = int(str[j+3]-'0');
str[j] = '\0'; // 确保新字符串以 '\0' 结尾
// 分割字符串并转换为数字
i=0;
char *token = strtok(str, ",");
while (token != NULL) {
num[i++] = atoi(token);
token = strtok(NULL, ",");
}
return i;
}
// 计算三元组的最小距离
int findMinofTrip(int A [],int n,int B [],int m,int C[], int p){
int i=0, j=0, k=0, min=INT_MAX, d;
while(i < n && j < m && k < p && min > 0){
// 计算d
d = absNum(A[i] - B[j]) + absNum(B[j] - C[k] ) + absNum(C[k] - A[i]);
if (d < min)
min = d; //更新 d
if (minNum(A[i], B[j], C[k] ) )
i++;
else if(minNum(B[j], C[k], A[i]))
j++;
else
k++;
}
return min;
}
int main() {
int a[10], b[10], c[10];
printf("请输入三组数:\n");
int n = createArr(a);
int m = createArr(b);
int p = createArr(c);
int d = findMinofTrip(a, n, b, m, c, p);
printf("最小距离是%d", d);
return 0;
}