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

     

    It's a lonely road!!!
  • 相关阅读:
    js 比较日期的大小
    日历(从今天起后面的14天)
    数字转大写
    object对象进行深拷贝
    浏览器渲染机制
    t-5.倒计时(秒杀效果)--本地--服务器(待续)
    s-1.rem自适应
    t-3.跑马灯
    t-2.手机端简单轮播(无滑动效果)
    16.弹性布局
  • 原文地址:https://www.cnblogs.com/JunkingBoy/p/15248519.html
Copyright © 2020-2023  润新知