数据结构与算法——单链表练习

本文涉及的产品
应用型负载均衡 ALB,每月750个小时 15LCU
传统型负载均衡 CLB,每月750个小时 15LCU
网络型负载均衡 NLB,每月750个小时 15LCU
简介: 前面的文章说到了一种很基础的数据结构——链表:数据结构与算法——链表,今天就来看看关于单链表的几种常见的操作,技术笔试的时候很大概率能够遇到其中的一些。多练习一下,对我们理解链表有很大的帮助,也能够提升我们的编码能力。废话不多说,这几个练习题是:• 单链表反转• 合并两个有序链表• 检测链表中的环• 删除链表倒数第 k 个节点• 找到链表的中间节点

1. 概述


前面的文章说到了一种很基础的数据结构——链表:数据结构与算法——链表,今天就来看看关于单链表的几种常见的操作,技术笔试的时候很大概率能够遇到其中的一些。多练习一下,对我们理解链表有很大的帮助,也能够提升我们的编码能力。

废话不多说,这几个练习题是:

  • 单链表反转
  • 合并两个有序链表
  • 检测链表中的环
  • 删除链表倒数第 k 个节点
  • 找到链表的中间节点


2. 单链表反转


单链表反转,顾名思义,就是将链表的指针指向全部倒过来,尾结点变成头节点,头节点变成尾结点。具体的代码如下:

public class SingleLinkedList {
    private Node head = null;//链表的头节点
    public Node reverse(Node node) {
        Node head = null;
        Node previous = null;
        Node current = node;
        while(current != null) {
            Node next = current.next; 
            if (next == null) {
                head = current;
            }
            current.next = previous;
            previous = current;
            current = next;
        }
        this.head = head;
        return this.head;
    }
}


3. 合并两个有序链表


假如链表中存储的数据是数值类型,并且是有序的,这时候可以合并两个有序的链表,主要涉及到两个链表元素的比较。代码如下:

 

//合并两个有序的链表
    public Node mergeSortedList(Node la, Node lb) {
        if(la == null && lb == null) return null;
        if(la == null) return lb;
        if(lb == null) return la;
        Node p = la;
        Node q = lb;
        Node head = null;
        //比较第一个元素
        if(p.getData() < q.getData()) {
            head = p;
            p = p.next;
        }else {
            head = q;
            q = q.next;
        }
        //比较后面的元素
        Node r = head;
        while(p != null && q != null) {
            if(p.getData() < q.getData()) {
                r.next = p;
                p = p.next;
            }else {
                r.next = q;
                q = q.next;
            }
            r = r.next;
        }
        //比较链表可能剩余的元素
        while(p != null) {
            r.next = p;
            p = p.next;
            r = r.next;
        }
        while(q != null) {
            r.next = q;
            q = q.next;
            r = r.next;
        }
        return head;
    }


4. 检测链表中的环


单链表中有可能存在像循环链表这样的环形结构,检测链表中是否有这样的结构,可以利用这样的思路:定义两个指针,一个指针每次移动两个节点,另一个指针移动一个节点,如果两个指针相遇,则说明存在环,代码如下:

//合并两个有序的链表
    public Node mergeSortedList(Node la, Node lb) {
        if(la == null && lb == null) return null;
        if(la == null) return lb;
        if(lb == null) return la;
        Node p = la;
        Node q = lb;
        Node head = null;
        //比较第一个元素
        if(p.getData() < q.getData()) {
            head = p;
            p = p.next;
        }else {
            head = q;
            q = q.next;
        }
        //比较后面的元素
        Node r = head;
        while(p != null && q != null) {
            if(p.getData() < q.getData()) {
                r.next = p;
                p = p.next;
            }else {
                r.next = q;
                q = q.next;
            }
            r = r.next;
        }
        //比较链表可能剩余的元素
        while(p != null) {
            r.next = p;
            p = p.next;
            r = r.next;
        }
        while(q != null) {
            r.next = q;
            q = q.next;
            r = r.next;
        }
        return head;
    }


5. 删除链表倒数第 k 个节点


这个题在笔试当中非常常见,解决的思路比较的巧妙,不容易想到,但是只要一想到,代码写起来就很简单了。主要的思路是这样的:定义一个指针 fast,从链表头开始,移动 k-1 个节点,再定义一个指针 slow,同时移动 fast 和 slow ,当 fast 到达链表尾节点的时候,slow 所指向的节点就是要删除的节点。

具体的代码实现如下:

public static Node deleteLastKth(Node head, int k) {
        Node fast = head;
        int i = 1;
        //先让前面的指针移动k - 1步
        while(fast != null && i < k) {
            fast = fast.next;
            ++ i;
        }
        Node slow = head;
        Node prev = null;
        //前后指针同时移动
        while(fast.next != null) {
            fast = fast.next;
            prev = slow;
            slow = slow.next;
        }
        if(prev == null) {//说明删除的是第一个节点
            head = head.next;
        }else {
            prev.next = prev.next.next;
        }
        return head;
    }


6. 找到链表的中间节点


寻找链表中间的那个节点,思路很简单,也是定义两个指针,一个指针每次移动两个节点,另一个指针移动一个节点,前面的指针到达链表尾部的时候,后面的指针指向的节点就是中间的那个节点:

public static Node findMiddleNode(Node head) {
        if(head == null) return null;
        Node fast = head;
        Node slow = head;
        while(fast.next != null && fast.next.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }
相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
相关文章
|
4月前
【数据结构】单链表(长期维护)(1)
【数据结构】单链表(长期维护)(1)
|
2月前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
43 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
|
2月前
|
存储
[数据结构] -- 单链表
[数据结构] -- 单链表
26 1
|
3月前
|
存储 Java
java数据结构,线性表链式存储(单链表)的实现
文章讲解了单链表的基本概念和Java实现,包括头指针、尾节点和节点结构。提供了实现代码,包括数据结构、接口定义和具体实现类。通过测试代码演示了单链表的基本操作,如添加、删除、更新和查找元素,并总结了操作的时间复杂度。
java数据结构,线性表链式存储(单链表)的实现
|
2月前
|
存储
【数据结构】——单链表实现
【数据结构】——单链表实现
|
2月前
|
存储
数据结构2——单链表
数据结构2——单链表
35 1
|
2月前
|
存储
【初阶数据结构】深入解析单链表:探索底层逻辑(无头单向非循环链表)(一)
【初阶数据结构】深入解析单链表:探索底层逻辑(无头单向非循环链表)
|
2月前
|
存储
数据结构(单链表)
数据结构(单链表)
20 0
|
2月前
|
存储
数据结构--单链表
数据结构--单链表
|
3月前
|
存储 算法 C语言
数据结构基础详解(C语言):单链表_定义_初始化_插入_删除_查找_建立操作_纯c语言代码注释讲解
本文详细介绍了单链表的理论知识,涵盖单链表的定义、优点与缺点,并通过示例代码讲解了单链表的初始化、插入、删除、查找等核心操作。文中还具体分析了按位序插入、指定节点前后插入、按位序删除及按值查找等算法实现,并提供了尾插法和头插法建立单链表的方法,帮助读者深入理解单链表的基本原理与应用技巧。
649 6