Node

java 中的 LIinkedList 的数据结构是链表,而链表中每一个元素是节点。

我们先定义一下节点:

package com.xzlf.collection;

public class Node {
Node previous; // 上一个节点
Node next; // 下一个节点
Object element; // 元素数据 public Node(Object element) {
super();
this.element = element;
} public Node(Node previous, Node next, Object element) {
super();
this.previous = previous;
this.next = next;
this.element = element;
} }

版本一:基础版本

先创建一个类,完成链表的创建、添加元素、然后重写toString() 方法:

package com.xzlf.collection;

/**
* 自定义一个链表
* @author xzlf
*
*/
public class MyLinkedList {
private Node first;
private Node last;
private int size; public void add(Object obj) {
Node node = new Node(obj); if(first == null) {
first = node;
last = node;
}else {
node.previous = last;
node.next = null; last.next = node;
last = node;
}
size++;
} @Override
public String toString() {
StringBuilder sb = new StringBuilder("[");
Node tmp = first;
while(tmp != null) {
sb.append(tmp.element + ",");
tmp = tmp.next;
}
sb.setCharAt(sb.length() - 1, ']');
return sb.toString();
} public static void main(String[] args) {
MyLinkedList list = new MyLinkedList();
list.add("a");
list.add("b");
list.add("c");
list.add("a");
list.add("b");
list.add("c");
list.add("a");
list.add("b");
list.add("c");
System.out.println(list);
}
}

测试:

版本二:增加get() 方法

package com.xzlf.collection;

/**
* 自定义一个链表
* 增加get方法
* @author xzlf
*
*/
public class MyLinkedList2 {
private Node first;
private Node last;
private int size; public void add(Object obj) {
Node node = new Node(obj); if(first == null) {
first = node;
last = node;
}else {
node.previous = last;
node.next = null; last.next = node;
last = node;
}
size++;
} public Object get(int index) {
Node tmp = null;
// 判断索引是否合法
if(index < 0 || index > size - 1) {
throw new RuntimeException("索引不合法:" + index);
} /*索引位置为前半部分,从头部开始找*/
if (index <= size >> 1) {
tmp = first;
for (int i = 0; i < index; i++) {
tmp = tmp.next;
}
}else {
/*索引位置为或半部分,从未部开始找*/
tmp = last;
for (int i = size -1; i > index; i--) {
tmp = tmp.previous;
}
}
return tmp.element;
} @Override
public String toString() {
StringBuilder sb = new StringBuilder("[");
Node tmp = first;
while(tmp != null) {
sb.append(tmp.element + ",");
tmp = tmp.next;
}
sb.setCharAt(sb.length() - 1, ']');
return sb.toString();
} public static void main(String[] args) {
MyLinkedList2 list = new MyLinkedList2();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
list.add("f"); System.out.println(list);
System.out.println(list.get(1));
System.out.println(list.get(4));
}
}

测试:

版本三:增加remove() 方法

package com.xzlf.collection;

/**
* 自定义一个链表
* 增加remove
* @author xzlf
*
*/
public class MyLinkedList3 {
private Node first;
private Node last;
private int size; public void add(Object obj) {
Node node = new Node(obj); if(first == null) {
first = node;
last = node;
}else {
node.previous = last;
node.next = null; last.next = node;
last = node;
}
size++;
} public Object get(int index) {
Node tmp = null;
// 判断索引是否合法
if(index < 0 || index > size - 1) {
throw new RuntimeException("索引不合法:" + index);
}
tmp = getNode(index);
return tmp == null ? null : tmp.element;
} public void remove(int index) {
Node tmp = getNode(index);
Node up = tmp.previous;
Node down = tmp.next;
if (tmp != null) {
if (up != null) {
up.next = down;
}
if (down != null) {
down.previous = up;
}
// 被删元素是第一个时
if(index == 0) {
first = down;
}
// 被删元素是最后一个时
if(index == size - 1) {
last = up;
} size--;
}
} public Node getNode(int index) {
Node tmp = null;
/*索引位置为前半部分,从头部开始找*/
if (index <= size >> 1) {
tmp = first;
for (int i = 0; i < index; i++) {
tmp = tmp.next;
}
}else {
/*索引位置为或半部分,从未部开始找*/
tmp = last;
for (int i = size -1; i > index; i--) {
tmp = tmp.previous;
}
} return tmp;
} @Override
public String toString() {
StringBuilder sb = new StringBuilder("[");
Node tmp = first;
while(tmp != null) {
sb.append(tmp.element + ",");
tmp = tmp.next;
}
sb.setCharAt(sb.length() - 1, ']');
return sb.toString();
} public static void main(String[] args) {
MyLinkedList3 list = new MyLinkedList3();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
list.add("f"); System.out.println(list);
list.remove(2);
System.out.println(list);
list.remove(0);// 删除第一个元素
System.out.println(list);
list.remove(3);// 删除最后一个元素
System.out.println(list);
}
}

