数据结构:链表-单向链表篇

链表,它由一系列节点(结构体) 组成,每个节点包含数据字段和指针 ,节点和节点之间通过指针连接在一起。与数组不同,链表中的元素在内存中不是连续存储的,而是通过指针连接在一起。

cpp 复制代码
// 单向链表节点定义
struct Node {
    int data;           // 数据字段
    struct Node* next;  // 指向下一个节点的指针
};

单向链表

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

// 定义链表节点结构
struct Node {
    int data;
    struct Node* next;
};

// 创建新节点的函数
struct Node* createNode(int data) {
    // 分配内存
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    
    // 检查内存分配是否成功
    if (newNode == NULL) {
        printf("内存分配失败!\n");
        exit(1);
    }
    
    // 初始化节点数据
    newNode->data = data;
    newNode->next = NULL;
    
    return newNode;
}

在链表头部插入节点

cpp 复制代码
// 在链表头部插入节点
struct Node* insertAtBeginning(struct Node* head, int data) {
    // 创建新节点
    struct Node* newNode = createNode(data);
    
    // 将新节点的next指向当前的头节点
    newNode->next = head;
    
    // 更新头节点为新节点
    return newNode;
}

在链表尾部插入节点

cpp 复制代码
// 在链表尾部插入节点
struct Node* insertAtEnd(struct Node* head, int data) {
    // 创建新节点
    struct Node* newNode = createNode(data);
    
    // 如果链表为空,新节点就是头节点
    if (head == NULL) {
        return newNode;
    }
    
    // 找到链表的最后一个节点
    struct Node* current = head;
    while (current->next != NULL) {
        current = current->next;
    }
    
    // 将最后一个节点的next指向新节点
    current->next = newNode;
    
    // 返回头节点
    return head;
}

在指定位置插入节点

cpp 复制代码
// 在指定位置插入节点
struct Node* insertAtPosition(struct Node* head, int data, int position) {
    // 如果位置是1,相当于在头部插入
    if (position == 1) {
        return insertAtBeginning(head, data);
    }
    
    // 创建新节点
    struct Node* newNode = createNode(data);
    
    // 找到要插入位置的前一个节点
    struct Node* current = head;
    for (int i = 1; i < position - 1 && current != NULL; i++) {
        current = current->next;
    }
    
    // 检查位置是否有效
    if (current == NULL) {
        printf("位置无效!\n");
        free(newNode);
        return head;
    }
    
    // 插入新节点
    newNode->next = current->next;
    current->next = newNode;
    
    return head;
}

删除节点

cpp 复制代码
// 删除指定值的第一个节点
struct Node* deleteNode(struct Node* head, int key) {
    // 如果链表为空,直接返回
    if (head == NULL) {
        return NULL;
    }
    
    // 如果头节点就是要删除的节点
    if (head->data == key) {
        struct Node* temp = head;
        head = head->next;
        free(temp);
        return head;
    }
    
    // 查找要删除的节点
    struct Node* current = head;
    while (current->next != NULL && current->next->data != key) {
        current = current->next;
    }
    
    // 如果找到了要删除的节点
    if (current->next != NULL) {
        struct Node* temp = current->next;
        current->next = temp->next;
        free(temp);
    }
    
    return head;
}

查找节点

cpp 复制代码
// 查找指定值的节点
struct Node* searchNode(struct Node* head, int key) {
    struct Node* current = head;
    
    // 遍历链表
    while (current != NULL) {
        if (current->data == key) {
            return current;  // 找到节点,返回指针
        }
        current = current->next;
    }
    
    return NULL;  // 未找到节点
}

打印链表

cpp 复制代码
// 打印链表的所有节点
void printList(struct Node* head) {
    struct Node* current = head;
    
    printf("链表内容: ");
    while (current != NULL) {
        printf("%d -> ", current->data);
        current = current->next;
    }
    printf("NULL\n");
}

释放链表

cpp 复制代码
// 释放链表的所有节点
void freeList(struct Node* head) {
    struct Node* current = head;
    struct Node* next;
    
    while (current != NULL) {
        next = current->next;  // 保存下一个节点
        free(current);         // 释放当前节点
        current = next;        // 移动到下一个节点
    }
}
cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

// 定义链表节点结构
struct Node {
    int data;
    struct Node* next;
};

// 创建新节点
struct Node* createNode(int data) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    if (newNode == NULL) {
        printf("内存分配失败!\n");
        exit(1);
    }
    newNode->data = data;
    newNode->next = NULL;
    return newNode;
}

// 在链表头部插入节点
struct Node* insertAtBeginning(struct Node* head, int data) {
    struct Node* newNode = createNode(data);
    newNode->next = head;
    return newNode;
}

// 在链表尾部插入节点
struct Node* insertAtEnd(struct Node* head, int data) {
    struct Node* newNode = createNode(data);
    
    if (head == NULL) {
        return newNode;
    }
    
