算法之链表反转

算法系列

1、链表反转

一、核心思路

现在有一个单向链表,链表的第一个节点指向第二个,第二个节点指向第三个,以此类推,组成一个链表,按理说这个链表能无限大,只要内存足够大。
什么是链表反转?就是把链表倒过来,最后一个节点变成了头节点,倒数第二个节点变成正序第二个,这样把整个链表进行反转过来。
那怎么实现呢,有两种方法,第一种是循环来操作链表进行反转,第二种是递归的方式进行反转。

二、循环反转

先看思路,请看下图:
循环反转链表

看图说话,思路是这样子的,循环遍历一遍链表,把链表的每一个节点指针指向前一个节点,再把下一个节点的 next 属性指向上一个节点。
这里我们需要借助两个变量,prevnext 来操作。

比如在第一次遍历的时候,当前的节点就是 1 这个节点,先把节点 1 的 next 属性存放到一个临时变量中;next = curr.next;

然后把节点 1 指向上一个节点(头结点没有上一个节点,则为 null);
curr.next = prev;

上一个节点此时是没有的(也就是一个null),所以需要给上一个节点指定节点,就是把当前的节点指到上一个节点;
prev = curr;

这时候当前节点就是下一个节点,下一个节点就是刚才的临时变量 next;
curr = next;

2.1 示例代码

实现代码如下:

代码中首先定义一个 Node 内部类,作为节点,节点里面是一个 int 值,和下一个节点 next,reverse() 方法用来实现列表的反转,main() 方法中定义 5 个节点,通过 reverse() 方法来反转。

	public class ReverseLinkedList {
    /**
     * 定义节点 Node
     */
    static class Node{
        public int value;
        public Node next;

        public Node(int value, Node next) {
            this.value = value;
            this.next = next;
        }
    }

    public static void main(String[] args) {
        Node node5 = new Node(5, null);
        Node node4 = new Node(4, node5);
        Node node3 = new Node(3, node4);
        Node node2 = new Node(2, node3);
        Node node1 = new Node(1, node2);
        Node curr = node1;
        while (curr != null){
            System.out.printf("%d -> ", curr.value);
            curr = curr.next;
        }
        curr = reverse(node1);
        System.out.println();
        System.out.println("反转后的链表:");
        while (curr != null){
            System.out.printf("%d -> ", curr.value);
            curr = curr.next;
        }
    }

    /**
     * 实现反转
     * @param curr 当前节点,传进来的是头结点
     * @return 返回是反转后的头结点
     */
    private static Node reverse(Node curr){
        Node prev = null, next;
        while (Objects.nonNull(curr)){
            //用临时变量保存当前的下一个
            next = curr.next;
            //把当前节点的 next 指向上一个节点
            curr.next = prev;
            //经过前两步操作,当前节点的 next 已经指向下一个了,指针往后移动,prev 变成当前节点
            prev = curr;
            //当前节点则指向刚才临时变量 next,也就是下一个节点
            curr = next;
        }
        return prev;
    }
}

测试结果:

1 -> 2 -> 3 -> 4 -> 5 -> 
反转后的链表:
5 -> 4 -> 3 -> 2 -> 1 -> 

三、递归反转

先看思路,请看下图:
递归反转

看图说话,思路是这样子的,感觉这个比循环反转简单,递归时如果节点中的 next 不为空,说明当前节点不是最后一个节点,则递归调用自己,传当前的 next 作为参数,知道当前节点的 next 为空则返回节点。

每次操作,如果当前节点的 next 是 null,则返回,否则继续调用并传参 curr.next,则当前节点是下一个节点;
Node curr = recurrence(head.next);

然后是当前节点的next 的 next 则指向当前节点;head.next.next = head;

到第一个节点是,前面再没有节点;head.next = null;

最终返回 当前节点;return curr;

3.1 示例代码

实现代码如下:

其他代码和上面一样,实现方法不一样,递归实现反转代码如下:

	private static Node recurrence(Node head){
        if(Objects.isNull(head.next) || Objects.isNull(head)){
            return head;
        }
        Node curr = recurrence(head.next);
        head.next.next = head;
        head.next = null;
        return curr;
    }

四、总结

