9.9单链表之链表反转

9.9单链表之链表反转

单链表反转的四种经典算法

  • 迭代反转链表

  • 递归反转链表

  • 头插法反转链表

  • 就地逆置法反转链表


主要示例的是:不带头节点的链表反转

链表反转图示图解:

起始链表:

反转后链表:

迭代反转链表

具体实现:

  • 设置三个指针,分别指向首元节点、首元节点直接前驱、首元节点后继--->beg、mid、end

  • 循环开始

  • 修改mid的指针域令其指向beg

  • 将三个指针整体向后移动一个节点

  • 循环重复。当end为空,更改mid指针域,跳出循环

  • 更改头指针位置

一个流程实现图示:

设置三个指针:

更改mid指针指向,整体向后移动一个节点:

最后一个节点:

迭代反转算法C语言的实现:

/*
1、head为无头节点链表的头指针
*/
Link * iterator_reverse(Link * head){
   //判断头指针是否有指向首元节点
   if (head==NULL||head->next==NULL)
  {
       //返回头指针
       return head;
  }
   else {
       //设置三个指针--->beg、mid、end。分别指向首元节点前面的空节点、首元节点、首元节点的下一位
       Link * beg = NULL;
       Link * mid = head;
       Link * end = head->next;

       //循环执行
       while (true)
      {
           //修改mid指针域指向前一个指针
           mid->next = beg;
           //判断end是否为空--->mid是否是在最后一个节点了
           if (end == NULL)
          {
               //结束循环
               break;
          }
           //三个数整体向后移动一个节点
           beg = mid;
           mid = end;
           end = end->next;
      }
       //修改head头指针的指向,指向mid
       head = mid;
       //返回头指针--->用于找到链表
       return head;
  }
}

递归反转链表

本质:

  • 如果把NULL看成一个变量相当于把NULL这个变量从最后移动到首元节点之前

具体实现:

  • 通过判断头节点和头节点的指针域是否为空决定是否返回头节点

  • 通过递归的方式找到最后一个节点,此时会返回头节点并且创建新的数据域节点

  • 第一次开始进行NULL反转的时候起始位置是在倒数第二个节点,创建的临时节点是指针域

  • 让指针域的下一位指向自身,自身的指针域指向NULL--->这样结束的时候就会递归执行

递归反转实现流程:

指针域表示为 NULL

递归找到最后一个节点:

从倒数第二个节点开始创建新的预留节点:

一直递归重复到首元节点:

递归反转算法C语言实现:

Link * recusive_reverse(Link * head){
   //判断递归返回的节点是否是最后一个节点
   if (head == NULL || head->next == NULL)
  {
       //返回头节点
       return head;
  }
   else
  {
       //一直创建新节点
       Link * new_head = (Link*)malloc(sizeof(Link));

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

       //每退出一层改变head指针域的下一位的指向和head指针的指针域置空
       head->next->next = head;
       head->next = NULL;
       //返回新节点
       return new_head;
  }
}
/*
head 由节点 1 进入递归,此时 head 的指向又返回到节点 1,整个递归过程结束。
新反转链表的头指针为 new_head。
*/

头插法反转链表

具体实现:

  • 声明一个新的节点,形参传入原链表

  • 当原链表为空时候结束方法

  • 开始循环

  • 摘取原链表的首元节点,接到新链表上

  • 重复循环

头插法实现流程:

新建一个链表:

取原链表第一个节点放入新链表中:

直到最后:

头插法反转链表算法C语言实现:

/*
1、新建一个链表
2、取出原链表的首元节点放入新链表
3、循环执行步骤
*/
Link * head_reverse(Link * head){
   /*新建链表头指针*/
   Link * new_head = NULL;
   /*定义存储原链表的临时节点*/
   Link * temp = NULL;
   //判断结束方法条件
   if (head == NULL || head->next == NULL)
  {
       //结束方法,返回head链表
       return head;
  }
   //如果head不为空,进入循环(为什么不是head->next)
   while (head!=NULL)
  {
       //临时节点存储首元节点
       temp = head;
       //将head变成head的数据域指针--->需要将head的指针域复制给head所以不能是head->next为空
       head = head->next;
       //temp插入到新建链表的头部--->因为是插入到头部所以temp->next=new_head
       temp->next = new_head;
       new_head = temp; //起始这个是new_head->elem = temp
  }
   //最后返回new_head
   return new_head;
}

就地逆置法反转链表

具体实现:

  • 设置两个指针,分别指向首元节点和第二个节点

  • 将第二个节点从链表上删除并且添加到链表头部

    • 先删除节点--->->next->next

    • 再更改摘下来的节点的指针域指向beg

  • 交换endhead的位置

  • 调整end位置,让他指向当前的beg节点的下一个节点

就地逆置法反转链表C语言实现:

/*
1、创建两个指针
2、删除第二个节点
3、将第二个节点的指针域指向第一个节点
4、将第一个节点的指针域名指向第三个节点
5、更改数据域
6、循环操作
*/
Link * local_reverse(Link * head)
{
   //创建两个空指针
   Link * beg;
   Link * end;
   //判断返回情况
   if (head == NULL || head->next == NULL)
  {
       //返回链表自身
       return head;
  }
   //令空指针指向首元节点和第二个节点
   beg = head;
   end = head->next;
   //当end不为空--->指针域不为空(没到最后一位的时候)
   while (end!=NULL)
  {
       //摘除end
       beg->next = end->next; //相当于是head->next->next
       //更改end的指针域指向链表头
       end->next = head; //不能写beg因为如果写了beg那么beg将会是常量
       //交换head和end的位置
       head = end;
       //调整end位置,让他指向当前的beg节点的下一个节点
       end = beg->next;
  }
   //返回head节点
   return head;
}

 

posted @ 2021-09-09 19:31  俊king  阅读(133)  评论(0编辑  收藏  举报