IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 应用-单向链表-数据结构和算法 -> 正文阅读

[数据结构与算法]应用-单向链表-数据结构和算法

1 单向链表反转

  • 需求:原链表数据1->2->3->4,反转之后链表中的数据4->3->2->1。效果图示,在这里插入图片描述

  • 思路:

    1. 非递归:从第一个节点开始遍历链表,记录前一个节点,当前节点,后一个节点;把当前节点的next指针指向前一个节点,指针后移,直到链表结尾,交换头指针和尾指针,整个链表反转完成。
      • 指针后移指当前节点指针赋值给前一个节点指针,后一个指针节点赋值给当前节点,后一个节点指针.next赋值给后一个节点指针
    2. 递归实现:从第一个节点开始,依次递归调用反转每一个节点直到最后一个节点既原尾节点现在的头结点,整个链表反转完成。
  • 思路2递归实现

    • API:把下面2个方法放入我们前面实现的单向链表中

      • public void reverse():反转整个链表
      • public Node reverse(Noce curr):反转当前节点
    • 代码:

      /**
       * 反转单向链表
       */
      public void reverse() {
          if (size == 0 || size == 1) {
              return;
          }
          // 递归反转
          reverseRecursion(first);
          // 交换头尾指针
          Node<E> n = first;
          first = last;
          last = n;
      }
      
      private Node<E> reverseRecursion(Node<E> curr) {
          if (curr.next == null) {
              return curr;
          }
          Node<E> pre = reverseRecursion(curr.next);
          pre.next = curr;
          curr.next = null;
          return curr;
      }
      
    • 测试:

      ===反转前====
      [1, 2, 3, 4]
      ===反转后====
      [4, 3, 2, 1]
      
  • 非递归实现

    • 代码:

      /**
           * 单向链表反转非递归实现
           */
          public void reverse() {
              if (size == 0 || size == 1) {
                  return;
              }
              //
              Node<E> pre = null;
              Node<E> curr = first;
              Node<E> next = first.next;
              while (curr != null) {
                  curr.next = pre;
                  if (next == null) {
                      break;
                  }
                  pre = curr;
                  curr = next;
                  next = next.next;
              }
              // 交换头尾指针
              Node<E> n = first;
              first = last;
              last = n;
          }
      
    • 测试:

      ===反转前====
      [1, 2, 3, 4]
      ===反转后====
      [4, 3, 2, 1]
      

2 快慢指针

快慢指针指的就是定义两个指针,这两个指针的移动速度一块一慢,快慢指针之间的差值可以让我们找到链表中的相应节点。一般情况下,快指针的移动步长为慢指针的两倍。

2.1 中间值问题

利用快慢指针查找链表中间节点。

原理:快慢指针初始位置为链表头,快指针移动步长2倍于慢指针,当快指针移动到链表末尾的时候,慢指针刚好移动到链表中间位置。

链表有7个节点,分别存储字符串aa,bb,cc,dd,ee,ff,gg,蓝色表示慢指针,每次移动一个节点位置;绿色表示快指针,每次移动2个节点位置,当绿色指针移动到链表结尾时,蓝色节点刚好移动到中间节点位置dd处。如图2.1-1所有:在这里插入图片描述

用代码模拟实现,代码2.1-1如下:

public class FastSlowPointerTest {

    public static void main(String[] args) {
        // 创建链表
        Node<String> seven = new Node<>("gg", null);
        Node<String> six = new Node<>("ff", seven);
        Node<String> five = new Node<>("ee", six);
        Node<String> four = new Node<>("dd", five);
        Node<String> three = new Node<>("cc", four);
        Node<String> two = new Node<>("bb", three);
        Node<String> one = new Node<>("aa", two);
        // 获取中间节点的值
        System.out.println(getMid(one));

    }

    /**
     * 获取中间节点元素
     * @param first     头结点
     * @return          中间节点元素值
     */
    public static String getMid(Node<String> first) {
        // 定义快慢指针
        Node<String> fast = first;
        Node<String> slow = first;

        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            if (fast == null) {
                break;
            }
            slow = slow.next;
        }
        return slow.item;
    }

    /**
     * 节点类
     */
    private static class Node<E> {
        E item;
        Node<E> next;

        public Node(E item, Node<E> next) {
            this.item = item;
            this.next = next;
        }
    }
}

2.2 单向链表是否有环

无环链表,前一节点指向后一节点,而后面节点不指向前面节点,如图2.2-1所示:在这里插入图片描述

有环链表,前一节点指向后一节点,且后面节点指向前面节点,如图2.2-2所示:在这里插入图片描述

快慢指针查找是否有环原理:快指针移动快,如有环路,当慢指针进入环路时,快指针已经在环路中,且快指针移动快,一直移动直至快慢指针相遇;如果没有环路,则快指针和慢指针不会相遇。

快慢指针查找环路图示2.2-3:在这里插入图片描述

用代码模拟实现,代码2.2-1如下:

public class LinkListCircuitTest {

    public static void main(String[] args) {
        // 创建链表
        Node<String> seven = new Node<>("gg", null);
        Node<String> six = new Node<>("ff", seven);
        Node<String> five = new Node<>("ee", six);
        Node<String> four = new Node<>("dd", five);
        Node<String> three = new Node<>("cc", four);
        Node<String> two = new Node<>("bb", three);
        Node<String> one = new Node<>("aa", two);
        // 环路
        seven.next = three;
        // 判断链表是否有环路
        System.out.println(isCircuit(one));

    }

    /**
     * 判断链表是否有环路
     * @param first     头结点
     * @return          是否是环路
     */
    public static boolean isCircuit(Node<String> first) {
        // 定义快慢指针
        Node<String> fast = first;
        Node<String> slow = first;

        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            if (fast == null) {
                break;
            }
            slow = slow.next;
            if (fast == slow) {
                return true;
            }
        }
        return false;
    }

    /**
     * 节点类
     */
    private static class Node<E> {
        E item;
        Node<E> next;

        public Node(E item, Node<E> next) {
            this.item = item;
            this.next = next;
        }
    }
}

2.3 有环链表入口

当检测的链表有环后,怎么找到入口呢?当快慢指针相遇时,这是重新设定一个新的指针指向链表的启点,且步长与慢指针一样为1,则慢指针与“新”指针相遇的地方就是环的入口。证明涉及数论的知识,本人还没有学,略过。

代码实现如下:

public static Node<String> getEntrance(Node<String> first) {
    // 定义快慢指针,临时指针
    Node<String> fast = first;
    Node<String> slow = first;
    Node<String> temp = null;
    // 遍历链表,先找的环(快慢指针相遇), 临时指针指向链表的启点,且步长与慢指针一样为1,则慢指针与临时指针相遇的地方就是环的入口
    while (fast != null && fast.next != null) {
        fast = fast.next.next;
        if (fast == null) {
            break;
        }
        slow = slow.next;
        if (fast == slow) {
            temp = first;
            continue;
        }
        if (temp != null) {
            temp = temp.next;
            if (temp == slow) {
                return slow;
            }
        }
    }
    return null;
}

测试代码同2.2一致

3 后记

? 如果小伙伴什么问题或者指教,欢迎交流。

?QQ:806797785

??源代码仓库地址:https://gitee.com/gaogzhen/algorithm

参考:

[1]黑马程序员.黑马程序员Java数据结构与java算法全套教程,数据结构+算法教程全资料发布,包含154张java数据结构图[CP/OL].p56~p60.

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-10-22 21:39:02  更:2022-10-22 21:40:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 19:29:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码