笔记:数据结构(链表)

链表基本操作分解

链表是一种动态数据结构,它通过指针将一组零散的内存块串联起来。链表的基本操作包括初始化、插入、删除、查找、遍历和销毁等。以下是链表的基本操作分解,以单链表为例。

1. 链表的定义

复制代码
typedef struct Node {
    int data;           // 数据域,存储元素的值
    struct Node *next;  // 指针域,指向下一个结点
} Node;

typedef struct {
    Node *head;  // 头指针,指向链表的第一个结点
} LinkedList;

2. 链表的初始化

初始化链表,将头指针置为 NULL,表示链表为空。

复制代码
void InitList(LinkedList *L) {
    L->head = NULL;  // 头指针初始化为NULL
}

3. 链表的插入操作

(1)在链表头部插入元素
复制代码
void InsertAtHead(LinkedList *L, int e) {
    Node *newNode = (Node*)malloc(sizeof(Node));  // 创建新结点
    if (!newNode) {
        printf("Memory allocation failed.\n");
        return;
    }
    newNode->data = e;      // 设置新结点的数据域
    newNode->next = L->head; // 新结点的指针域指向原头结点
    L->head = newNode;      // 更新头指针
}
(2)在链表尾部插入元素
复制代码
void InsertAtTail(LinkedList *L, int e) {
    Node *newNode = (Node*)malloc(sizeof(Node));  // 创建新结点
    if (!newNode) {
        printf("Memory allocation failed.\n");
        return;
    }
    newNode->data = e;  // 设置新结点的数据域
    newNode->next = NULL;  // 新结点的指针域置为NULL

    if (L->head == NULL) {  // 如果链表为空,新结点为头结点
        L->head = newNode;
    } else {
        Node *p = L->head;
        while (p->next != NULL) {  // 找到链表的最后一个结点
            p = p->next;
        }
        p->next = newNode;  // 将新结点插入链表尾部
    }
}
(3)在链表的第 i 个位置插入元素
复制代码
void InsertAtPosition(LinkedList *L, int i, int e) {
    if (i < 1) {
        printf("Invalid position.\n");
        return;
    }

    Node *newNode = (Node*)malloc(sizeof(Node));  // 创建新结点
    if (!newNode) {
        printf("Memory allocation failed.\n");
        return;
    }
    newNode->data = e;  // 设置新结点的数据域

    if (i == 1) {  // 如果插入位置是第一个结点
        newNode->next = L->head;
        L->head = newNode;
        return;
    }

    Node *p = L->head;
    for (int j = 1; j < i - 1 && p != NULL; j++) {  // 找到第 `i-1` 个结点
        p = p->next;
    }

    if (p == NULL) {  // 如果插入位置超出链表长度
        printf("Invalid position.\n");
        free(newNode);
        return;
    }

    newNode->next = p->next;  // 将新结点插入第 `i` 个位置
    p->next = newNode;
}

4. 链表的删除操作

(1)删除链表的第 i 个位置的元素
复制代码
void DeleteAtPosition(LinkedList *L, int i) {
    if (i < 1 || L->head == NULL) {
        printf("Invalid position or list is empty.\n");
        return;
    }

    if (i == 1) {  // 如果删除的是第一个结点
        Node *temp = L->head;
        L->head = L->head->next;
        free(temp);
        return;
    }

    Node *p = L->head;
    for (int j = 1; j < i - 1 && p != NULL; j++) {  // 找到第 `i-1` 个结点
        p = p->next;
    }

    if (p == NULL || p->next == NULL) {  // 如果删除位置超出链表长度
        printf("Invalid position.\n");
        return;
    }

    Node *temp = p->next;  // 临时指针指向要删除的结点
    p->next = temp->next;  // 将第 `i-1` 个结点的指针域指向第 `i+1` 个结点
    free(temp);  // 释放删除结点的内存
}
(2)删除链表中值为 e 的第一个元素
复制代码
void DeleteByValue(LinkedList *L, int e) {
    if (L->head == NULL) {
        printf("List is empty.\n");
        return;
    }

    if (L->head->data == e) {  // 如果删除的是第一个结点
        Node *temp = L->head;
        L->head = L->head->next;
        free(temp);
        return;
    }

    Node *p = L->head;
    while (p->next != NULL && p->next->data != e) {  // 找到值为 `e` 的结点的前驱结点
        p = p->next;
    }

    if (p->next == NULL) {  // 如果未找到值为 `e` 的结点
        printf("Element not found.\n");
        return;
    }

    Node *temp = p->next;  // 临时指针指向要删除的结点
    p->next = temp->next;  // 将前驱结点的指针域指向删除结点的下一个结点
    free(temp);  // 释放删除结点的内存
}

