日常开发中,数组和集合使用的很多,而数组的无序插入和删除效率都是偏低的,这点在学习ArrayList源码的时候就知道了,因为需要把要

插入索引后面的所以元素全部后移一位。

  而本文会详细讲解链表,可以解决数组的部分问题,相比数组的大小不可更改,链表更加灵活,在学习LinkedList源码对链表有了一个大致的

了解。

ArrayList和LinkedList源码请参考:

  Java集合(四)--基于JDK1.8的ArrayList源码解读

  Java集合(五)--LinkedList源码解读

  本文我们会学习:单链表、双端链表、有序链表、双向链表和有迭代器的链表,并且会讲解一下抽象数据类型(ADT)的思想,如何用 ADT 描述

栈和队列,如何用链表代替数组来实现栈和队列。

链节点:

  在链表中,每个元素都被包含在链节点Link中。一个链节点是某个类的对象,这个类可以叫做Link。每个Link对象都包含对下一个Link引用的

字段(通常叫next)。但是链表本身有个字段指向对第一个Link的引用。

代码示例:

public class Link {private Object data;private Link next;
}

单链表:

  单链表的机构比较简单,每个Node包含data和next(指向下个Node),最后一个Node的next指向null

图例:

代码实现:

public class SingleLinkList<E> {private int size;   //链表长度大小private Node head;  //头结点public SingleLinkList() {size = 0;head = null;}//添加元素到headpublic void addFirst(E data) {Node newNode = new Node(data);if (size == 0) {head = newNode;} else {newNode.next = head;head = newNode;}size++;}//删除头结点public E deleteFirst() {final E data = (E)head.data;head = head.next;size--;return data;}//查询某个元素是否存在public E find(E object) {Node current = head;int tempSize = size;while (tempSize > 0) {if (object == current.data) {return (E)current.data;} else {current = current.next;}tempSize--;}return null;}//删除链表中某个元素public boolean delete(E object) {if (null != object) {Node current = head;Node previous = head;while (!object.equals(current.data)) {if (current.next == null) {return false;} else {previous = current;current = current.next;}}if (current == head) {head = current.next;} else {previous.next = current.next;}size--;}return true;}//遍历打印链表public void displayList() {Node current = head;int tempSize = size;if (tempSize == 0) {System.out.print("[]");} else {System.out.print("[");while (current != null) {if (current.next == null) {System.out.print(current.data);;} else {System.out.print(current.data + "-->");;}current = current.next;}System.out.println("]");}}public boolean isEmpty() {return size == 0;}private static class Node<E>{E data;Node<E> next;Node(E data) {this.data = data;}}
}

