理解java容器底层原理--手动实现LinkedList
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的更多相关文章
- 理解java容器底层原理--手动实现HashMap
		
HashMap结构 HashMap的底层是数组+链表,百度百科找了张图: 先写个链表节点的类 package com.xzlf.collection2; public class Node { int ...
 - 理解java容器底层原理--手动实现HashSet
		
HashSet的底层其实就是HashMap,换句话说HashSet就是简化版的HashMap. 直接上代码: package com.xzlf.collection2; import java.uti ...
 - 理解java容器底层原理--手动实现ArrayList
		
为了照顾初学者,我分几分版本发出来 版本一:基础版本 实现对象创建.元素添加.重新toString() 方法 package com.xzlf.collection; /** * 自定义一个Array ...
 - (前篇:NIO系列 推荐阅读) Java NIO 底层原理
		
出处: Java NIO 底层原理 目录 1.1. Java IO读写原理 1.1.1. 内核缓冲与进程缓冲区 1.1.2. java IO读写的底层流程 1.2. 四种主要的IO模型 1.3. 同步 ...
 - Java面试底层原理
		
面试发现经常有些重复的面试问题,自己也应该学会记录下来,最好自己能做成笔记,在下一次面的时候说得有条不紊,深入具体,面试官想必也很开心.以下是我个人总结,请参考: HashSet底层原理:(问了大几率 ...
 - 10分钟看懂, Java  NIO   底层原理
		
目录 写在前面 1.1. Java IO读写原理 1.1.1. 内核缓冲与进程缓冲区 1.1.2. java IO读写的底层流程 1.2. 四种主要的IO模型 1.3. 同步阻塞IO(Blocking ...
 - java容器HashMap原理
		
1.为什么需要HashMap 前面我们说了ArrayList和LinkedList,它们对容器内的对象都能实现增.删.改.查.遍历等操作, 并且对应不同的情况,我们可以选择不同的List,用以提高效率 ...
 - 魔鬼在细节,理解Java并发底层之AQS实现
		
jdk的JUC包(java.util.concurrent)提供大量Java并发工具提供使用,基本由Doug Lea编写,很多地方值得学习和借鉴,是进阶升级必经之路 本文从JUC包中常用的对象锁.并发 ...
 - Java 容器源码分析之 LinkedList
		
概览 同 ArrayList 一样,LinkedList 也是对 List 接口的一种具体实现.不同的是,ArrayList 是基于数组来实现的,而 LinkedList 是基于双向链表实现的.Lin ...
 
随机推荐
- Linux环境下部署项目时的步骤和一些要注意的点
			
SQL的导出和导入 sql的导出 首先选中要导出的数据库 然后点击左下角的administration选项,进入导出界面. 点击Data Export 然后勾选图中的几个选项即可导出一个sql,如果需 ...
 - ThreadPoolExcutor 原理探究
			
概论 线程池(英语:thread pool):一种线程使用模式.线程过多会带来调度开销,进而影响缓存局部性和整体性能.而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务.这避免了在处理短时间 ...
 - C 送外卖
			
时间限制 : - MS 空间限制 : 365536 KB 评测说明 : 时限1000ms 问题描述 暑期期间,何老板闲来无事,于是买了辆摩托车,签约某团外卖,跑起来送外卖的业务. 何老板负责的 ...
 - JDK12不包含JAXB-API
			
##用JDK12环境下 做EUREKA的的时候 报错如下 java.lang.TypeNotPresentException: Type javax.xml.bind.JAXBContext not ...
 - 国内 Java 开发者必备的两个装备,你配置上了么?
			
虽然目前越来越多的国产优秀技术产品走出了国门,但是对于众领域的开发者来说,依然对于国外的各种基础资源依赖还是非常的强.所以,一些网络基本技能一直都是我们需要掌握的,但是速度与稳定性问题一直也都有困扰着 ...
 - Vmware安装CentOs7.4
			
转载https://blog.csdn.net/qq_42545206/article/details/90301472
 - node.js模拟学校教务处登录
			
临近毕业,在做毕设,我的毕设中有一个功能是模拟我学校的教务处登录以获得cookie,本来以为是挺简单的一个功能,但却花了我两天的时间.(我学校教务处用的是湖南强智科技开发的) 在网上搜了大量的模拟登录 ...
 - PTA | 1019 数字黑洞 (20分)
			
给定任一个各位数字不完全相同的 4 位正整数,如果我们先把 4 个数字按非递增排序,再按非递减排序,然后用第 1 个数字减第 2 个数字,将得到一个新的数字.一直重复这样做,我们很快会停在有" ...
 - .NET Core项目部署到Linux(Centos7)(二)环境和软件的准备
			
目录 1.前言 2.环境和软件的准备 3.创建.NET Core API项目 4.VMware Workstation虚拟机及Centos 7安装 5.Centos 7安装.NET Core环境 6. ...
 - python 爬虫之 urllib 实践
			
文章更新于:2020-03-19 注:本文参考官方文档进行 urllib 的讲解. 文章目录 一.urllib 模块介绍 1.urllib.request.py模块 (1)`urlopen`函数 (2 ...