博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java数据结构和算法(四)--链表
阅读量:5134 次
发布时间:2019-06-13

本文共 15741 字,大约阅读时间需要 52 分钟。

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

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

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

了解。

ArrayList和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
{ private int size; //链表长度大小 private Node head; //头结点 public SingleLinkList() { size = 0; head = null; } //添加元素到head public 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 data; Node
next; Node(E data) { this.data = data; } }}
public static void main(String[] args) {
SingleLinkList
singleList = new SingleLinkList
(); 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
{ private int size; //链表长度大小 private Node head; //头结点 private Node tail; //尾结点 public DoubleLinkList() { size = 0; head = null; tail = null; } //添加元素到head public void addFirst(E data) { Node newNode = new Node(data); if (size == 0) { head = newNode; tail = newNode; } else { newNode.next = head; head = newNode; } size++; } //添加元素到tail public 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 data; Node
next; Node(E data) { this.data = data; } }}
public static void main(String[] args) {	DoubleLinkList
doubleLinkList = new DoubleLinkList
(); 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源码的时候,我们已经详细了解过双向链表了,

图例:

代码示例:

public class DoubleLinkedList
{ private int size; //链表长度大小 private Node head; //头结点 private Node tail; //尾结点 public DoubleLinkedList() { size = 0; head = null; tail = null; } //添加元素到head public void addFirst(E data) { Node newNode = new Node(data); if (size == 0) { tail = newNode; } else { head.previous = newNode; newNode.next = head; } head = newNode; size++; } //添加元素到tail public 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
x = head; x != null; x = x.next) { if (x.data == null) { return x.data; } } } else { for (Node
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
x = head; x != null; x = x.next) { if (x.data == null) { unlink(x); return true; } } } else { for (Node
x = head; x != null; x = x.next) { if (object.equals(x.data)) { unlink(x); return true; } } } return false; } E unlink(Node
x) { final E element = x.data; final Node
next = x.next; final Node
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
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 data; Node
previous; Node
next; Node(E data) { this.data = data; } }}
public static void main(String[] args) {	DoubleLinkedList
doubleLinkList = new DoubleLinkedList
(); 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
{ 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
{ 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

你可能感兴趣的文章
ACM-ICPC 2018 world final A题 Catch the Plane
查看>>
那些年,那些书
查看>>
面向对象六大基本原则的理解
查看>>
注解小结
查看>>
java代码编译与C/C++代码编译的区别
查看>>
Bitmap 算法
查看>>
转载 C#文件中GetCommandLineArgs()
查看>>
list control控件的一些操作
查看>>
精读《useEffect 完全指南》
查看>>
SNF快速开发平台MVC-EasyQuery-拖拽生成SQL脚本
查看>>
DrawerLayout实现双向侧滑
查看>>
MySQL入门很简单-触发器
查看>>
LVM快照(snapshot)备份
查看>>
绝望的第四周作业
查看>>
一月流水账
查看>>
数论四大定理
查看>>
npm 常用指令
查看>>
20几个正则常用正则表达式
查看>>
TextArea中定位光标位置
查看>>
非常棒的Visual Studo调试插件:OzCode 2.0 下载地址
查看>>