真正的动态数据结构(引用和指针)

优点:真正的动态,不需要处理固定容量的问题。

缺点:丧失随机访问的能力。

链表就像寻宝,我们拿到藏宝图开始出发寻宝,每找到一个地方后,里面藏着下一步应该去哪里寻找。一步一步往下找,就能找到宝藏。每个节点都存有数据和下个节点的位置。

将数据存储在节点中,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实现单链表的更多相关文章

  1. Java实现单链表的各种操作

    Java实现单链表的各种操作 主要内容:1.单链表的基本操作 2.删除重复数据 3.找到倒数第k个元素   4.实现链表的反转   5.从尾到头输出链表 6.找到中间节点 7.检测链表是否有环 8.在 ...

  2. java实现单链表的增删功能

    JAVA 实现单链表的增删功能 package linked; class LinkedTable{ } public class LinkedTableTest { public static vo ...

  3. JAVA数据结构——单链表

    链表:一. 顺序存储结构虽然是一种很有用的存储结构,但是他有如下几点局限性:1. 因为创造线性表的时候已经固定了空间,所以当需要扩充空间时,就需要重新创建一个地址连续的更大的存储空间.并把原有的数据元 ...

  4. 使用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 ...

  5. 用Java实现单链表的基本操作

    笔试题中经常遇到单链表的考题,下面用java总结一下单链表的基本操作,包括添加删除节点,以及链表转置. package mars; //单链表添加,删除节点 public class ListNode ...

  6. java实现单链表常见操作

    一.概述: 本文主要总结单链表常见操作的实现,包括链表结点添加.删除:链表正向遍历和反向遍历.链表排序.判断链表是否有环.是否相交.获取某一结点等. 二.概念: 链表: 一种重要的数据结构,HashM ...

  7. Java实现单链表的快速排序和归并排序

    本文描述了LeetCode 148题 sort-list 的解法. 题目描述如下: Sort a linked list in O(n log n) time using constant space ...

  8. 数据结构——Java实现单链表

    一.分析 单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素.链表中的数据是以结点来表示的,每个结点由元素和指针构成.在Java中,我们可以将单链表定义成一个类,单链表的基 ...

  9. Java实现单链表翻转

    单链表翻转比方有例如以下链表: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZmVuZ3NoaXp0eQ==/font/5a6L5L2T/fontsize ...

  10. 用java实现单链表

    对于一个单链表来说,要求有最基本的数据节点以及一些重要的方法. 方法应该有增删改查.定位.输出.获取链表长度.排序.链表读入.链表输出.下面是我用java写的单链表 public class List ...

随机推荐

  1. 五个最佳RSS新闻阅读器

    文章出自http://www.williamlong.info/archives/1591.html 在博客和在线新闻充斥的互联网上,大量信息已经使得用户阅读量过载,幸运的是,通过RSS Feed提供 ...

  2. SQL Server 日志和代理的错误日志

    本文介绍的日志不是事务日志,而是SQL Server 日志和代理的错误日志,按照主体把错误日志分为SQL Server.SQL Server Agent.Database Mail,以及 Window ...

  3. 根据高德API知道坐标获取详细地址信息

    /** * 根据坐标获取具体地址 * @param coor 坐标字符串 * @return */ public static String getAdd(String coor){ String u ...

  4. 好代码是管出来的——Git的分支工作流与Pull Request

    上一篇文章介绍了常用的版本控制工具以及git的基本用法,从基本用法来看git与其它的版本控制工具好像区别不大,都是对代码新增.提交进行管理,可以查看提交历史.代码差异等功能.但实际上git有一个重量级 ...

  5. 【最小生成树+贪心】BZOJ1821: [JSOI2010]Group 部落划分 Group

    Description 聪聪研究发现,荒岛野人总是过着群居的生活,但是,并不是整个荒岛上的所有野人都属于同一个部落,野人们总是拉帮结派形成属于自己的部落,不同的部落之间则经常发生争斗.只是,这一切都成 ...

  6. Vue-CLI和脚手架

    但我们学习Vue时,很多教程都会说到用Vue-CLI构建项目,那么什么是脚手架?什么是Vue-CLI?为什么要用脚手架,好处在哪?以及为何我们用Vue开发项目时要用到Vue-CLI? 首先,CLI为c ...

  7. OpenLayer实现路径运动

    近期由于业务的需求,让我这从未想过要碰Web Gis的业余前端开发者,走了Web Gis的开发道路.功能需求很简单,但却也是让自己难为了好几天.如,应该选择那个Gis框架,Gis框架的兼容性如何,直接 ...

  8. 微信小程序之表单验证

    表单验证 何为表单验证呢? 百度百科给出的回答是这样的: 表单验证是javascript中的高级选项之一.JavaScript 可用来在数据被送往服务器前对 HTML 表单中的这些输入数据进行验证 [ ...

  9. docker(5):数据的管理

    Docker的volume卷 为了能持久话保存和共享容器的数据. 使用docker volume卷的两种方式 1:数据卷 2:数据卷容器 1:数据卷 数据卷:数据卷会绕过docker 的ufs 直接写 ...

  10. PoolEntry 参数讲解

    public abstract class PoolEntry<T, C> { private final String id; private final T route; //路由 p ...