【2020年山西大学真题】用单链表保存m个整数,结点的结构为【data】[link],且|data|≤n(n为
正整数)。现要求设计一个时间复杂度尽可能高效的算法,对于链表中data的绝对值相等的结点
,仅保留第一次出现的结点而删除其余绝对值相等的结点。
(1)给出单链表结点的数据类型定义。
(2)给出算法的基本设计思想。
(3)根据设计思想,描述算法,关键之处给出注释。
(4)说明所设计算法的时间复杂度和空间复杂度
(1)首先,我们可以使用以下结构来定义单链表的节点:
```c
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data; // 节点数据
struct Node* next; // 指向下一个节点的指针
} Node;
```
(2)接下来,我们可以使用以下算法设计思路来实现删除节点的功能:
1. 创建一个数组 `appeared`,用于记录已经出现的绝对值。将数组中的所有元素初始化为0。
2. 遍历链表中的每个节点,对每个节点的数据进行以下操作:
- 如果该节点的数据绝对值在 `appeared` 数组中对应的位置上为0,则将该位置的元素设置为1,表示该绝对值已经出现过。
- 如果该节点的数据绝对值在 `appeared` 数组中对应的位置上不为0,则将这个节点从链表中删除。
下面是使用 C 语言编写的实现上述算法的代码:
```c
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* next;
} Node;
void deleteDuplicates(Node* head) {
if (head == NULL || head->next == NULL) {
return; // 如果链表为空或只有一个节点,无需进行操作
}
int max_value = abs(head->data); // 记录链表头节点的绝对值
int* appeared = (int*)calloc((max_value + 1), sizeof(int)); // 创建 appeared 数组并初始化为0
Node* current = head;
Node* previous = NULL;
while (current != NULL) {
int abs_value = abs(current->data);
if (appeared[abs_value] == 0) {
appeared[abs_value] = 1; // 将 appeared 数组中对应位置的元素设置为1,表示该绝对值已经出现过
previous = current;
} else {
previous->next = current->next; // 从链表中删除节点
free(current);
}
current = previous->next;
}
free(appeared);
}
// 测试代码
void printList(Node* head) {
Node* current = head;
while (current != NULL) {
printf("%d ", current->data);
current = current->next;
}
printf("\n");
}
int main() {
Node* head = (Node*)malloc(sizeof(Node));
Node* node1 = (Node*)malloc(sizeof(Node));
Node* node2 = (Node*)malloc(sizeof(Node));
Node* node3 = (Node*)malloc(sizeof(Node));
Node* node4 = (Node*)malloc(sizeof(Node));
Node* node5 = (Node*)malloc(sizeof(Node));
head->data = 1;
node1->data = 2;
node2->data = 3;
node3->data = 2;
node4->data = 2;
node5->data = 4;
head->next = node1;
node1->next = node2;
node2->next = node3;
node3->next = node4;
node4->next = node5;
node5->next = NULL;
printf("原链表:");
printList(head);
deleteDuplicates(head);
printf("删除重复节点后的链表:");
printList(head);
return 0;
}
```
(3)在上述代码中,我们首先创建了一个 `appeared` 数组来记录出现过的绝对值。然后使用两个指针 `current` 和 `previous` 来遍历链表,并依次处理每个节点。在处理每个节点时,我们根据节点数据的绝对值在 `appeared` 数组中的值来判断节点是否重复出现,并进行删除操作。最后,我们测试这个算法的功能,并打印链表的内容。
(4)算法的时间复杂度为 O(n),其中 n 是链表中的节点个数。算法的空间复杂度为 O(m),其中 m 是链表数据的最大绝对值。