图解java链表基本操作篇一(头插法和尾插法)
整体代码结构定义
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链表基本操作篇一(头插法和尾插法)相关推荐
- c语言 链表建立头插法尾插法,单链表的创建(头插法和尾插法)
单链表的创建分为头插法和尾插法,头插法是不断地向头结点插入新的结点.这样会使你所插入的结点值呈现逆序,所以头插法也可以实现单链表的逆置.尾插法是不断地向插入的新元素之后再插入新的元素.需要注意的是头插 ...
- 数据结构学习(二)——单链表的操作之头插法和尾插法创建链表
http://blog.csdn.net/abclixu123/article/details/8210109 链表也是线性表的一种,与顺序表不同的是,它在内存中不是连续存放的.在C语言中,链表是通过 ...
- java实现单链表的建立(头插法和尾插法)
单链表 单链表(Single Linked List): 单链表是一种链式存取的数据结构,用一组地址任意(可能连续,也可能不连续)的存储单元存放线性表中的数据元素. 链表中的数据是以结点来表示的,每个 ...
- 不带头结点的单链表的创建(头插法和尾插法)
1.用头插法建立不带头结点的单链表 #include<iostream> using namespace std;//单链表的结构体 typedef struct Node {int da ...
- c语言单链表的创建(头插法和尾插法)
概念: 单链表的建立: 头插法:元素插入在链表的头部,也叫做前插法. 尾插法:元素插入在链表的尾部,也叫做后插法. 头插法: 方法1: 步骤: 1)创建一个空链表(含头结点) 2)再创建一个需要插入的 ...
- 头插法和尾插法创建链表(有无头结点)
头插法和尾插法创建链表(有无头结点) 文章目录 头插法和尾插法创建链表(有无头结点) 1 头插法 1.1头插法建表规则: 1.2 头插法建表代码实现 2 尾插法 2.1 尾插法建表规则: 2.2 尾插 ...
- 单链表的头插法和尾插法c语言实现
/*单链表的头插法和尾插法c语言实现*/ #include <stdio.h> #include <stdlib.h> #include <string.h> #d ...
- 采用头插法和尾插法建立单链表
面说一下如果用C语言建立单链表,分为头插法和尾插法两种. 采用头插法建立单链表 该方法从一个空表开始,生成新结点,并将读取到的数据存放到新结点的数据域中,然后将新结点插入到当前链表的表头,即头结点之后 ...
- 头插法和尾插法建立带头节点的单链表
有两种方法建立单链表,尾插法和头插法,他们的区别是:头插法是按照输入元素倒序建立,为尾插法为顺序插入,并且多一个尾节点,我们一般使用尾插法. 一.头插法 代码为: pCurr -> next = ...
- C语言的双向链表头插法和尾插法,指定节点删除
文章目录 前言 头插法 尾插法 删除节点 测试代码如下 前言 双向链表和单链表的唯一区别就是多个一个指针域而已,该指针域可以访问链表的上一个节点. 关于构造双向链表的过程我们常见的有两种方法,和单链表 ...
最新文章
- python代码基础题-python第一部分基础题1-80题
- 反反复复的磁盘丢失故障处理过程
- 开发中 常用 js 记录(一)
- JS实现上下左右对称的九九乘法表
- 青客宝团队redis内部分享ppt
- java6虚拟机_Java 虚拟机之六:javap工具
- 文字识别_文字识别的应用
- 宿主机进程挂载到容器内_微服务架构之 容器技术
- vivo和OPPO手机刷机
- 办公室服务器文件管理制度,机要文件管理制度
- HDU 5143 NPY and arithmetic progression(思维)
- python存储数据到mysql--针对dataframe格式下的
- POJ1417 True Liars —— 并查集 + DP
- CentOS7挂载NTFS分区步骤
- 股票MACD指标算法公式
- NOIP2017大总结
- 马斯克用数字孪生开启航天工业大时代,工互2.0来了吗?
- C++ 实现BMP位图读写
- STM32F103C8T6_UART1(RS485通讯)复用PB6+PB7
- 全球当下最厉害的 14 位程序员!最后一位好年轻啊
热门文章
- java实现时间轮定时器_c++ 时间轮定时器实现
- Protel的下载地址和学习资料
- Unity存储路径具体位置整理(Win+Android+ios)
- Redis持久化RDB/AOF详解与实践
- matlab 2016b vs2010,在Matlab2010b中调用 Microsoft Visual C++ 2010
- 使用pdfobject预览pdf
- 博客系统文章的数据库存储方式
- 教妹学Java(九):一文搞懂Java中的基本数据类型
- 好人不长命 祸害遗千年
- Bootstrap标签(label)的使用