反转链表

245 阅读2分钟

给定单链表的头结点,反转链表,并返回反转后的链表

定义一个链表

struct Node {
  int data;
  struct Node *next;
};

创建链表

struct Node* constructList(void)
{
  // 头结点定义
  struct Node *head = NULL;
  // 记录当前尾结点
  struct Node *cur = NULL;

  for (int i = 1; i < 5; i++) {
    struct Node *node = malloc(sizeof(struct Node));
    node->data = i;

  // 头结点为空,新结点即为头结点
  if (head == NULL) {
    head = node;
  }
  // 当前结点的next为新结点
  else{
    cur->next = node;
  }

  // 设置当前结点为新结点
  cur = node;
  }

  return head;
}

打印链表

void printList(struct Node *head)
{
  struct Node* temp = head;
  while (temp != NULL) {
    printf("node is %d \n", temp->data);
    temp = temp->next;
  }
} 

反转链表(头插法)

在原有链表的基础上,依次将位于链表头部的结点取出,然后采用从头部插入的方式生成一个新链表,则此链表即为原链表的反转版。

struct Node* reverseList(struct Node *head)
{
  // 定义遍历指针,初始化为头结点
  struct Node *p = head;

  // 反转后的链表头部
  struct Node *newH = NULL;

  // 遍历链表
  while (p != NULL) {

    // 记录下一个结点
    struct Node *temp = p->next;
    // 当前结点的next指向新链表头部
    p->next = newH;
    // 更改新链表头部为当前结点
    newH = p;
    // 移动p指针
    p = temp;
  }

  // 返回反转后的链表头结点
  return newH;
}

反转链表(递归法)

递归法的实现思想是从链表的尾节点开始,依次向前遍历,遍历过程依次改变各节点的指向,即另其指向前一个节点

struct Node* reverseList(struct Node *head)
{
  //递归的出口
  if (head == NULL || head->next == NULL) { // 空链或只有一个结点,直接返回头指针
    return head;
  } else {
    //一直递归,找到链表中最后一个节点
    struct Node *newHead = reverseList(head->next);

    //当逐层退出时,new_head 的指向都不变,一直指向原链表中最后一个节点;
    //递归每退出一层,函数中 head 指针的指向都会发生改变,都指向上一个节点。

    //每退出一层,都需要改变 head->next 节点指针域的指向,同时令 head 所指节点的指针域为 NULL。
    head->next->next = head;
    head->next = NULL;
    //每一层递归结束,都要将新的头指针返回给上一层。由此,即可保证整个递归过程中,能够一直找得到新链表的表头。
    return newHead;
  }
}