Java实现单链表
真正的动态数据结构(引用和指针)
优点:真正的动态,不需要处理固定容量的问题。
缺点:丧失随机访问的能力。
链表就像寻宝,我们拿到藏宝图开始出发寻宝,每找到一个地方后,里面藏着下一步应该去哪里寻找。一步一步往下找,就能找到宝藏。每个节点都存有数据和下个节点的位置。

将数据存储在节点中,next指向当前节点的下一个节点。
class Node
{
E e;
Node next;
}
要想访问这个链表的所有节点,我们必须知道链表的头节点,所以我们定义head,在定义个size记录链表中有几个元素

向链表的头添加元素很简单,我们添加一个node,在把这个nodet指针指下一个节点,这时的head节点就变成我们添加的节点,我们就变成头节点。

所以LinkList类
package com.dsideal.test; public class LinkList<E>
{
private class Node
{
public E e; public Node next; public Node(E e, Node next)
{
this.e = e;
this.next = next;
}
public Node(E e)
{
this(e,null);
}
public Node()
{
this(null,null);
}
@Override
public String toString()
{
return e.toString();
}
} private Node head; private int size; public LinkList()
{
head = null;
size = 0;
} public int getSize()
{
return size;
} public boolean isEmpty()
{
return size == 0;
} public void addFirst(E e)
{
// Node node = new Node(e);
// node.next = head;
// head = node; head = new Node(e,head);
size ++;
}
}
在链表中间添加元素,我们必须知道在插入节点之前的一个节点是什么。将前一个节点的指针指向我们插入的节点,把我们的插入节点的指针指向下一个节点。

package com.dsideal.test;
public class LinkList<E>
{
private class Node
{
public E e; public Node next; public Node(E e, Node next)
{
this.e = e;
this.next = next;
}
public Node(E e)
{
this(e,null);
}
public Node()
{
this(null,null);
}
@Override
public String toString()
{
return e.toString();
}
} private Node head; private int size; public LinkList()
{
head = null;
size = 0;
} public int getSize()
{
return size;
} public boolean isEmpty()
{
return size == 0;
} public void addFirst(E e)
{
// Node node = new Node(e);
// node.next = head;
// head = node; head = new Node(e,head);
size ++;
} public void add(int index,E e)
{
if (index < 0 || index > size)
{
throw new IllegalArgumentException("add is fail,index < 0 or index >= size");
}
if (index == 0)
{
addFirst(e);
}else {
Node prev = head;
for (int i = 0;i < index - 1;++i)
{
prev = prev.next;
}
// Node node = new Node(e);
// node.next = prev.next;
// prev.next = node; prev.next = new Node(e,prev.next);
size ++;
} } public void addLast(E e)
{
add(size,e);
} @Override
public String toString()
{
StringBuilder res = new StringBuilder();
res.append("Link head:");
Node cur = head;
while (cur != null)
{
res.append(cur + "->");
cur = cur.next;
}
res.append("NULL");
return res.toString();
}
}
这时我们发现,当add插入index等于零的时候,要做个判断。所以我们引入一个虚拟的头节点。Node dunmmy = new Node(null,null);删除节点,找到要删除节点的上一个节点,将
他的指针指向删除节点的下一个节点,将我们删除节点的next指向null。

