整体代码结构定义

public class LinkedListTest <E>{}

节点数据存储定义

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

// 创建每个数据的节点private static class Node<E>{// 节点元素值E item;// 前一个节点Node<E> pre;// 下一个节点Node<E> next;public Node(){}public Node(E item) {this.item = item;}public Node(E item, Node<E> next) {this.item = item;this.next = next;}public Node(E item, Node<E> pre, Node<E> 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<E> getNext() {return next;}public void setNext(Node<E> next) {this.next = next;}public Node<E> getPre() {return pre;}public void setPre(Node<E> pre) {this.pre = pre;}}

头插法

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

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

程序调用:

public static void main(String[] args) {LinkedListTest<Character> 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<E> last = tail;final Node<E> 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<E> last = tail;
//        final Node<E> newNode = new Node<>(e, last, null);
//        tail = newNode;
//        if (last != null) {//           last.next = newNode;
//        }else {//            head = newNode;
//        }
//        size ++;final Node<E> last = tail;final Node<E> 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<Character> 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 节点,差不多就是你中有我,我中有你的样子,在下面的计算节点中展示数据会显示出死循环。

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

代码奉上

/*** @author: 随风飘的云* @describe: 单链表、双链表、循环链表* @date 2022/03/21 22:13*/
public class LinkedListTest <E>{// 创建每个数据的节点private static class Node<E>{// 节点元素值E item;// 前一个节点Node<E> pre;// 下一个节点Node<E> next;public Node(){}public Node(E item) {this.item = item;}public Node(E item, Node<E> next) {this.item = item;this.next = next;}public Node(E item, Node<E> pre, Node<E> 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<E> getNext() {return next;}public void setNext(Node<E> next) {this.next = next;}public Node<E> getPre() {return pre;}public void setPre(Node<E> pre) {this.pre = pre;}}private int size;private Node<E> head;private Node<E> tail;/*** 无参构造函数*/public LinkedListTest() {}// 头插法public void createNodeFirst(E e){final Node<E> first = head;final Node<E> 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<E> last = tail;final Node<E> 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<Character> 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<Integer> 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;}}
}

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

  1. c语言 链表建立头插法尾插法,单链表的创建(头插法和尾插法)

    单链表的创建分为头插法和尾插法,头插法是不断地向头结点插入新的结点.这样会使你所插入的结点值呈现逆序,所以头插法也可以实现单链表的逆置.尾插法是不断地向插入的新元素之后再插入新的元素.需要注意的是头插 ...

  2. 数据结构学习(二)——单链表的操作之头插法和尾插法创建链表

    http://blog.csdn.net/abclixu123/article/details/8210109 链表也是线性表的一种,与顺序表不同的是,它在内存中不是连续存放的.在C语言中,链表是通过 ...

  3. java实现单链表的建立(头插法和尾插法)

    单链表 单链表(Single Linked List): 单链表是一种链式存取的数据结构,用一组地址任意(可能连续,也可能不连续)的存储单元存放线性表中的数据元素. 链表中的数据是以结点来表示的,每个 ...

  4. 不带头结点的单链表的创建(头插法和尾插法)

    1.用头插法建立不带头结点的单链表 #include<iostream> using namespace std;//单链表的结构体 typedef struct Node {int da ...

  5. c语言单链表的创建(头插法和尾插法)

    概念: 单链表的建立: 头插法:元素插入在链表的头部,也叫做前插法. 尾插法:元素插入在链表的尾部,也叫做后插法. 头插法: 方法1: 步骤: 1)创建一个空链表(含头结点) 2)再创建一个需要插入的 ...

  6. 头插法和尾插法创建链表(有无头结点)

    头插法和尾插法创建链表(有无头结点) 文章目录 头插法和尾插法创建链表(有无头结点) 1 头插法 1.1头插法建表规则: 1.2 头插法建表代码实现 2 尾插法 2.1 尾插法建表规则: 2.2 尾插 ...

  7. 单链表的头插法和尾插法c语言实现

    /*单链表的头插法和尾插法c语言实现*/ #include <stdio.h> #include <stdlib.h> #include <string.h> #d ...

  8. 采用头插法和尾插法建立单链表

    面说一下如果用C语言建立单链表,分为头插法和尾插法两种. 采用头插法建立单链表 该方法从一个空表开始,生成新结点,并将读取到的数据存放到新结点的数据域中,然后将新结点插入到当前链表的表头,即头结点之后 ...

  9. 头插法和尾插法建立带头节点的单链表

    有两种方法建立单链表,尾插法和头插法,他们的区别是:头插法是按照输入元素倒序建立,为尾插法为顺序插入,并且多一个尾节点,我们一般使用尾插法. 一.头插法 代码为: pCurr -> next = ...

  10. C语言的双向链表头插法和尾插法,指定节点删除

    文章目录 前言 头插法 尾插法 删除节点 测试代码如下 前言 双向链表和单链表的唯一区别就是多个一个指针域而已,该指针域可以访问链表的上一个节点. 关于构造双向链表的过程我们常见的有两种方法,和单链表 ...

最新文章

  1. python代码基础题-python第一部分基础题1-80题
  2. 反反复复的磁盘丢失故障处理过程
  3. 开发中 常用 js 记录(一)
  4. JS实现上下左右对称的九九乘法表
  5. 青客宝团队redis内部分享ppt
  6. java6虚拟机_Java 虚拟机之六:javap工具
  7. 文字识别_文字识别的应用
  8. 宿主机进程挂载到容器内_微服务架构之 容器技术
  9. vivo和OPPO手机刷机
  10. 办公室服务器文件管理制度,机要文件管理制度
  11. HDU 5143 NPY and arithmetic progression(思维)
  12. python存储数据到mysql--针对dataframe格式下的
  13. POJ1417 True Liars —— 并查集 + DP
  14. CentOS7挂载NTFS分区步骤
  15. 股票MACD指标算法公式
  16. NOIP2017大总结
  17. 马斯克用数字孪生开启航天工业大时代,工互2.0来了吗?
  18. C++ 实现BMP位图读写
  19. STM32F103C8T6_UART1(RS485通讯)复用PB6+PB7
  20. 全球当下最厉害的 14 位程序员!最后一位好年轻啊

热门文章

  1. java实现时间轮定时器_c++ 时间轮定时器实现
  2. Protel的下载地址和学习资料
  3. Unity存储路径具体位置整理(Win+Android+ios)
  4. Redis持久化RDB/AOF详解与实践
  5. matlab 2016b vs2010,在Matlab2010b中调用 Microsoft Visual C++ 2010
  6. 使用pdfobject预览pdf
  7. 博客系统文章的数据库存储方式
  8. 教妹学Java(九):一文搞懂Java中的基本数据类型
  9. 好人不长命 祸害遗千年
  10. Bootstrap标签(label)的使用