测试:

版本四:插入节点

package com.xzlf.collection;

/**
* 自定义一个链表
* 插入节点
* @author xzlf
*
*/
public class MyLinkedList4 {
private Node first;
private Node last;
private int size; public void add(Object obj) {
Node node = new Node(obj); if(first == null) {
first = node;
last = node;
}else {
node.previous = last;
node.next = null; last.next = node;
last = node;
}
size++;
} public void add(int index, Object obj) {
Node tmp = getNode(index);
Node newNode = new Node(obj);
if(tmp != null) {
Node up = tmp.previous;
up.next = newNode;
newNode.previous = up; newNode.next = tmp;
tmp.previous = newNode; }
} public Object get(int index) {
Node tmp = null;
// 判断索引是否合法
if(index < 0 || index > size - 1) {
throw new RuntimeException("索引不合法:" + index);
}
tmp = getNode(index);
return tmp == null ? null : tmp.element;
} public void remove(int index) {
Node tmp = getNode(index);
Node up = tmp.previous;
Node down = tmp.next;
if (tmp != null) {
if (up != null) {
up.next = down;
}
if (down != null) {
down.previous = up;
}
// 被删元素是第一个时
if(index == 0) {
first = down;
}
// 被删元素是最后一个时
if(index == size - 1) {
last = up;
} size--;
}
} public Node getNode(int index) {
Node tmp = null;
/*索引位置为前半部分,从头部开始找*/
if (index <= size >> 1) {
tmp = first;
for (int i = 0; i < index; i++) {
tmp = tmp.next;
}
}else {
/*索引位置为或半部分,从未部开始找*/
tmp = last;
for (int i = size -1; i > index; i--) {
tmp = tmp.previous;
}
} return tmp;
} @Override
public String toString() {
StringBuilder sb = new StringBuilder("[");
Node tmp = first;
while(tmp != null) {
sb.append(tmp.element + ",");
tmp = tmp.next;
}
sb.setCharAt(sb.length() - 1, ']');
return sb.toString();
} public static void main(String[] args) {
MyLinkedList4 list = new MyLinkedList4();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
list.add("f"); System.out.println(list);
list.add(1, "hello");
System.out.println(list);
}
}

测试:

版本五:增加泛型,小的封装

package com.xzlf.collection;

/**
* 自定义一个链表
* 增加泛型,小的封装
* @author xzlf
*
*/
public class MyLinkedList5<E> {
private Node first;
private Node last;
private int size; public void add(E element) {
Node node = new Node(element); if(first == null) {
first = node;
last = node;
}else {
node.previous = last;
node.next = null; last.next = node;
last = node;
}
size++;
} public void add(int index, E element) {
checkRange(index);
Node tmp = getNode(index);
Node newNode = new Node(element);
if(tmp != null) {
Node up = tmp.previous;
up.next = newNode;
newNode.previous = up; newNode.next = tmp;
tmp.previous = newNode; size++;
}
} private void checkRange(int index) {
if(index < 0 || index > size - 1) {
throw new RuntimeException("索引不合法:" + index);
}
} public E get(int index) {
Node tmp = null;
// 判断索引是否合法
checkRange(index);
tmp = getNode(index);
return tmp == null ? null : (E) tmp.element;
} public void remove(int index) {
checkRange(index);
Node tmp = getNode(index);
Node up = tmp.previous;
Node down = tmp.next;
if (tmp != null) {
if (up != null) {
up.next = down;
}
if (down != null) {
down.previous = up;
}
// 被删元素是第一个时
if(index == 0) {
first = down;
}
// 被删元素是最后一个时
if(index == size - 1) {
last = up;
} size--;
}
} private Node getNode(int index) {
checkRange(index);
Node tmp = null;
/*索引位置为前半部分,从头部开始找*/
if (index <= size >> 1) {
tmp = first;
for (int i = 0; i < index; i++) {
tmp = tmp.next;
}
}else {
/*索引位置为或半部分,从未部开始找*/
tmp = last;
for (int i = size -1; i > index; i--) {
tmp = tmp.previous;
}
} return tmp;
} @Override
public String toString() {
StringBuilder sb = new StringBuilder("[");
Node tmp = first;
while(tmp != null) {
sb.append(tmp.element + ",");
tmp = tmp.next;
}
sb.setCharAt(sb.length() - 1, ']');
return sb.toString();
} public static void main(String[] args) {
MyLinkedList5<String> list = new MyLinkedList5<>();
list.add("a");
list.add("b");
list.add("c"); System.out.println(list);
list.add(1, "hello");
System.out.println(list); System.out.println(list.get(1));
}
}

测试:

现在我们在编辑上使用add() 方法后已经提示要插入String类型的数据了:



以上代码测试运行结果:

以上代码可能还有部分细节上的bug,不过作为理解LinkedList数据结构的练习应该够用了。