所以LinkLIst类变为
public class LinkList<E>
{
private class Node
{
public E e; public Node next; public Node(E e, Node next)
{
this.e = e;
this.next = next;
} public Node(E e)
{
this(e, null);
} public Node()
{
this(null, null);
} @Override
public String toString()
{
return e.toString();
}
} private Node dummyHead; private int size; public LinkList()
{
dummyHead = new Node(null, null);
size = 0;
} //获取链表元素个数
public int getSize()
{
return size;
} //链表是否为空
public boolean isEmpty()
{
return size == 0;
} //增加链表头元素
public void addFirst(E e)
{
// Node node = new Node(e);
// node.next = head;
// head = node;
add(0, e);
} //增加链表元素个数
public void add(int index, E e)
{
if (index < 0 || index > size)
{
throw new IllegalArgumentException("index < 0 or index > size,add is fail.");
} Node prev = dummyHead;
for (int i = 0; i < index; i++)
{
prev = prev.next;
}
// Node node = new Node(e);
// node.next = prev.next;
// prev.next = node;
prev.next = new Node(e, prev.next);
size++;
} //添加链表末尾元素
public void addLast(E e)
{
add(size, e);
} //获取元素index
public E get(int index)
{
if (index < 0 || index >= size)
{
throw new IllegalArgumentException("get is fail,index < 0 or index > size");
}
Node cur = dummyHead.next;
for (int i = 0;i < index;++i)
{
cur = cur.next;
}
return cur.e;
} //获取第一个元素
public E getFirst()
{
return get(0);
} //获取最后一个元素
public E getLast()
{
return get(size - 1);
} //判读是否包含
public boolean contains(E e)
{
Node cur = dummyHead.next;
while (cur != null)
{
if (cur.e.equals(e))
{
return true;
}
cur = cur.next;
}
return false;
} //修改值
public void set(int index,E e)
{
if (index < 0 || index >= size)
{
throw new IllegalArgumentException("set is fail,index < 0 or index > size");
}
Node cur = dummyHead.next;
for (int i = 0;i < index;++i)
{
cur = cur.next;
}
cur.e = e;
} //删除元素
public E remove(int index)
{
if (index < 0 || index >= size)
{ }
Node prev = dummyHead;
for (int i = 0;i < index;++i)
{
prev = prev.next;
}
//删除的元素
Node retNode = prev.next;
prev.next = retNode.next;
retNode.next = null;//删除元素的指向下一个地址为空
size-- ;
return retNode.e;
}
//删除第一元素
public E removeFirst()
{
return remove(0);
}
//删除最后一个元素
public E removeLast()
{
return remove(size - 1);
}
@Override
public String toString()
{
StringBuilder res = new StringBuilder("");
for (Node cur = dummyHead.next; cur != null; cur = cur.next)
{
res.append(cur + "->");
}
res.append("NULL");
return res.toString();
}
}
用链表实现栈
public class LinkListStack<E> implements Stack<E>
{
private LinkList<E> linkList; public LinkListStack()
{
linkList = new LinkList<>();
} @Override
public int getSize()
{
return linkList.getSize();
} @Override
public boolean isEmpty()
{
return linkList.isEmpty();
} @Override
public void push(E e)
{
linkList.addFirst(e);
} @Override
public E pop()
{
return linkList.removeFirst();
} @Override
public E peek()
{
return linkList.getFirst();
} @Override
public String toString()
{
StringBuilder res = new StringBuilder();
res.append("Stack top[");
res.append(linkList);
res.append("] tail");
return res.toString();
}
}
链表实现队列,优化算法变为O(1)级别的
public class LinkListQueue<E> implements Queue<E>
{
//内置节点
private class Node
{
public E e; public Node next; public Node(E e,Node next)
{
this.e = e;
this.next = next;
} public Node(E e)
{
this(e,null);
} public Node()
{
this(null,null);
}
@Override
public String toString()
{
return e.toString();
}
} private Node head,tail; private int size; public LinkListQueue()
{
head = null;
tail = null;
size = 0;
} @Override
public int getSize() {
return size;
} @Override
public boolean isEmpty() {
return size == 0;
} @Override
public void enqueue(E e) {
if (tail == null)
{
tail = new Node(e);
head = tail;
}else {
tail.next = new Node(e);
tail = tail.next;
tail.next = null;
}
size ++;
} @Override
public E dequeue() {
if (isEmpty())
{
throw new IllegalArgumentException("dequeue is fail,queue is isEmpty");
}
Node retNode = head;
head = retNode.next;
retNode.next = null;
if (head == null)
{
tail = null;
}
size--;
return retNode.e;
} @Override
public E getFront() {
if (isEmpty())
{
throw new IllegalArgumentException("Queue is isEmpty,so getFront is fail.");
}
return head.e;
}
@Override
public String toString()
{
StringBuffer str = new StringBuffer("");
str.append("LinkListQueue: head:");
Node cur = head;
while (cur != null)
{
str.append(cur + "->");
cur = cur.next;
}
str.append("NULL");
return str.toString();
}
}
Java实现单链表的更多相关文章
- Java实现单链表的各种操作
Java实现单链表的各种操作 主要内容:1.单链表的基本操作 2.删除重复数据 3.找到倒数第k个元素 4.实现链表的反转 5.从尾到头输出链表 6.找到中间节点 7.检测链表是否有环 8.在 ...
- java实现单链表的增删功能
JAVA 实现单链表的增删功能 package linked; class LinkedTable{ } public class LinkedTableTest { public static vo ...
- JAVA数据结构——单链表
链表:一. 顺序存储结构虽然是一种很有用的存储结构,但是他有如下几点局限性:1. 因为创造线性表的时候已经固定了空间,所以当需要扩充空间时,就需要重新创建一个地址连续的更大的存储空间.并把原有的数据元 ...
- 使用java实现单链表(转载自:https://www.cnblogs.com/zhongyimeng/p/9945332.html)
使用java实现单链表----(java中的引用就是指针)转载自:https://www.cnblogs.com/zhongyimeng/p/9945332.html ? 1 2 3 4 5 6 7 ...
- 用Java实现单链表的基本操作
笔试题中经常遇到单链表的考题,下面用java总结一下单链表的基本操作,包括添加删除节点,以及链表转置. package mars; //单链表添加,删除节点 public class ListNode ...
- java实现单链表常见操作
一.概述: 本文主要总结单链表常见操作的实现,包括链表结点添加.删除:链表正向遍历和反向遍历.链表排序.判断链表是否有环.是否相交.获取某一结点等. 二.概念: 链表: 一种重要的数据结构,HashM ...
- Java实现单链表的快速排序和归并排序
本文描述了LeetCode 148题 sort-list 的解法. 题目描述如下: Sort a linked list in O(n log n) time using constant space ...
- 数据结构——Java实现单链表
一.分析 单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素.链表中的数据是以结点来表示的,每个结点由元素和指针构成.在Java中,我们可以将单链表定义成一个类,单链表的基 ...
- Java实现单链表翻转
单链表翻转比方有例如以下链表: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZmVuZ3NoaXp0eQ==/font/5a6L5L2T/fontsize ...
- 用java实现单链表
对于一个单链表来说,要求有最基本的数据节点以及一些重要的方法. 方法应该有增删改查.定位.输出.获取链表长度.排序.链表读入.链表输出.下面是我用java写的单链表 public class List ...
随机推荐
- 五个最佳RSS新闻阅读器
文章出自http://www.williamlong.info/archives/1591.html 在博客和在线新闻充斥的互联网上,大量信息已经使得用户阅读量过载,幸运的是,通过RSS Feed提供 ...
- SQL Server 日志和代理的错误日志
本文介绍的日志不是事务日志,而是SQL Server 日志和代理的错误日志,按照主体把错误日志分为SQL Server.SQL Server Agent.Database Mail,以及 Window ...
- 根据高德API知道坐标获取详细地址信息
/** * 根据坐标获取具体地址 * @param coor 坐标字符串 * @return */ public static String getAdd(String coor){ String u ...
- 好代码是管出来的——Git的分支工作流与Pull Request
上一篇文章介绍了常用的版本控制工具以及git的基本用法,从基本用法来看git与其它的版本控制工具好像区别不大,都是对代码新增.提交进行管理,可以查看提交历史.代码差异等功能.但实际上git有一个重量级 ...
- 【最小生成树+贪心】BZOJ1821: [JSOI2010]Group 部落划分 Group
Description 聪聪研究发现,荒岛野人总是过着群居的生活,但是,并不是整个荒岛上的所有野人都属于同一个部落,野人们总是拉帮结派形成属于自己的部落,不同的部落之间则经常发生争斗.只是,这一切都成 ...
- Vue-CLI和脚手架
但我们学习Vue时,很多教程都会说到用Vue-CLI构建项目,那么什么是脚手架?什么是Vue-CLI?为什么要用脚手架,好处在哪?以及为何我们用Vue开发项目时要用到Vue-CLI? 首先,CLI为c ...
- OpenLayer实现路径运动
近期由于业务的需求,让我这从未想过要碰Web Gis的业余前端开发者,走了Web Gis的开发道路.功能需求很简单,但却也是让自己难为了好几天.如,应该选择那个Gis框架,Gis框架的兼容性如何,直接 ...
- 微信小程序之表单验证
表单验证 何为表单验证呢? 百度百科给出的回答是这样的: 表单验证是javascript中的高级选项之一.JavaScript 可用来在数据被送往服务器前对 HTML 表单中的这些输入数据进行验证 [ ...
- docker(5):数据的管理
Docker的volume卷 为了能持久话保存和共享容器的数据. 使用docker volume卷的两种方式 1:数据卷 2:数据卷容器 1:数据卷 数据卷:数据卷会绕过docker 的ufs 直接写 ...
- PoolEntry 参数讲解
public abstract class PoolEntry<T, C> { private final String id; private final T route; //路由 p ...