链表逆序用哨兵位头节点

在C语言中实现链表的逆序,使用哨兵头节点是一种常见的做法。哨兵头节点可以简化代码逻辑,特别是当链表为空时,可以避免空指针异常。下面是一个使用哨兵头节点逆序单链表的C语言实现

示例:

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

// 定义链表节点结构体
typedef struct ListNode {
    int val;
    struct ListNode *next;
} ListNode;

// 创建新节点
ListNode* createNode(int value) {
    ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
    if (!newNode) {
        exit(-1); // 分配内存失败,退出程序
    }
    newNode->val = value;
    newNode->next = NULL;
    return newNode;
}

// 逆序链表,使用哨兵头节点
void reverseList(ListNode** headRef) {
    ListNode* prev = NULL;
    ListNode* current = *headRef;
    ListNode* next = NULL;

    while (current != NULL) {
        next = current->next;  // 保存下一个节点
        current->next = prev;  // 当前节点指向前一个节点,实现逆序
        prev = current;        // 前一个节点移动到当前节点
        current = next;        // 当前节点移动到下一个节点
    }
    *headRef = prev;  // 更新头节点
}

// 打印链表
void printList(ListNode* head) {
    ListNode* temp = head;
    while (temp != NULL) {
        printf("%d ", temp->val);
        temp = temp->next;
    }
    printf("\n");
}

// 主函数,测试逆序链表功能
int main() {
    ListNode* head = createNode(1);
    head->next = createNode(2);
    head->next->next = createNode(3);
    head->next->next->next = createNode(4);
    
    printf("原始链表:");
    printList(head);

    reverseList(&head);
    
    printf("逆序后链表:");
    printList(head);
    
    // 释放链表内存
    ListNode* temp;
    while (head != NULL) {
        temp = head;
        head = head->next;
        free(temp);
    }
    
    return 0;
}

在这个代码中,我们首先定义了链表节点的结构体ListNode,然后提供了创建新节点的函数createNodereverseList函数用来逆序链表,它使用了一个哨兵头节点,即第一个节点作为prev指针的初始位置,最后将头节点更新为prev指针所指向的节点。printList函数用来打印链表的节点值。

main函数中,我们创建了一个简单的链表,并调用reverseList函数进行逆序,然后打印出逆序后的结果。最后,我们释放了链表占用的内存。

请注意,在实际的项目开发中,还需要对代码进行适当的错误处理和边界条件检查,以确保程序的健壮性。

在C语言中,使用哨兵位头节点(dummy head)来逆序链表是一种常见的技巧,因为它可以简化边界条件的处理。以下是一个使用哨兵位头节点逆序单链表的示例代码:

// 链表节点的结构体定义

cpp 复制代码
typedef struct ListNode {
    int val;
    struct ListNode *next;
} ListNode;

// 创建一个新的链表节点

cpp 复制代码
ListNode* createNode(int value) {
    ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
    if (!newNode) {
        exit(-1); // 分配内存失败,退出程序
    }
    newNode->val = value;
    newNode->next = NULL;
    return newNode;
}

// 在链表的末尾添加一个新节点

cpp 复制代码
void appendNode(ListNode** headRef, int value) {
    ListNode* newNode = createNode(value);
    ListNode* temp = *headRef;
    
    if (temp == NULL) {
        *headRef = newNode;
        return;
    }
    
    while (temp->next != NULL) {
        temp = temp->next;
    }
    
    temp->next = newNode;
}

// 逆序链表,使用哨兵位头节点

cpp 复制代码
void reverseList(ListNode** headRef) {
    ListNode* prev = NULL;
    ListNode* current = *headRef;
    ListNode* next = NULL;
    
    while (current != NULL) {
        next = current->next;  // 保存下一个节点
        current->next = prev;  // 当前节点指向前一个节点
        prev = current;        // 前一个节点移动到当前节点
        current = next;        // 当前节点移动到下一个节点
    }
    *headRef = prev;  // 更新头节点
}

// 打印链表

cpp 复制代码
void printList(ListNode* head) {
    ListNode* temp = head;
    while (temp != NULL) {
        printf("%d ", temp->val);
        temp = temp->next;
    }
    printf("\n");
}

// 主函数,测试逆序链表功能