5. 链表的查找操作

查找链表中值为 e 的第一个结点,并返回其位置。

复制代码
int LocateElem(LinkedList *L, int e) {
    Node *p = L->head;
    int pos = 1;
    while (p != NULL) {  // 遍历链表
        if (p->data == e) {  // 找到值为 `e` 的结点
            return pos;  // 返回结点的位置
        }
        p = p->next;
        pos++;
    }
    return -1;  // 未找到返回 -1
}

6. 链表的遍历操作

遍历链表并打印所有元素。

复制代码
void PrintList(LinkedList *L) {
    Node *p = L->head;
    if (p == NULL) {
        printf("List is empty.\n");
        return;
    }
    printf("List: ");
    while (p != NULL) {  // 遍历链表
        printf("%d ", p->data);  // 打印结点的值
        p = p->next;
    }
    printf("\n");
}

7. 链表的销毁操作

释放链表中所有结点的内存。

复制代码
void DestroyList(LinkedList *L) {
    Node *p = L->head;
    while (p != NULL) {  // 遍历链表
        Node *temp = p;  // 临时指针指向当前结点
        p = p->next;     // 指针指向下一个结点
        free(temp);      // 释放当前结点的内存
    }
    L->head = NULL;  // 头指针置为NULL
    printf("List destroyed.\n");
}

8. 示例代码

复制代码
int main() {
    LinkedList L;
    InitList(&L);  // 初始化链表

    InsertAtHead(&L, 10);  // 在头部插入10
    InsertAtTail(&L, 20);  // 在尾部插入20
    InsertAtPosition(&L, 2, 15);  // 在第2个位置插入15

    PrintList(&L);  // 输出: List: 10 15 20

    DeleteAtPosition(&L, 2);  // 删除第2个位置的元素
    PrintList(&L);  // 输出: List: 10 20

    DeleteByValue(&L, 20);  // 删除值为20的元素
    PrintList(&L);  // 输出: List: 10

    int pos = LocateElem(&L, 10);  // 查找值为10的元素
    printf("Element 10 is at position: %d\n", pos);  // 输出: Element 10 is at position: 1

    DestroyList(&L);  // 销毁链表

    return 0;
}

9. 总结

链表的基本操作包括初始化、插入、删除、查找、遍历和销毁。链表的优点是插入和删除操作高效,缺点是访问元素需要遍历链表。通过掌握链表的基本操作,可以更好地理解链表的实现原理和应用场景。

相关推荐
xiaoyuchidayuma1 小时前
【# 电压极限圆、电流极限圆、MTPA曲线、最大功率曲线的关系】
笔记·学习
五哈俱乐部1 小时前
TCHouse-C分布式表创建指南
笔记
问君能有几多愁~9 小时前
C++ 数据结构复习笔记
数据结构·c++·笔记
至乐活着10 小时前
深入解析跳表SkipList:原理、实现与性能优化实战
数据结构·算法·跳表·skiplist·java实现
r_oo_ki_e_10 小时前
Java Map 集合学习笔记
java·笔记·学习
liuyicenysabel12 小时前
大模型学习笔记 · 第八篇 · 进阶:偏好对齐与多卡训练
人工智能·笔记·学习
fpcc14 小时前
数据结构—表
数据结构
Funing714 小时前
FreeRTOS学习day1:Keil 工程配置与 FreeRTOS 链表机制理解
数据结构·学习·链表
番茄育学园15 小时前
我的三款主流云存储音乐库实测笔记
笔记·分类·媒体