算法是一种思想,是一种解决问题的方法,不限制任何工具和语言,多联系算法则在日常的工作中思路更多。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,以下是用C语言实现链表的代码示例: ```c #include <stdio.h> #include <stdlib.h> struct ListNode { int val; struct ListNode *next; }; struct ListNode* reverseList(struct ListNode* head) { struct ListNode* prev = NULL; struct ListNode* curr = head; struct ListNode* next = NULL; while (curr != NULL) { next = curr->next; curr->next = prev; prev = curr; curr = next; } return prev; } int main() { // 创建链表 1 -> 2 -> 3 -> 4 -> 5 struct ListNode* head = (struct ListNode*)malloc(sizeof(struct ListNode)); head->val = 1; head->next = (struct ListNode*)malloc(sizeof(struct ListNode)); head->next->val = 2; head->next->next = (struct ListNode*)malloc(sizeof(struct ListNode)); head->next->next->val = 3; head->next->next->next = (struct ListNode*)malloc(sizeof(struct ListNode)); head->next->next->next->val = 4; head->next->next->next->next = (struct ListNode*)malloc(sizeof(struct ListNode)); head->next->next->next->next->val = 5; head->next->next->next->next->next = NULL; // 输出原始链表 struct ListNode* node = head; while (node != NULL) { printf("%d ", node->val); node = node->next; } printf("\n"); // 链表 struct ListNode* newHead = reverseList(head); // 输出后的链表 node = newHead; while (node != NULL) { printf("%d ", node->val); node = node->next; } printf("\n"); return 0; } ``` 该代码中定义了一个链表结构体 ListNode,包含节点的值 val 和指向下一个节点的指针 next。实现了链表的函数 reverseList,采用迭代的方式,使用三个指针 prev、curr、next 分别表示前一个节点、当前节点和下一个节点,链表的过程就是不断地将 curr->next 指向 prev,然后更新三个指针的值。在 main 函数中创建了一个链表,然后输出原始链表后的链表。 ### 回答2: 链表是一种常见的链表操作,可以使用C语言来实现。 首先,我们需要定义链表的结构体节点: ```c struct ListNode { int val; // 节点的数值 struct ListNode *next; // 指向下一个节点的指针 }; ``` 然后,我们可以定义一个函数来实现链表: ```c struct ListNode* reverseList(struct ListNode* head) { struct ListNode *prev = NULL; // 指向前一个节点的指针 struct ListNode *curr = head; // 指向当前节点的指针 while (curr != NULL) { struct ListNode *nextNode = curr->next; // 暂存下一个节点的指针 curr->next = prev; // 将当前节点的指针指向前一个节点 prev = curr; // 更新前一个节点为当前节点 curr = nextNode; // 更新当前节点为下一个节点 } return prev; // 返回后的链表的头节点 } ``` 这个函数使用了迭代的方式进行链表。我们需要维护两个指针,一个指向前一个节点(初始为NULL),一个指向当前节点(初始为链表的头节点)。在遍历链表的过程中,每次都将当前节点的指针指向前一个节点,然后更新两个指针。最后,返回重置后的头节点。 如果要测试这个链表算法,可以调用以下代码: ```c #include <stdio.h> int main() { // 创建链表 struct ListNode *node1 = (struct ListNode*)malloc(sizeof(struct ListNode)); struct ListNode *node2 = (struct ListNode*)malloc(sizeof(struct ListNode)); struct ListNode *node3 = (struct ListNode*)malloc(sizeof(struct ListNode)); node1->val = 1; node2->val = 2; node3->val = 3; node1->next = node2; node2->next = node3; node3->next = NULL; // 打印原链表 struct ListNode *curr = node1; while (curr != NULL) { printf("%d ", curr->val); curr = curr->next; } printf("\n"); // 链表 struct ListNode *reversedHead = reverseList(node1); // 打印后的链表 curr = reversedHead; while (curr != NULL) { printf("%d ", curr->val); curr = curr->next; } printf("\n"); return 0; } ``` 这段代码创建了一个包含三个节点的链表,并分别设置节点的值。然后,调用 `reverseList` 函数对链表进行,并打印后的链表的值。 这就是使用C语言实现链表算法的方法。 ### 回答3: 链表是将一个链表中的节点顺序进行的操作。通过C语言,我们可以使用指针来实现这个算法。 下面是用C语言实现链表算法的示例代码: ```c #include <stdio.h> #include <stdlib.h> struct Node{ int data; struct Node* next; }; 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; current = next; } head = prev; return head; } void printList(struct Node* head){ struct Node* temp = head; while(temp != NULL){ printf("%d ", temp->data); temp = temp->next; } printf("\n"); } int main(){ struct Node* head = NULL; struct Node* second = NULL; struct Node* third = NULL; // 分配内存 head = (struct Node*)malloc(sizeof(struct Node)); second = (struct Node*)malloc(sizeof(struct Node)); third = (struct Node*)malloc(sizeof(struct Node)); // 赋值 head->data = 1; head->next = second; second->data = 2; second->next = third; third->data = 3; third->next = NULL; printf("原始链表: "); printList(head); head = reverseList(head); printf("后的链表: "); printList(head); return 0; } ``` 以上是链表算法的实现。我们使用了三个指针,prev指向当前节点的前一个节点,current指向当前节点,next指向当前节点的下一个节点。通过不断更新这三个指针的指向,并将当前节点的next指向前一个节点,最后返回后的头节点,即可完成链表操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值