cpp 复制代码
int main() {
    ListNode* head = NULL; // 哨兵位头节点
    
    // 向链表中添加元素
    appendNode(&head, 1);
    appendNode(&head, 2);
    appendNode(&head, 3);
    appendNode(&head, 4);
    
    printf("原始链表:");
    printList(head);
    
    // 逆序链表
    reverseList(&head);
    
    printf("逆序后链表:");
    printList(head);
    
    // 释放链表内存
    ListNode* temp;
    while (head != NULL) {
        temp = head;
        head = head->next;
        free(temp);
    }
    
    return 0;
}

总代码

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

// 链表节点的结构体定义
typedef struct ListNode {
    int val;
    struct ListNode *next;
} ListNode;

// 创建一个新的链表节点
ListNode* createNode(int value) {
    ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
    if (!newNode) {
        exit(-1); // 分配内存失败,退出程序
    }
    newNode->val = value;
    newNode->next = NULL;
    return newNode;
}

// 在链表的末尾添加一个新节点
void appendNode(ListNode** headRef, int value) {
    ListNode* newNode = createNode(value);
    ListNode* temp = *headRef;
    
    if (temp == NULL) {
        *headRef = newNode;
        return;
    }
    
    while (temp->next != NULL) {
        temp = temp->next;
    }
    
    temp->next = newNode;
}

// 逆序链表,使用哨兵位头节点
void reverseList(ListNode** headRef) {
    ListNode* prev = NULL;
    ListNode* current = *headRef;
    ListNode* next = NULL;
    
    while (current != NULL) {
        next = current->next;  // 保存下一个节点
        current->next = prev;  // 当前节点指向前一个节点
        prev = current;        // 前一个节点移动到当前节点
        current = next;        // 当前节点移动到下一个节点
    }
    *headRef = prev;  // 更新头节点
}

// 打印链表
void printList(ListNode* head) {
    ListNode* temp = head;
    while (temp != NULL) {
        printf("%d ", temp->val);
        temp = temp->next;
    }
    printf("\n");
}

// 主函数,测试逆序链表功能
int main() {
    ListNode* head = NULL; // 哨兵位头节点
    
    // 向链表中添加元素
    appendNode(&head, 1);
    appendNode(&head, 2);
    appendNode(&head, 3);
    appendNode(&head, 4);
    
    printf("原始链表:");
    printList(head);
    
    // 逆序链表
    reverseList(&head);
    
    printf("逆序后链表:");
    printList(head);
    
    // 释放链表内存
    ListNode* temp;
    while (head != NULL) {
        temp = head;
        head = head->next;
        free(temp);
    }
    
    return 0;
}

在这个代码中,我们首先定义了链表节点的结构体ListNode。然后,我们提供了创建新节点和向链表末尾添加新节点的函数createNodeappendNodereverseList函数用来逆序链表,它使用了一个哨兵头节点prev,并最终将头节点更新为prev指针所指向的节点。printList函数用来打印链表的节点值。

main函数中,我们创建了一个链表,并调用reverseList函数进行逆序,然后打印出逆序后的结果。最后,我们释放了链表占用的内存。

请注意,在实际的项目开发中,还需要对代码进行适当的错误处理和边界条件检查,以确保程序的健壮性。

相关推荐
杜子不疼.7 分钟前
基于ATVC模板库的Ascend C Vector算子快速开发指南
c语言·开发语言·mfc
C++ 老炮儿的技术栈33 分钟前
Qt Creator中不写代如何设置 QLabel的颜色
c语言·开发语言·c++·qt·算法
艾莉丝努力练剑38 分钟前
【Linux:文件】基础IO
linux·运维·c语言·c++·人工智能·io·文件
you-_ling39 分钟前
IO编程相关知识
c语言·vscode
小龙报42 分钟前
【51单片机】深度解析 51 串口 UART:原理、配置、收发实现与工程化应用全总结
c语言·开发语言·c++·stm32·单片机·嵌入式硬件·51单片机
承渊政道1 小时前
C++学习之旅【C++中模板进阶内容介绍】
c语言·c++·笔记·学习·visual studio
浅念-1 小时前
C语言——动态内存管理
c语言·开发语言·c++·笔记·学习
学嵌入式的小杨同学9 小时前
【Linux 封神之路】信号编程全解析:从信号基础到 MP3 播放器实战(含核心 API 与避坑指南)
java·linux·c语言·开发语言·vscode·vim·ux
精彩极了吧10 小时前
C语言基本语法-自定义类型:结构体&联合体&枚举
c语言·开发语言·枚举·结构体·内存对齐·位段·联合
进击的小头12 小时前
实战案例:51单片机低功耗场景下的简易滤波实现
c语言·单片机·算法·51单片机