理解java容器底层原理--手动实现LinkedList的更多相关文章

  1. 理解java容器底层原理--手动实现HashMap

    HashMap结构 HashMap的底层是数组+链表,百度百科找了张图: 先写个链表节点的类 package com.xzlf.collection2; public class Node { int ...

  2. 理解java容器底层原理--手动实现HashSet

    HashSet的底层其实就是HashMap,换句话说HashSet就是简化版的HashMap. 直接上代码: package com.xzlf.collection2; import java.uti ...

  3. 理解java容器底层原理--手动实现ArrayList

    为了照顾初学者,我分几分版本发出来 版本一:基础版本 实现对象创建.元素添加.重新toString() 方法 package com.xzlf.collection; /** * 自定义一个Array ...

  4. (前篇:NIO系列 推荐阅读) Java NIO 底层原理

    出处: Java NIO 底层原理 目录 1.1. Java IO读写原理 1.1.1. 内核缓冲与进程缓冲区 1.1.2. java IO读写的底层流程 1.2. 四种主要的IO模型 1.3. 同步 ...

  5. Java面试底层原理

    面试发现经常有些重复的面试问题,自己也应该学会记录下来,最好自己能做成笔记,在下一次面的时候说得有条不紊,深入具体,面试官想必也很开心.以下是我个人总结,请参考: HashSet底层原理:(问了大几率 ...

  6. 10分钟看懂, Java NIO 底层原理

    目录 写在前面 1.1. Java IO读写原理 1.1.1. 内核缓冲与进程缓冲区 1.1.2. java IO读写的底层流程 1.2. 四种主要的IO模型 1.3. 同步阻塞IO(Blocking ...

  7. java容器HashMap原理

    1.为什么需要HashMap 前面我们说了ArrayList和LinkedList,它们对容器内的对象都能实现增.删.改.查.遍历等操作, 并且对应不同的情况,我们可以选择不同的List,用以提高效率 ...

  8. 魔鬼在细节,理解Java并发底层之AQS实现

    jdk的JUC包(java.util.concurrent)提供大量Java并发工具提供使用,基本由Doug Lea编写,很多地方值得学习和借鉴,是进阶升级必经之路 本文从JUC包中常用的对象锁.并发 ...

  9. Java 容器源码分析之 LinkedList

    概览 同 ArrayList 一样,LinkedList 也是对 List 接口的一种具体实现.不同的是,ArrayList 是基于数组来实现的,而 LinkedList 是基于双向链表实现的.Lin ...

随机推荐

  1. 命令行中运行Java字节码文件提示找不到或无法加载主类的问题

    测试类在命令行操作,编译通过,运行时,提示 错误: 找不到或无法加载主类 java类 package com.company.schoolExercise; public class test7_3_ ...

  2. Oracle 10g客户端的安装和配置

    1.双击Oracle11g_database安装目录下的Setup.exe. 2.选择“基本安装”,设置“安装位置”,填写“数据库名”和“口令”,点击“下一步”. 3.点击“下一步”. 4.一般会出现 ...

  3. MATLAB——时间,日期及显示格式

    一.日期和时间 1.生成指定格式日期和时间 标准日期格式 2.获取当前时间的数值 >> datestr(now,) ans = -- :: >> datestr(now,'yy ...

  4. Mysql 截取字符串总结

    MySQL 字符串截取函数:left(), right(), substring(), substring_index().还有 mid(), substr().其中,mid(), substr() ...

  5. CentOS7部署指南

    1.rpm包安装---下载安装文件 wget https://pkg.jenkins.io/redhat/jenkins-2.156-1.1.noarch.rpm rpm -ivh jenkins-2 ...

  6. 面试刷题32:你对tomcat做了哪些性能调优?

    背景 java程序员的开发的java应用程序,一般都会选择使用tomcat发布,但是: 如何充分的掌控tomcat,并让它发挥最优性能呢? 这也是面试的热点问题,结合多年的工作实践,我是李福春,今天总 ...

  7. RocketMQ 源码分析之路由中心(NameServer)

    你可能没有看过 RocketMQ 的架构图,没关系,一起来学习一下,RocketMQ 架构图如下: 在 RocketMQ 中,有四个角色: Producer:消息的生产者,每个 MQ 中间件都有. C ...

  8. 版本控制git的简单使用

    0.第一次使用时配置: git config --global user.name "your_name" git config --global user.email " ...

  9. 类实例调用静态方法(Java)

    前言 第一次看到在Java中是可以通过类实例调用静态方法,当然不推荐这么做,接下来会讲到,但是在C#中通过类实例调用静态方法在编译时就不会通过,这里做下记录. 类实例调用静态方法 首先我们来看一个简单 ...

  10. web安全学习神器——DVWA安装部署

    前言 DVWA是用PHP+Mysql编写的一套用于常规WEB漏洞教学和检测的WEB脆弱性测试程序.包含了SQL注入.XSS.文件包含等常见的一些安全漏洞.接下来我会用图文的形式讲解一下DVWA的下载与 ...