栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

图解java链表基本操作篇一(头插法和尾插法)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

图解java链表基本操作篇一(头插法和尾插法)

整体代码结构定义
public class linkedListTest {}
节点数据存储定义

这样子定义只是为了可以方便地创建双向链表,循环链表,不影响单链表的创建,在创建链表的过程中,可以修改前驱指针或者后驱指针的使用或否。

// 创建每个数据的节点
   private static class Node{
        // 节点元素值
        E item;
        // 前一个节点
        Node pre;
        // 下一个节点
        Node next;

        public Node(){

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

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

        public E getItem() {
            return item;
        }
        public void setItem(E item) {
            this.item = item;
        }
        public Node getNext() {
            return next;
        }
        public void setNext(Node next) {
            this.next = next;
        }
        public Node getPre() {
            return pre;
        }
        public void setPre(Node pre) {
            this.pre = pre;
        }
    }
头插法

实例代码(主讲第一种构造方法):

    // 头插法
    public void createNodeFirst(E e){
        final Node first = head;
        final Node newNode = new Node<>(e, null, first);
        head = newNode;
        if (first != null) {
            first.pre = newNode;
        }else {
            tail = newNode;
        }
        size ++;
    }

实例代码(第二种构造方法):

   // 头插法
    public void createNodeFirst(E e){
//        final Node first = head;
//        final Node newNode = new Node<>(e, null, first);
//        head = newNode;
//        if (first != null) {
//            first.pre = newNode;
//        }else {
//            tail = newNode;
//        }
//        size ++;

        final Node first = head;
        final Node newNode = new Node<>(e, null);
        if (first != null) {
            newNode.next = head;
        }
        head = newNode;
        size ++;
    }

程序调用:

public static void main(String[] args) {
        linkedListTest listTest = new linkedListTest<>();
        String test = "abcdefg";
        for (char str : test.toCharArray()) {
            listTest.createNodeFirst(str);
        }
        System.out.println(listTest.size);
        while (listTest.head != null){
            System.out.print(listTest.head.item + " ");
            listTest.head = listTest.head.next;
        }
    }

结果:

代码分析:
(第一次代码循环)第一步代码解读:首先定义一个前置节点 first 指向头结点head,此时的头结点 head 为null值。此时的head节点的构造可以如下所示:

使用IDEA自带的断点调试可以清楚看到每一个节点的数据变化,(不会打断点的恕我无能为力)如下图:

(第一次代码循环)第二步代码解读:调用节点的构造函数创建出一个有具体值的节点出来,命名为newNode,传入构造newNode节点的数据有具体的值 e变量,(使用泛型,支持定义为Integer,char等等基本的数据类型的传递)和前置节点 first 。此时的链表构造可以表示为:

注意: newNode节点中的next指针应当包含了head节点的全部数据,head节点为 null ,那么newNode 节点中的 next 指针也应当是 null, 示意图为了直观了当才这样子画的。

(第一次代码循环)第三步代码解读:主要的作用是将head节点往前移动,存放字符 a 的节点既是head 节点,同时也是 newNode 节点。这个时候的构造图可以这样子解读:

(第一次代码循环)第四步代码解读:首先存放的字符是 a , 这个时候链表只有一个字符,而且前置节点 first 在程序开头指向的是一个没有数据的那头结点 head ,那理所应当此时的 first 节点是一个 null 值的状态,也就是如上面第一步代码解读的结构一样。所以,这一步代码执行的是尾节点 tail 指向新的节点数据newNode。最后一步代码执行的是保存链表中有数据的长度,执行到这一步,链表中具有数据的长度为 1 ,此时的链表结构可以这样子表示:

第二次代码循环:当代码执行到第二次循环时,这个时候的前置节点 first 指向头结点 head,其链表结构与第一次代码循环中head的节点结构一样。

头结点在第一次循环中已经保存有数据了,这个时候创建一个新的节点数据 newNode ,其中保存的字符值为 b 。

head 节点往前移动,这个时候的整体链表结构可以这样子解读:

然后这个时候的 first 节点不为空,那么 first 节点的前节点保存新创建的节点newNode节点。

第三次以上的代码循环与第二次代码循环的分析一致,这里就不做多余的补充了。另外可以看出上面的构图,pre 节点均为空,也就是处于没有使用的状态,这个可以看作是单链表的头插法。

尾插法

实例代码(主讲第一种构造方法):

    // 尾插法
    public void createNodeLast(E e){
        final Node last = tail;
        final Node newNode = new Node<>(e, last, null);
        tail = newNode;
        if (last != null) {
           last.next = newNode;
        }else {
            head = newNode;
        }
        size ++;
    }

实例代码(第二种构造方法):

  // 尾插法
    public void createNodeLast(E e){
//        final Node last = tail;
//        final Node newNode = new Node<>(e, last, null);
//        tail = newNode;
//        if (last != null) {
//           last.next = newNode;
//        }else {
//            head = newNode;
//        }
//        size ++;

        final Node last = tail;
        final Node newNode = new Node<>(e, null);
        if(last != null){
            tail.next = newNode;
            tail = newNode;
        }else {
            head = newNode;
            tail = head;
        }
        size ++;
    }

程序调用:

public static void main(String[] args) {
        linkedListTest listTest = new linkedListTest<>();
        String test = "abcdefg";
        for (char str : test.toCharArray()) {
            listTest.createNodeLast(str);
        }
        System.out.println(listTest.size);
        while (listTest.head != null){
            System.out.println(listTest.head.item);
            listTest.head = listTest.head.next;
        }
    }

结果:

代码分析:
(第一次代码循环)第一步代码解读:此时的链表尾节点 tail 指针为空,创建后置节点 last 指向 链表尾节点 tail 。此时的链表结构可以这样解读:

使用IDEA自带的断点调试可以清楚看到每一个节点的数据变化,(不会打断点的恕我无能为力)如下图:

(第一次代码循环)第二步代码解读:调用节点的构造函数创建出一个有具体值的节点出来,命名为newNode,传入构造newNode节点的数据有具体的值 e 变量和 后置节点 last 。此时的链表构造可以表示为:

由于指向新创建节点 newNode 节点的 last 节点或者是 tail 节点的值均为 null 所以 newNode 节点的前一个节点 pre 的值为 null 。

(第一次代码循环)第三步代码解读: 此时的 链表的尾节点 tail 指向新创建的节点 newNode ,具体的作用是 tail 节点往后移动,这个时候的链表结构可以这样表示:

(第一次代码循环)第四,五步代码解读: 这个时候已经进入到了 if else 语句了,很明显在上图展示的链表结构中last节点的值均为 null 值,这个时候头结点指向新创建的节点 newNode中,同时后面的存放链表有效长度加一(size ++),链表的结构可以这样子解读:

(第二次代码循环)当代码执行到第二次循环时,这个时候的后置节点 last 指向链表尾结点 tail。

尾结点在第一次循环中已经保存有数据了,这个时候创建一个新的节点数据 newNode ,其中保存的字符值为 b ,同时将后置节点 last 存放在新创建节点的前置指针区域,这个时候的链表结构可以这样子解读:

程序运行,这个时候来到 if else 语句中,这个时候可以从上图中看出 last 节点很明显不为空,将后置节点 last 的 下一个节点指向新创建的 newNode 节点,这个时候的链表结构可以这样子解读:

区别不大,也就是 next 节点不为空了,可以这样子理解 newNode 节点的 pre 指针存放了 tail 节点 ,last 节点和 head 节点,差不多就是你中有我,我中有你的样子,在下面的计算节点中展示数据会显示出死循环。

举一个简单的例子你就懂了:春娇与志明各有两颗糖,分别写着春娇吃和志明吃,现在春娇给一颗写着春娇吃的字样的糖给志明,然后志明再给一颗写着志明吃的字样的糖给春娇,问什么时候他们俩才能获得一模一样的糖?显然不可能的是吧?

代码奉上
public class linkedListTest {
    // 创建每个数据的节点
    private static class Node{
        // 节点元素值
        E item;
        // 前一个节点
        Node pre;
        // 下一个节点
        Node next;

        public Node(){

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

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

        public E getItem() {
            return item;
        }
        public void setItem(E item) {
            this.item = item;
        }
        public Node getNext() {
            return next;
        }
        public void setNext(Node next) {
            this.next = next;
        }
        public Node getPre() {
            return pre;
        }
        public void setPre(Node pre) {
            this.pre = pre;
        }
    }

    private int size;
    private Node head;
    private Node tail;
    
    
    public linkedListTest() {
    }
    
    // 头插法
    public void createNodeFirst(E e){
        final Node first = head;
        final Node newNode = new Node<>(e, null, first);
        head = newNode;
        if (first != null) {
            first.pre = newNode;
        }else {
            tail = newNode;
        }
        size ++;
    }

    // 尾插法
    public void createNodeLast(E e){
        final Node last = tail;
        final Node newNode = new Node<>(e, last, null);
        tail = newNode;
        if (last != null) {
           last.next = newNode;
        }else {
            head = newNode;
        }
        size ++;
    }

    public static void main(String[] args) {
//        linkedListTest listTest = new linkedListTest<>();
//        String test = "abcdefg";
//        for (char str : test.toCharArray()) {
//            listTest.createNodeFirst(str);
//        }
//        System.out.println(listTest.size);
//        while (listTest.head != null){
//            System.out.print(listTest.head.item + " ");
//            listTest.head = listTest.head.next;
//        }

        linkedListTest listTest = new linkedListTest<>();
        for (int i = 0; i < 10; i++) {
            listTest.createNodeLast(i);
        }
        System.out.println(listTest.size);
        while (listTest.head != null){
            System.out.print(listTest.head.item + " ");
            listTest.head = listTest.head.next;
        }
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/785248.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号