反转链表和哨兵位

目录

法一

法2

法3(哨兵位头节点)

// 创建新节点

// 链表逆序

// ... 其他链表操作函数(如打印链表等)

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

简易的两种方法


在编程中,尤其是在处理数组或数据流时,“哨兵位”可以是一种特殊的值,用来标记某些条件或异常情况。例如,你可以在数组的第一个元素放置一个特殊的值,用来表示数组的结束或者某种特定的状态。

以下是一个简单的例子,展示了如何在C语言中使用“哨兵位”:

#include <stdio.h>

int main() {
    int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, -1}; // 假设-1用作哨兵值
    int n = sizeof(array) / sizeof(array[0]);
    int i;

    for (i = 0; array[i] != -1; i++) {
        // 处理数组中的每个元素,直到遇到哨兵值
        printf("%d ", array[i]);
    }

    printf("\n");
    return 0;
}

在这个例子中,数组的第一个元素被设置为-1,用作哨兵值。在循环中,我们检查当前元素是否等于哨兵值。如果等于,循环结束;否则,我们处理该元素。

这种方法常用于处理不确定长度的数据流,或者在数据处理过程中需要一个明确的结束标志的情况。通过使用哨兵位,你可以简化代码逻辑,避免使用复杂的状态变量或额外的数据结构。

法一

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* reverseList(struct ListNode* head)
{

    //法1
    //  if(head==NULL)
    // {
    //     return NULL;
    // }

    // struct ListNode*n1=NULL,*n2=head,*n3=NULL;
    // n1=NULL;
    // n2=head;
    // n3=n2->next; 
    // while(n2)
    // {
    //     n2->next=n1;
    //     n1=n2;
    //     n2=n3;
    //     if(n3!=NULL)
    //     {
    //         n3=n3->next;
    //     }
    // }
    // return n1;

法2

 //法二,画图
    struct ListNode*cur=NULL;
    struct ListNode*tail=head;
    while(tail)
    {
        struct ListNode*p=tail->next;
        tail->next=cur;
        cur=tail;
        tail=p;
    }
    return cur;

法3(哨兵位头节点)

在C语言中,链表逆序同样可以不使用哨兵位头节点,但使用哨兵位头节点可以简化某些边界情况的处理。以下我将分别展示两种方法的示例代码。不使用哨兵位头节点的链表逆序
 

#include <stdio.h>
#include <stdlib.h>

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

// 创建新节点

ListNode* createNode(int val) {
    ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
    if (!newNode) {
        return NULL;
    }
    newNode->val = val;
    newNode->next = NULL;
    return newNode;
}

// 链表逆序

ListNode* reverseList(ListNode* head) {
    ListNode *prev = NULL;
    ListNode *curr = head;
    ListNode *next = NULL;
    
    while (curr != NULL) {
        next = curr->next;  // 保存下一个节点
        curr->next = prev;  // 将当前节点的next指向前一个节点
        prev = curr;        // 移动prev到当前节点
        curr = next;        // 移动curr到下一个节点
    }
    
    // prev现在指向新的头节点
    return prev;
}

// ... 其他链表操作函数(如打印链表等)

int main() {
    // 构造链表:1 -> 2 -> 3 -> 4 -> 5
    ListNode *head = createNode(1);
    head->next = createNode(2);
    head->next->next = createNode(3);
    head->next->next->next = createNode(4);
    head->next->next->next->next = createNode(5);

    // 逆序链表
    head = reverseList(head);

    // ... 打印链表等操作

    return 0;
}

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

使用哨兵位头节点时,我们需要在链表的最前面添加一个额外的节点,并将它的next指针指向原始链表的头节点。逆序完成后,我们可以直接返回哨兵位头节点的next指针作为新链表的头节点。

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

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

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

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

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

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;
}

总代码

#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函数进行逆序,然后打印出逆序后的结果。最后,我们释放了链表占用的内存。

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

#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;
}


注意,在使用哨兵位头节点的示例中,我们不需要特别处理头节点为空的情况,因为哨兵位头节点始终存在。此外,在逆序过程中,我们还需要注意处理原链表的尾节点,因为当curr指向尾节点时,curr->next将为NULL,我们不需要再将其指向前一个节点。

简易的两种方法

// 方法1:使用三个指针
ListNode* reverseList(ListNode* head) {
    ListNode *prev = NULL;
    ListNode *current = head;
    ListNode *next_node = NULL;
    
    while (current != NULL) {
        next_node = current->next;
        current->next = prev;
        prev = current;
        current = next_node;
    }
    return prev;
}

// 方法2:使用哨兵位头节点
ListNode* reverseList2(ListNode* head) {
    ListNode dummy;
    dummy.next = head;
    ListNode *prev = &dummy;
    ListNode *current = head;
    
    while (current != NULL) {
        ListNode *next_node = current->next;
        current->next = prev->next;
        prev->next = current;
        current = next_node;
    }
    return dummy.next;
}

  • 55
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值