美文网首页
01. 链表

01. 链表

作者: 一直流浪 | 来源:发表于2022-09-07 17:36 被阅读0次

01. 链表

1、链表的概述

1.1 链式存储:

用一组任意类型的存储单元存储线性表,在逻辑上面相邻的结点在物理位置上面不一定相邻。

1.2 链表:

采用链式存储方法的线性表叫做链表

1.3 链表的特点:

其结点的存储单元可以不连续,每个结点中除存储原表结点中的数据外,还须存储指示其直接后继或前趋结点的地址,以反映结点之间的逻辑关系。因此,链表中每个结点由两部分构成:数据域和链域

链表没有固定的长度,可以在后面一直加

1.4 链表的分类

从实现角度可分为:动态链表和静态链表

从链接方式可分为:单链表、双链表和循环链表

2、单链表

指的是单向链表,每个节点的结构如下:

image.png

把结点的实现,用面向对象的方法分析,把结点归为一个Structural类。

Structural类中把数据域和后继节点都转为类的属性。

image.png

通常,我们定义一个链表,在他的第一个元素都不存储东西,让他只作为一个head标记,具体原因为什么?

因为链表有删除操作,如果要删除的是第一个结点,我们没有最前面head结点的话,就没有办法进行。

比如,数据域我们就存储一个name。

那么Node类的结构如下:

public class Structural {
    public String name;
    public Structural next;
}

我们可以把创建节点,分配空间的过程,在构造方法中完成

// 创建节点,分配空间
    public Structural(String name, Structural next) {
        // TODO Auto-generated constructor stub
        this.name = name;
        this.next = next;
    }

这样我们利用类的构造方法就可以完成,结点的创建过程。

因为链表最小单元,就是一个结点,我们就把链表的操作归给,这个结点的方法,写出静态方法,调用的时候,只需要直接用类名调用就行。

一个结点就是一个链表,如需加入更多结点只需要在后面接着加就好了!!!

下来开始写链表的操作:

(1)插入操作

image.png image.png
// 插入操作(链表头节点,一个指定节点,要插入的节点) 插到指定节点之后
    public static void insert(Structural head, Structural index, Structural data) {
        boolean flag = false;
        // 如果头指针不存在,链表不存在
        if (head == null) {
            return;
        }
        // 如果插入到头节点之后,也就是要成为第一个元素
        if (head.next == index) {
            data.next = head.next;
            head.next = data;
            flag = true;
        }

        while (head.next != null) {
            head = head.next;
            if (head == index) {
                data.next = head.next;
                head.next = data;
                flag = true;

                break;
            }

        }
        if (flag == true) {
            System.out.println("插入成功");
        } else {
            System.out.println("插入失败");
        }

    }

(2)删除操作

image.png

代码实现:

    // 删除操作(头节点,要删除节点)
    public static void dir(Structural head, Structural data) {
        boolean flag = false;
        // 如果头指针不存在,链表不存在
        if (head == null) {
            System.out.println("删除失败");
            return;
        }
        // 如果删除头节点
        if (head == data) {
            head = head.next;
            flag = true;
        }
        while (head.next != null) {
            if (head.next == data) {
                head.next = head.next.next;
                flag = true;
                break;
            }
            head = head.next;
        }
        if (flag) {
            System.out.println("删除成功");
        } else {
            System.out.println("删除失败");
        }
    }

(3) 修改操作

image.png

代码实现:

public static void revise(Structural head, Structural str1, Structural str2) {
        boolean flag = false;
        if (head == null) {
            System.out.println("修改失败");
        }

        while (head.next != null) {

            if (head.next == str1) {
                str2.next = head.next.next;
                head.next = str2;
                flag = true;
                break;
            }
            head = head.next;
        }
        if (flag) {
            System.out.println("修改成功");
        } else {
            System.out.println("修改失败");
        }

    }

测试:

public class LinkedList {
    public static void main(String[] args) {
        Structural head = new Structural(null, null);
        Structural structural1 = new Structural("a",null);
        Structural structural2 = new Structural("b",null);
        Structural structural3 = new Structural("c",null);
        Structural structural4 = new Structural("d",null);
        Structural structural5 = new Structural("e",null);
        
        //单向链表
        head.next = structural1;
        structural1.next = structural2;
        structural2.next = structural3;
        structural3.next = structural4;
        structural4.next = structural5;     
        
        
        for(Structural structural = head ; structural != null ;structural = structural.next) {
            System.out.println(structural);
        }
        
        
        
        System.out.println("---------------------");
        //插入(把f插到d后面)
        Structural structural6 = new Structural("f", null);
        Structural.insert(head, structural4, structural6);
        for(Structural structural = head ; structural != null ;structural = structural.next) {
            System.out.println(structural);
        }
        System.out.println("---------------------");
        //删除(把f删除)中间元素删除
        Structural.dir(head, structural6);
        for(Structural structural = head ; structural != null ;structural = structural.next) {
            System.out.println(structural);
        }
        System.out.println("---------------------");
        //删除(把a删除)头节点删除
        Structural.dir(head, structural1);
        for(Structural structural = head ; structural != null ;structural = structural.next) {
            System.out.println(structural);
        }
        System.out.println("---------------------");
        //删除(把e删除)末尾节点删除
        Structural.dir(head, structural5);
        for(Structural structural = head ; structural != null ;structural = structural.next) {
            System.out.println(structural);
        }
        System.out.println("---------------------");
        
        //修改(把c改为g)
        Structural structural7 = new Structural("g", null);
        Structural.revise(head,structural3, structural7);
        for(Structural structural = head ; structural != null ;structural = structural.next) {
            System.out.println(structural);
        }
        System.out.println("---------------------");
        
            
    }
    
}