public static void main(String[] args) {    SingleLinkList<Integer> singleList = new SingleLinkList<Integer>();    singleList.addFirst(22);   //添加节点    singleList.addFirst(44);    singleList.addFirst(66);    singleList.addFirst(88);    singleList.displayList();   //打印链表结构    singleList.delete(44);   //删除某个节点    singleList.displayList();    System.out.println(singleList.find(66));   //查询某个节点}

打印结果:
[88-->66-->44-->22]
[88-->66-->22]
66

双端链表:

双端链表和单向链表很相似,但是增加了一个新特性:就是对最后一个节点的引用,最后一个节点定义为tail

PS:双端链表不是双向链表,只能单向遍历,只是可以在双端添加/删除数据

图例:

代码实现:

public class DoubleLinkList<E> {private int size;   //链表长度大小private Node head;  //头结点private Node tail;  //尾结点public DoubleLinkList() {size = 0;head = null;tail = null;}//添加元素到headpublic void addFirst(E data) {Node newNode = new Node(data);if (size == 0) {head = newNode;tail = newNode;} else {newNode.next = head;head = newNode;}size++;}//添加元素到tailpublic void addLast(E data) {Node newNode = new Node(data);if (size == 0) {head = newNode;tail = newNode;} else {tail.next = newNode;tail = newNode;}size++;}//删除头结点public E deleteFirst() {if (isEmpty()) {return null;}final E data = (E)head.data;if (head.next == null) {tail = null;}head = head.next;size--;return data;}//删除尾结点public E deleteLast() {if (isEmpty()) {return null;}final E data = (E)tail.data;if (head.next == null) {head = null;}int tempSize = size;Node current = head;Node previous = head;while (tempSize > 0) {if (current.next == null) {previous.next = null;break;}previous = current;current = current.next;tempSize--;}tail = previous;size--;return data;}//查询某个元素是否存在public E find(E object) {Node current = head;int tempSize = size;while (tempSize > 0) {if (object == current.data) {return (E)current.data;} else {current = current.next;}tempSize--;}return null;}//删除链表中某个元素public boolean delete(E object) {if (null != object) {Node current = head;Node previous = head;while (!object.equals(current.data)) {if (current.next == null) {return false;} else {previous = current;current = current.next;}}if (current == head) {head = current.next;}else {previous.next = current.next;}size--;}return true;}//遍历打印链表public void displayList() {Node current = head;int tempSize = size;if (tempSize == 0) {System.out.print("[]");} else {System.out.print("[");while (current != null) {if (current == tail) {System.out.print(current.data);break;} else {System.out.print(current.data + "-->");}current = current.next;}System.out.println("]");}}public boolean isEmpty() {return size == 0;}private static class Node<E>{E data;Node<E> next;Node(E data) {this.data = data;}}
}

public static void main(String[] args) {DoubleLinkList<Integer> doubleLinkList = new DoubleLinkList<Integer>();doubleLinkList.addFirst(22);   //添加节点doubleLinkList.addFirst(44);doubleLinkList.addLast(66);doubleLinkList.addLast(88);doubleLinkList.addFirst(101);doubleLinkList.displayList();   //打印链表结构doubleLinkList.delete(44); //删除某个节点doubleLinkList.displayList();doubleLinkList.deleteLast();    //删除尾节点doubleLinkList.displayList();doubleLinkList.deleteFirst();   //删除头结点doubleLinkList.displayList();System.out.println(doubleLinkList.find(66));   //查询某个节点
}

输出结果:
[101-->44-->22-->66-->88]
[101-->22-->66-->88]
[101-->22-->66]
[22-->66]
66

链表的效率:

  表头插入和删除的速度很快,时间复杂度O(1)

  平均下来,定点插入、删除、查询都需要搜索链表中一半的节点,需要O(N)次比较,相比而言,数组执行这些操作也需要O(N)次比较,但是

链表不需要移动数据,只需要改变前后引用,而数组只能整体复制,效率会好很多

  链表的另一个优点体现在内存使用上,需要多少内存就使用多少内存,而数组一开始的内存空间都是确定的

有序链表:

  对于某些应用来说,在链表中保持数据的有序很很有用的。有序链表中,数据都是按照关键值有序排列的。

  在大多数使用有序数组的场景也可以使用有序链表,在插入速度方面有很大优势

  有序链表和一般单向链表只是添加方法有区别,其余方法都是相同的

代码示例:

public class SortedLinkList {private int size;   //链表长度大小private Node head;  //头结点public SortedLinkList() {size = 0;head = null;}//添加元素public void add(int data) {Node newNode = new Node(data);Node previoue = null;Node current = head;while (current != null && data > current.data) {previoue = current;current = current.next;}if (previoue == null) {head = newNode;head.next = current;} else {previoue.next = newNode;newNode.next = current;}size++;}//删除头结点public int deleteFirst() {final int data = head.data;head = head.next;size--;return data;}//查询某个元素是否存在public int find(int object) {Node current = head;int tempSize = size;while (tempSize > 0) {if (object == current.data) {return current.data;} else {current = current.next;}tempSize--;}return -1;}//删除链表中某个元素public boolean delete(int object) {Node current = head;Node previous = head;while (object != current.data) {if (current.next == null) {return false;} else {previous = current;current = current.next;}}if (current == head) {head = current.next;} else {previous.next = current.next;}size--;return true;}//遍历打印链表public void displayList() {Node current = head;int tempSize = size;if (tempSize == 0) {System.out.print("[]");} else {System.out.print("[");while (current != null) {if (current.next == null) {System.out.print(current.data);;} else {System.out.print(current.data + "-->");;}current = current.next;}System.out.println("]");}}public boolean isEmpty() {return size == 0;}private static class Node{int data;Node next;Node(int data) {this.data = data;}}
}

public static void main(String[] args) {SortedLinkList sortedLinkList = new SortedLinkList();sortedLinkList.add(5);   //添加节点sortedLinkList.add(1);sortedLinkList.add(8);sortedLinkList.add(2);sortedLinkList.add(101);sortedLinkList.displayList();   //打印链表结构sortedLinkList.delete(8); //删除某个节点sortedLinkList.displayList();sortedLinkList.deleteFirst();   //删除头结点sortedLinkList.displayList();System.out.println(sortedLinkList.find(101));   //查询某个节点
}

输出结果:
[1-->2-->5-->8-->101]
[1-->2-->5-->101]
[2-->5-->101]
101

双向链表:

  双向链表就是为了解决单向链表只能单向遍历而效率慢的问题,因为只能current=current.next进行遍历,只能获得下一个节点,而不能

获取上一个节点

在学习LinkedList源码的时候,我们已经详细了解过双向链表了,Java集合(五)--LinkedList源码解读

图例:

代码示例:

public class DoubleLinkedList<E> {private int size;   //链表长度大小private Node head;  //头结点private Node tail;  //尾结点public DoubleLinkedList() {size = 0;head = null;tail = null;}//添加元素到headpublic void addFirst(E data) {Node newNode = new Node(data);if (size == 0) {tail = newNode;} else {head.previous = newNode;newNode.next = head;}head = newNode;size++;}//添加元素到tailpublic void addLast(E data) {Node newNode = new Node(data);if (size == 0) {head = newNode;} else {tail.next = newNode;newNode.previous = tail;}tail = newNode;size++;}//删除头结点public E deleteFirst() {if (isEmpty()) {return null;}final E data = (E)head.data;if (head.next == null) {tail = null;}head = head.next;head.previous = null;size--;return data;}//删除尾结点public E deleteLast() {if (isEmpty()) {return null;}final E data = (E)tail.data;if (head.next == null) {head = null;}tail = tail.previous;tail.next = null;size--;return data;}//查询某个元素是否存在/*public E find(E object) {if (object == null) {for (Node<E> x = head; x != null; x = x.next) {if (x.data == null) {return x.data;}}} else {for (Node<E> x = head; x != null; x = x.next) {if (object.equals(x.data)) {return x.data;}}}return null;}*///查询某个索引下标的数据public E find(int index) {return (E)node(index).data;}//删除链表中某个元素public boolean delete(E object) {if (object == null) {for (Node<E> x = head; x != null; x = x.next) {if (x.data == null) {unlink(x);return true;}}} else {for (Node<E> x = head; x != null; x = x.next) {if (object.equals(x.data)) {unlink(x);return true;}}}return false;}E unlink(Node<E> x) {final E element = x.data;final Node<E> next = x.next;final Node<E> prev = x.previous;if (prev == null) {head = next;} else {prev.next = next;x.previous = null;}if (next == null) {tail = prev;} else {next.previous = prev;x.next = null;}x.data = null;size--;return element;}Node node(int index) {if (index < (size >> 1)) {Node x = head;for (int i = 0; i < index; i++)x = x.next;return x;} else {Node<E> x = tail;for (int i = size - 1; i > index; i--)x = x.previous;return x;}}//遍历打印链表public void displayList() {Node current = head;int tempSize = size;if (tempSize == 0) {System.out.print("[]");} else {System.out.print("[");while (current != null) {if (current == tail) {System.out.print(current.data);break;} else {System.out.print(current.data + "-->");}current = current.next;}System.out.println("]");}}public boolean isEmpty() {return size == 0;}private static class Node<E>{E data;Node<E> previous;Node<E> next;Node(E data) {this.data = data;}}
}

public static void main(String[] args) {DoubleLinkedList<Integer> doubleLinkList = new DoubleLinkedList<Integer>();doubleLinkList.addFirst(22);   //添加节点doubleLinkList.addFirst(44);doubleLinkList.addLast(66);doubleLinkList.addLast(88);doubleLinkList.addFirst(101);doubleLinkList.displayList();   //打印链表结构doubleLinkList.delete(44); //删除某个节点doubleLinkList.displayList();doubleLinkList.deleteLast();    //删除尾节点doubleLinkList.displayList();doubleLinkList.deleteFirst();   //删除头结点doubleLinkList.displayList();System.out.println(doubleLinkList.find(66));   //查询某个节点System.out.println(doubleLinkList.find(33));   //查询某个节点
}

输出结果:
[101-->44-->22-->66-->88]
[101-->22-->66-->88]
[101-->22-->66]
[22-->66]
66

拓展1、用链表实现:

public class MyStackByLinkedList<E> {private SingleLinkList linkList;public MyStackByLinkedList() {linkList = new SingleLinkList();}public void push(E e) {linkList.addFirst(e);}public E pop(){E e = (E)linkList.deleteFirst();return e;}}

拓展2:用双端链表实现队列

public class MyQueueByLinkedList<E> {private DoubleLinkedList linkedList;public MyQueueByLinkedList() {linkedList = new DoubleLinkedList();}public void add(E e) {linkedList.addFirst(e);}//移除数据public E remove(){return (E)linkedList.deleteFirst();}}

内容参考:<Java数据结构和算法>

转载于:https://www.cnblogs.com/huigelaile/p/11078109.html

Java数据结构和算法(四)--链表相关推荐

  1. Java数据结构与算法 day02 链表

    文章目录 第三章 链表 单链表介绍和内存布局 单链表创建和遍历的分析实现 添加(创建)过程 遍历过程 代码实现 单链表按顺序插入节点 单链表节点的修改 单链表节点的删除和小结 单链表面试题 新浪面试题 ...

  2. Java 数据结构与算法面试 链表

    手写链表的Java实现 package test;class Node{ // 数据域private Object ele; // 指针域private Node node; // 默认构造器,标准构 ...

  3. 尚硅谷图解Java数据结构和算法四

    下载地址:https://pan.baidu.com/s/1aiMur9dTCUvnDRD32LH3Tg    提取密码:vv3k

  4. 一文通数据结构与算法之——链表+常见题型与解题策略+Leetcode经典题

    文章目录 1 链表 1.1 常见题型及解题策略 1.1.1 LeetCode中关于链表的题目有以下五种类型题: 1.1.2 解题策略 1.2 链表的基本内容 1.2.1 链表的基本结构: 1.2.2 ...

  5. java环形链表_数据结构和算法(四)Java实现环形链表

    1. 数据结构和算法(四)Java实现环形链表 1.1 约瑟夫问题 约瑟夫问题:公元66年,约瑟夫不情愿地参与领导了犹太同胞反抗罗马统治的起义,后来起义失败,他和一些宁死不降的起义者被困于一个山洞之中 ...

  6. java数据结构与算法之顺序表与链表深入分析

    转载请注明出处(万分感谢!): http://blog.csdn.net/javazejian/article/details/52953190 出自[zejian的博客] 关联文章: java数据结 ...

  7. java数据结构与算法之双链表设计与实现

    转载请注明出处(万分感谢!): http://blog.csdn.net/javazejian/article/details/53047590 出自[zejian的博客] 关联文章: java数据结 ...

  8. 【Java数据结构及算法实战】系列002:算法的四种描述方式

    本节是<Java数据结构及算法实战>系列的第2节,主要介绍描述算法的常用的4种方式. 要定义一个算法,我们可以用自然语言.流程图.伪代码的方式描述解决某个问题的过程或是编写一段程序来实现这 ...

  9. Java数据结构和算法(一)——简介

    本系列博客我们将学习数据结构和算法,为什么要学习数据结构和算法,这里我举个简单的例子. 编程好比是一辆汽车,而数据结构和算法是汽车内部的变速箱.一个开车的人不懂变速箱的原理也是能开车的,同理一个不懂数 ...

最新文章

  1. “万人迷”小冰背后的AI故事
  2. 2016电大计算机网考,2016年电大-电大计算机网考题库[].doc
  3. 潮流设计师创作灵感|是时候设计一下蒸汽波海报了!
  4. java与android https,Java-Android SSL https发布
  5. add php support,WordPress add_theme_support() 函数详解
  6. 应用系统适配迁移方案
  7. android 图片可以滚动条,Android仿即刻首页垂直滚动图,炫酷到底!
  8. 网易云课堂 oracle,网易云课堂DBA学习笔记 (一) 数据库基础
  9. 面试官问“你还有什么需要了解的吗”——应该这样回答
  10. diskpart建立新卷
  11. DCO-OFDM可见光通信matlab
  12. C#,入门教程——列表(List)的基础知识
  13. Nginx反向代理实现负载均衡配置图解
  14. t430服务器安装系统,Dell PowerEdge T430
  15. 中国信通院:2017年Q3共享单车行业发展指数报告(附下载)
  16. CTA-敏感行为-AppOps方案
  17. 使用Dockerfile创建包含nginx-fair和nginx-check模块的nginx镜像
  18. [置顶]类的加载连接初始化
  19. National day present
  20. 计算机监控系统软件设计,计算机监控软件设计.doc

热门文章

  1. messagehub讲解,如何获取MessageHub的其余管理API的API密钥?
  2. TYVJ1467 通往聚会的道路
  3. PhoneGap在Microsoft Visual Studio Express For Wi...
  4. java导出excel 客户端_java如何将导出的excel下载到客户端
  5. 《假设的世界-一切不能想当然》笔记
  6. TCP/IP协议简介
  7. java中有效关键字_java中有效的关键字
  8. android shape 绘制气泡图,气泡图-自定义 shape
  9. 设置和使用地图的范围—ArcGIS API for JavaScript
  10. asp.net数据库连接web.config配置