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

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

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

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

将数据存储在节点中,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. Python爬虫-pyspider框架的使用

      pyspider 是一个用python实现的功能强大的网络爬虫系统,能在浏览器界面上进行脚本的编写,功能的调度和爬取结果的实时查看,后端使用常用的数据库进行爬取结果的存储,还能定时设置任务与任务优 ...

  2. python 产生token及token验证

    1.前言 最近在做微信公众号开发在进行网页授权时,微信需要用户自己在授权url中带上一个类似token的state的参数,以防止跨站攻击.在经过再三思考之后,自己试着实现一个产生token和验证tok ...

  3. [SQL Server]用 C# 在 LinqPad 建立 Linked Server 跨服务器数据库操作

    在涉及老项目数据迁移的时候,数据库结构已经完全发生变化,而且需要对老数据进行特殊字段的处理,而且数据量较大,使用Navicat导出单表之后,一个表数据大概在100多万的样子,直接导出SQL执行根本行不 ...

  4. Prometheus监控⼊⻔简介

    文档目录: • prometheus是什么?• prometheus能为我们带来些什么• prometheus对于运维的要求• prometheus多图效果展示 1) Prometheus是什么pro ...

  5. Dubbo中订阅和通知解析

    Dubbo中关于服务的订阅和通知主要发生在服务提供方暴露服务的过程和服务消费方初始化时候引用服务的过程中. 2345678910111213141516171819 public <T> ...

  6. vector作为函数返回类型

    在实际的操作中,我们经常会碰到需要返回一序列字符串或者一列数字的时候,以前会用到数组来保存这列的字符串或者数字,现在我们可以用vector来保存这些数据.但是当数据量很大的时候使用vector效率就比 ...

  7. BZOJ_2134_单选错位——期望DP

    BZOJ_2134_单选错位——期望DP 题意: 分析:设A为Ai ∈ [1,ai+1] 的概率,B为Ai = A(imodn+1)的概率显然P(A|B) = 1,那么根据贝叶斯定理P(B) = P( ...

  8. i春秋——Misc之百度杯

    今天心里很是不开森,想想往日何必那么努力呢?不如你的比比皆是,可是人家就是因为有关系,你又能怎样呢? 你所有应该有的都被打翻了,别灰心,至少你曾经努力过! 愿我未来的学弟学妹们都能一直开开心心的过好每 ...

  9. TensorFlow TensorBoard使用

    摘要: 1.代码例子 2.主要功能内容: 1.代码例子 <TensorFlow实战>使用MLP处理Mnist数据集并TensorBoard上显示 2.主要功能 执行TensorBoard程 ...

  10. MIP技术交流分享(3月9日)

    3月9日上周四下午,MIP 团队工程师与去哪儿酒店云.众荟的 Web 前端工程师进行了一次面对面的技术交流. 在这次交流中,MIP 工程师主要分享了 MIP 技术原理,MIP 加速原理,以及 MIP ...