结果:+

Structural [name=null]
Structural [name=a]
Structural [name=b]
Structural [name=c]
Structural [name=d]
Structural [name=e]
---------------------
插入成功
Structural [name=null]
Structural [name=a]
Structural [name=b]
Structural [name=c]
Structural [name=d]
Structural [name=f]
Structural [name=e]
---------------------
删除成功
Structural [name=null]
Structural [name=a]
Structural [name=b]
Structural [name=c]
Structural [name=d]
Structural [name=e]
---------------------
删除成功
Structural [name=null]
Structural [name=b]
Structural [name=c]
Structural [name=d]
Structural [name=e]
---------------------
删除成功
Structural [name=null]
Structural [name=b]
Structural [name=c]
Structural [name=d]
---------------------
修改成功
Structural [name=null]
Structural [name=b]
Structural [name=g]
Structural [name=d]
---------------------

终于无聊的把自己的思路说完了。

3、一道经典的算法题——判断单链表是否有环

先看看链表可能出现的情况,所有单链表无非三种情况

 * 第一种:从头节点指向下个,一直指下去,最后一个结点的next指向null

 * 第二种:从头节点指向下个,一直指下去,最后一个结点的next指向头节点,形成一个首尾相连的环链表

 * 第三种:从头节点指向下个,一直指下去,最后一个结点的next指向局部节点,形成一个局部尾部有环的链表。

关于如何判断单链表是否有环,有三种解法:

(1)先定义1个结点,先让他等于头节点,然后向后遍历,遍历一次,和头节点对比一次,如果出现相同,说明链表有环,如果没有出现相等情况,则说明没有环。

但是这种算法只能处理,前两种情况,因此缺乏普遍性,不适用。

(2)遍历链表,每遍历一个,把他们的hashcode值,先和数组里面的比较,如果没有再存储到一个数组里,如果找到有重复的,就说明有环。

(3)算法效率最高的,定义两个指针,一个跑得快,一个跑得慢,有一天他两相遇了,说明有环

例子:两个人都沿着跑步,都向前跑,一个跑的快,一个跑得慢,有一天他两相遇了,说明跑道中有环。

代码实现:

public static boolean hasLoop(Structural head) {
        
        if(head == null) {
            return false;
        }
        //定义一个跑的快的,每次遍历两个节点
        Structural stru1 = head;
        
        //定义一个跑的慢的,每次遍历一个节点
        Structural stru2 = head;
        while(true) {
            //避免一开始就相遇,让跑的快的,先跑两步。
            stru1 = stru1.next.next;
            stru2 =stru2.next;
            if(stru1 == null) {
                System.out.println("链表没有环");
                return false;
            }
            if(stru2 == stru1) {
                    System.out.println("链表有环");
                    return true;
                }       
            }
        }

相关文章

  • 01. 链表

    01. 链表 1、链表的概述 1.1 链式存储: 用一组任意类型的存储单元存储线性表,在逻辑上面相邻的结点在物理位...

  • 剑指OFFER总结

    我的头条号:http://suo.im/2qOG5t,欢迎关注哦!!!! 01.题目:链表中环的入口结点 答案:h...

  • 链表基础

    链表基础 链表长度 链表为空 链表结构 链表增加

  • 双向链表&双向循环链表

    链表分为:单链表、单向循环链表、双向链表、双向循环链表本节主要说明:双向链表、双向循环链表 定义结点 一、双向链表...

  • 算法与数据结构:链表

    链表 链表还分为单向链表和双向链表, 但是这篇文章只说单向链表 , 下次再讲双向链表 . 链表和数组的区别 ? 链...

  • 链表

    链表 单链表反转链表中环的检测两个有序链表合并删除链表倒数第n个节点求链表的元素总个数 一.单向链表 链表共有特征...

  • 五、双向链表

    双向链表 此前介绍的链表,也叫做单向链表使用双向链表可以提升链表的综合性能 修改之前的单链表的源码: 双向链表 –...

  • 链表

    内容 链表数据结构 向链表添加元素 从链表移除元素 使用 LinkedList 表 双向链表 循环链表 链表数据结...

  • 数据与算法结构

    线性表 顺序表 链表(物理上离散,逻辑上连续) 链表的类别 单链表 循环链表 双链表 链表的操作 顺序表与链表的比...

  • 数据结构——链表

    本文所讲的链表是单链表,链表采用无头链表 科普下:一般链表可以分为有头节点的链表与无头节点的链表 有头节点的链表:...

网友评论

      本文标题:01. 链表

      本文链接:https://www.haomeiwen.com/subject/bdbqwrtx.html