1、根据给定的整型数组,以尾插法建立一个单链表,并实现以下操作:
① 查找:输入一个欲查找的整数,找到则显示第一个相匹配的整数在单链表中所处的位置,若不存在,则显示提示信息。
② 删除:输入一个欲删除的整数e,若存在则在单链表中删除第一个值为e的元素。
③ 插入:输入一个欲插入位置i和欲插入元素e,将e插入到第i个整数之前(注意i的合法性)。
#include <stdio.h>
#include <stdlib.h>
// 定义单链表节点结构
typedef struct Node {
int data;
struct Node* next;
} Node;
// 尾插法建立单链表
Node* createLinkedList(int arr[], int size) {
Node* head = NULL;
Node* tail = NULL;
for (int i = 0; i < size; i++) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = arr[i];
newNode->next = NULL;
if (head == NULL) {
head = newNode;
tail = newNode;
} else {
tail->next = newNode;
tail = newNode;
}
}
return head;
}
// 查找元素在单链表中的位置
int findElement(Node* head, int target) {
Node* current = head;
int position = 1;
while (current != NULL) {
if (current->data == target) {
return position;
}
current = current->next;
position++;
}
return -1; // 未找到目标元素
}
// 删除单链表中的指定元素
void deleteElement(Node** headRef, int target) {
Node* current = *headRef;
Node* prev = NULL;
// 处理头节点为目标元素的情况
if (current != NULL && current->data == target) {
*headRef = current->next;
free(current);
return;
}
while (current != NULL && current->data != target) {
prev = current;
current = current->next;
}
if (current == NULL) {
return; // 未找到目标元素
}
prev->next = current->next;
free(current);
}
// 在单链表的指定位置插入元素
void insertElement(Node** headRef, int position, int value) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = value;
if (position == 1) {
newNode->next = *headRef;
*headRef = newNode;
} else {
Node* current = *headRef;
for (int i = 1; i < position - 1 && current != NULL; i++) {
current = current->next;
}
if (current == NULL) {
printf("无效的插入位置\n");
return;
}
newNode->next = current->next;
current->next = newNode;
}
}
// 打印单链表
void printLinkedList(Node* head) {
Node* current = head;
while (current != NULL) {
printf("%d ", current->data);
current = current->next;
}
printf("\n");
}
// 释放单链表内存
void freeLinkedList(Node* head) {
Node* current = head;
Node* next = NULL;
while (current != NULL) {
next = current->next;
free(current);
current = next;
}
}
int main() {
// 测试数据
int arr[] = {1, 2, 3, 4, 5};
int size = sizeof(arr) / sizeof(arr[0]);
// 建立单链表
Node* head = createLinkedList(arr, size);
// 打印单链表
printf("单链表内容:");
printLinkedList(head);
// 查找元素
int target = 3;
int position = findElement(head, target);
if (position != -1) {
printf("%d 在单链表中的位置为:%d\n", target, position);
} else {
printf("未找到元素 %d\n", target);
}
// 删除元素
int deleteValue = 2;
deleteElement(&head, deleteValue);
printf("删除元素 %d 后的单链表内容:", deleteValue);
printLinkedList(head);
// 插入元素
int insertPosition = 2;
int insertValue = 6;
insertElement(&head, insertPosition, insertValue);
printf("在位置 %d 插入元素 %d 后的单链表内容:", insertPosition, insertValue);
printLinkedList(head);
// 释放单链表内存
freeLinkedList(head);
return 0;
}
期末复习1:
1. createLinkedList:尾插法建立单链表
根据传入的数组和大小,依次创建新节点,并使用尾插法插入到链表中。同时记录头结点和尾结点的地址,并将头结点地址返回。
2. findElement:查找元素在单链表中的位置
从头结点开始遍历链表,如果当前节点的数据等于目标值,则返回该节点在链表中的位置;否则继续遍历下一个节点。如果遍历到链表末尾都未找到目标值,则返回 -1。
3. deleteElement:删除单链表中的指定元素
传入头结点指针的地址,以便在删除头节点时可以修改头结点的值。首先判断头节点是否为目标元素,如果是则删除头结点并返回;否则从头节点开始遍历链表,找到目标元素位置的前一个节点和目标元素节点,然后将前一个节点的 next 指针指向下一个节点,最后释放目标元素节点的内存空间。
4. insertElement:在单链表的指定位置插入元素
传入头结点指针的地址、插入位置和插入值。如果插入位置是第一个节点,则需要修改头结点的指针,否则需要遍历链表寻找插入位置的前一个节点,然后将新节点插入到该位置之后。
5. printLinkedList:打印单链表
从头节点开始遍历链表,并依次输出节点的数据值,直到链表末尾。
6. freeLinkedList:释放单链表内存
传入头结点的地址,然后从头节点开始遍历链表,依次释放每个节点的内存空间。同时将头结点指向 NULL,以免出现野指针问题。
2、分别创建两个有序的顺序表(每个表的元素个数及每个元素的值在运行时由键盘输入),现将两个有序表合并,并保证新表依然为有序的顺序表。
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 100
typedef struct {
int data[MAX_SIZE];
int length;
} SqList;
// 创建有序顺序表
void createSqList(SqList *list) {
printf("请输入顺序表元素个数:");
scanf("%d", &(list->length));
printf("请输入顺序表元素(从小到大排序):");
for (int i = 0; i < list->length; i++) {
scanf("%d", &(list->data[i]));
}
}
// 合并两个有序顺序表
SqList mergeSqLists(SqList list1, SqList list2) {
SqList mergedList;
int i = 0, j = 0, k = 0;
while (i < list1.length && j < list2.length) {
if (list1.data[i] <= list2.data[j]) {
mergedList.data[k++] = list1.data[i++];
} else {
mergedList.data[k++] = list2.data[j++];
}
}
while (i < list1.length) {
mergedList.data[k++] = list1.data[i++];
}
while (j < list2.length) {
mergedList.data[k++] = list2.data[j++];
}
mergedList.length = k;
return mergedList;
}
// 打印顺序表
void printSqList(SqList list) {
printf("合并后有序顺序表:");
for (int i = 0; i < list.length; i++) {
printf("%d ", list.data[i]);
}
printf("\n");
}
int main() {
SqList list1, list2, mergedList;
printf("创建第一个有序顺序表:\n");
createSqList(&list1);
printf("创建第二个有序顺序表:\n");
createSqList(&list2);
mergedList = mergeSqLists(list1, list2);
printSqList(mergedList);
return 0;
}
逻辑简单
思考题(括号内为摘要)
1、如何理解“顺序存储同时支持随机存取和顺序存取,而链式存储只支持顺序存取”?
答:顺序存储是将数据元素按照其逻辑关系依次存放在一块连续的内存空间中。由于数据元素在内存中的物理位置是连续的,所以可以直接通过元素的下标进行随机存取,即可以根据元素的位置快速地访问和修改数据。这种存储方式能够支持随机存取,即可以通过元素的索引直接访问到指定位置的元素。同时,也可以按照顺序依次遍历数据元素,即支持顺序存取。
链式存储则是将数据元素存储在独立的节点中,并且通过指针将这些节点连接起来形成一个链表结构。每个节点保存了数据元素本身的值以及指向下一个节点的指针。由于节点之间的连接关系是通过指针实现的,所以链式存储不要求数据元素在内存中的物理位置是连续的。对于链式存储,只能从头节点开始顺序遍历链表,依次访问每个节点,因此只支持顺序存取。(顺序存储是将数据元素按照其逻辑关系依次存放在连续的内存空间中,支持随机访问和修改数据,也可以按顺序遍历。链式存储是通过节点之间的指针连接来存储数据元素,不要求内存中的物理位置连续,只能顺序遍历访问链表中的节点。)
2.保证时间复杂度为O(n),如何将单链表原地(即不另外申请新的结点)翻转,简述算法思想。
答:将单链表原地翻转的算法思想是迭代法,其基本思路是从头节点开始,依次将每个节点的 next 指针反转指向其前一个节点,最终完成整个链表的翻转,同时需要特别处理好头节点和尾节点。
具体实现步骤如下:
定义三个指针变量:cur、pre、next,分别表示当前节点、该节点的前一个节点以及该节点的后一个节点。初始化时,将cur指向头节点,而pre和next都置为null。依次遍历单链表,当cur不为null时,执行以下操作:记录cur的下一个节点为next;将cur的next指针指向pre;更新pre为当前节点cur,更新cur为下一个节点next。最后,由于翻转后原来的尾节点变成了翻转后的头节点,需要将原来的头节点的指针指向null。(单链表原地翻转的迭代法基本思路是从头节点开始,将每个节点的 next 指针反转指向其前一个节点,最终完成整个链表的翻转。具体实现步骤包括定义三个指针变量:cur、pre、next,初始化时,将cur指向头节点,而pre和next都置为null。遍历单链表,当cur不为null时,记录cur的下一个节点为next;将cur的next指针指向pre;更新pre为当前节点cur,更新cur为下一个节点next。最后,将原来的头节点的指针指向 null。)