    struct Node* current = head;
    while (current->next != NULL) {
        current = current->next;
    }
    
    current->next = newNode;
    return head;
}

// 在指定位置插入节点
struct Node* insertAtPosition(struct Node* head, int data, int position) {
    if (position == 1) {
        return insertAtBeginning(head, data);
    }
    
    struct Node* newNode = createNode(data);
    
    struct Node* current = head;
    for (int i = 1; i < position - 1 && current != NULL; i++) {
        current = current->next;
    }
    
    if (current == NULL) {
        printf("位置无效!\n");
        free(newNode);
        return head;
    }
    
    newNode->next = current->next;
    current->next = newNode;
    
    return head;
}

// 删除指定值的第一个节点
struct Node* deleteNode(struct Node* head, int key) {
    if (head == NULL) {
        return NULL;
    }
    
    if (head->data == key) {
        struct Node* temp = head;
        head = head->next;
        free(temp);
        return head;
    }
    
    struct Node* current = head;
    while (current->next != NULL && current->next->data != key) {
        current = current->next;
    }
    
    if (current->next != NULL) {
        struct Node* temp = current->next;
        current->next = temp->next;
        free(temp);
    }
    
    return head;
}

// 查找指定值的节点
struct Node* searchNode(struct Node* head, int key) {
    struct Node* current = head;
    
    while (current != NULL) {
        if (current->data == key) {
            return current;
        }
        current = current->next;
    }
    
    return NULL;
}

// 打印链表
void printList(struct Node* head) {
    struct Node* current = head;
    
    printf("链表内容: ");
    while (current != NULL) {
        printf("%d -> ", current->data);
        current = current->next;
    }
    printf("NULL\n");
}

// 释放链表
void freeList(struct Node* head) {
    struct Node* current = head;
    struct Node* next;
    
    while (current != NULL) {
        next = current->next;
        free(current);
        current = next;
    }
}

// 获取链表长度
int getLength(struct Node* head) {
    int count = 0;
    struct Node* current = head;
    
    while (current != NULL) {
        count++;
        current = current->next;
    }
    
    return count;
}

// 反转链表
struct Node* reverseList(struct Node* head) {
    struct Node* prev = NULL;
    struct Node* current = head;
    struct Node* next = NULL;
    
    while (current != NULL) {
        next = current->next;  // 保存下一个节点
        current->next = prev;  // 反转当前节点的指针
        prev = current;        // 移动prev指针
        current = next;        // 移动current指针
    }
    
    return prev;  // 新的头节点
}

int main() {
    struct Node* head = NULL;
    
    // 在链表尾部插入节点
    head = insertAtEnd(head, 10);
    head = insertAtEnd(head, 20);
    head = insertAtEnd(head, 30);
    
    printf("初始链表:\n");
    printList(head);
    
    // 在链表头部插入节点
    head = insertAtBeginning(head, 5);
    printf("\n在头部插入5后:\n");
    printList(head);
    
    // 在指定位置插入节点
    head = insertAtPosition(head, 15, 3);
    printf("\n在位置3插入15后:\n");
    printList(head);
    
    // 删除节点
    head = deleteNode(head, 20);
    printf("\n删除值为20的节点后:\n");
    printList(head);
    
    // 查找节点
    struct Node* found = searchNode(head, 15);
    if (found != NULL) {
        printf("\n找到值为15的节点\n");
    } else {
        printf("\n未找到值为15的节点\n");
    }
    
    // 获取链表长度
    printf("\n链表长度: %d\n", getLength(head));
    
    // 反转链表
    head = reverseList(head);
    printf("\n反转链表后:\n");
    printList(head);
    
    // 释放链表
    freeList(head);
    
    return 0;
}
相关推荐
vibecoding日记7 小时前
双非如何快速入职字节等大厂大模型?真实案例分析:推理优化和投机解码
算法·求职·大模型工程师
yszaygr21389 小时前
Verilog参数化游程编码RLE模块
算法
望易9 小时前
刚设计的大模型架构-双域耦合认知框架
算法·架构
复杂网络13 小时前
多个 Claude Code 与多个 Codex 协同工作:设计与实现方案
算法
HjhIron1 天前
面试常客:字符串算法从入门到进阶
算法·面试
吴佳浩1 天前
DeepSeek DSpark:Confidence-Scheduled Speculative Decoding 技术解析
人工智能·算法·deepseek
触底反弹1 天前
🧠 搞懂 Token,才算真正入门大模型——从分词原理到 Embedding 语义实战
javascript·人工智能·算法
vivo互联网技术1 天前
ICLR 2026 | 基于后验采样的图像恢复方法LearnIR:人脸去阴影、去雾
人工智能·算法·aigc
浮生望2 天前
JS字符串与回文算法:从包装类到双指针的面试进阶之路
javascript·算法
黄敬峰2 天前
面试必刷:从JS底层包装类到双指针,彻底搞懂字符串与回文算法
算法